消抖

概述

在入门嵌入式的时候,对入门教材中的delay_ms,这种在轮询或者中断中死等的消抖行为其实大为诟病(好吧,就是正点原子)。轮询还好,但是在中断中消抖直接延时10ms,让追求效率的人是真的无法忍受。之前写了一个函数,通过轮询非阻塞读取IO状态,进行消抖。但是由于应用于某个场景,并没有模块化。因此并不能广泛适用。

其实本方式并不算复杂,只是个人觉得使用效果较好。

代码

#define MAX_BUTTON_NUM 10    //消抖的IO数目
#define BUTTON_PRESS_TIME 5  //按下消抖的基准次数
#define BUTTON_RELEASE_TIME 10 //离开消抖的基准次数
#define BUTTON_PRESS_VALUE 0  //当按下时,状态回调的值
#define BUTTON_RELEASE_VALUE 1 //当松开时,状态回调的值

typedef struct {
    uint8_t                 (*statu_cb)(void);                      /*引脚状态回调*/
    uint8_t                 new_state;                              /*当前IO状态*/
    uint8_t                 cnt;                                    /*消抖计数*/
    uint8_t                 real_state;                             /*消抖后的真实状态*/
    uint8_t                 ctrl_flag;                              /*是否控制 */
    void                    (*ctrl_cb)(uint8_t)						/*状态转换时调用的控制回调函数*/
}__attribute__ ((packed)) IO_INPUT_STATE_T;

static IO_INPUT_STATE_T ioStatus[MAX_BUTTON_NUM] = {0};
/*io输入消抖处理*/
static __attribute__((always_inline)) inline void io_input_process(void)
{
    for(int i=0;i<sysCfg->Infrared_Cfg.total_button;i++) {
        ioStatus[i].new_state = ioStatus[i].statu_cb;
        if(BUTTON_PRESS_VALUE == ioStatus[i].new_state) {
            if(ioStatus[i].cnt < BUTTON_PRESS_TIME) {
                ioStatus[i].cnt = BUTTON_PRESS_TIME;
            }
            if(ioStatus[i].cnt <= BUTTON_RELEASE_TIME) {
                ioStatus[i].cnt++;
            }else {
                ioStatus[i].real_state = BUTTON_PRESS_VALUE;
                if(ioStatus[i].ctrl_flag == 1){
                    ioStatus[i].ctrl_cb(ioStatus[i].real_state);
                    ioStatus[i].ctrl_flag = 0;
                }
            }
        }else {
            if(ioStatus[i].cnt > BUTTON_PRESS_TIME) {
                ioStatus[i].cnt = BUTTON_PRESS_TIME;
            }
            if(ioStatus[i].cnt > 0) {
                ioStatus[i].cnt--;
            }else {
                ioStatus[i].real_state = BUTTON_RELEASE_VALUE;
                if(ioStatus[i].ctrl_flag == 0)
                    ioStatus[i].ctrl_cb(ioStatus[i].real_state);
                    ioStatus[i].ctrl_flag = 1;
                }
            }
        }
    }
}

功能

NOTE:本模块需要在使用前对其状态回调函数和控制回调函数进行初始化。主函数在一定时间内进行调用。消抖时间=调用时间*基准次数

当有按键按下时,消抖时间内均在按下的状态,触发控制回调函数,传入值为BUTTON_PRESS_VALUE。

当有按键松开时,消抖时间内均在松开的状态,触发控制回调函数,传入值为BUTTON_RELEASE_VALUE。

分析

当有按键有状态时,cnt会立马变为BUTTON_PRESS_TIME的值,并在每次循环时,自行自加自减操作,当减少到0时,认为按键松开。当加到指定值时,认为按键按下,每次状态变化都会自行变为基准值。


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!