本帖最后由 dw772 于 2025-2-14 09:32 编辑
1:搞单片机程序有好几年了,回想出入门时写程序时,对按键处理一直理解不太透彻,每做一个项目就需要写一遍按键函数,虽然能解决问题,但是一直存在一个问题,按键识别跟功能一直纠缠在一起,无法将功能与按键的键值解耦。 2:随着项目的增加和经验的积累,逐渐理解了按键状态机和函数指针后,参考一些前辈的思路,总结了一个比较好用的按键思路。
3:在裸机系统中,我们一般采用while(1){}大循环,所有功能按顺序执行。在while循环内一般有个定时器标志位,比如10ms执行一次控制函数执行节奏,同时也可以做一下非精确的定时,比如按键长按时间,指示灯闪烁周期。
先定义一个按键状态的枚举类型结构体
- typedef enum
- {
- BT_EVENT_RELEASED = 0, /**< 按键已经释放 */
- BT_EVENT_PRESSED, /**< 按键按下边沿 */
- BT_EVENT_PRESSING, /**< 按键按住保持 */
- BT_EVENT_SHORT_CLICKED, /**< 按键短按释放边沿 */
- BT_EVENT_LONG_PRESSED, /**< 按键识别为长按边缘 press_cont ==最小长按时间 */
- BT_EVENT_LONG_PRESSED_REPEAT, /**< 按键长按重复 press_cont -上次计数 == 重复时间 */
- BT_EVENT_CLICKED, /**< 按键释放 长按/短按 */
- BT_EVENT_DOUBLE_CLICKED, /**< 按键双击 两次间隙<= 500MS */
-
- }bt_event_value_t;
再定义一个按键类型参数,用来存放按键的各个参数- typedef struct
- {
- flag_status (*read_gpio)(); //读取按键GPIO的函数指针 返回值为TRUE & FALSE
- bt_event_value_t btn_event; //枚举为 BT_EVENT_RELEASED ~ BT_EVENT_DOUBLE_CLICKED任意值
- uint8_t btn_stat; //按键有限状态机
- uint8_t btn_double_en; //双击是否使能
- uint8_t btn_act_sta; //有效状态
- uint32_t press_cont; //按下计数,判断长短按
- uint32_t idl_cont; //空闲计数,判断双击 组合按键需要另外处理
- }TypeButton;
根据需要几个按键定义几个按键变量,一个变量对应一个按键。该按键的所有数据都保存在这个变量内部。同时还需要定义一个数组存放这些变量的地址,方便扫描的时候顺序扫描按键。- TypeButton *bt[BUTTON_MAX] = { NULL}; //定义一个数组存放按键的地址,方便扫描按键的时候按顺序执行。
- TypeButton Power_key; //电源
- TypeButton Light_key; //灯
- TypeButton Funct_key; //功能
- TypeButton Incre_key; //增加
- TypeButton Decre_key; //减少
还需要一个注册按键的函数,注册按键并初始化按键对应的变量,并将读取按键IO的函数指针存放到按键结构体变量内,函数原型如下。
|