单片机按键的定时器消抖处理

来源:互联网 发布:php抓取网页匹配url 编辑:程序博客网 时间:2024/04/29 13:40

使用定时器计时,给按键的按下、抬起的计时消抖,在大循环while里不堵塞,可以同时检测到每个按键各自的“按下”“长按”“抬起”的状态。在此基础上,按键的长按一秒、两秒三秒,按键的双击,组合键功能(例如Ctrl+C)等已经很容易实现了。
button.c和button.h直接添加到工程里,编译然后修改到对应的布尔变量。user.c是应用文件。

一、源文件button.c

按键操作。不同的编译器里布尔变量类型的几种写法:bit - bool - _Bool - unsigned char。
函数Btn_InitNull(BtnControl_pst pBtn)对按键参数初始化,设置按键初始状态为“无动作”。
函数Btn_InitPress(BtnControl_pst pBtn)对按键参数初始化,设置按键初始状态为“长按”。
函数Btn_Scan(BtnControl_pst pBtn, _Bool bPin)是在main()的大循环里检测按键状态。

#include "button.h"static _Bool Btn_Shake(BtnControl_pst pBtn, uint8_t site);/**************************************************************************Function:    Btn_InitNullDescription: 初始化按键参数,状态设为:S_NULL(无动作)Input:       - pBtn 按键操作结构体Return:      no**************************************************************************/void Btn_InitNull(BtnControl_pst pBtn){    pBtn->status  = S_NULL;    pBtn->bAction = 0;    pBtn->bDelay  = 0;}/**************************************************************************Function:    Btn_InitPressDescription: 初始化按键参数,状态设为:S_PRESS(长按)Input:       - pBtn 按键操作结构体Return:      no**************************************************************************/void Btn_InitPress(BtnControl_pst pBtn){    pBtn->status  = S_PRESS;    pBtn->bAction = 1;    pBtn->bDelay  = 0;}/**************************************************************************Function:    Btn_ScanDescription: 获取按键状态Input:       - pBtn 按键操作结构体             - bPin 按键引脚逻辑值Return:      no**************************************************************************/void Btn_Scan(BtnControl_pst pBtn, _Bool bPin){    if (!bPin)    {        if (pBtn->bAction)             // 上一状态是按下的        {            pBtn->status = S_PRESS;    // ===长按===        }        else if (Btn_Shake(pBtn, SITE_DOWN))  // 消抖延时(记忆“按下”位置)        {            pBtn->bAction = 1;            pBtn->status  = S_DOWN;    // ===按下===        }    }    else if (pBtn->bAction)    {        if (S_DOWN == pBtn->status)        {            pBtn->status = S_PRESS;    // ===长按===        }        if (Btn_Shake(pBtn, SITE_UP))  // 消抖延时(记忆“抬起”位置)        {            pBtn->bAction = 0;            pBtn->status  = S_UP;      // ===抬起===        }    }    else    {        pBtn->status = S_NULL;         // ===无动作===    }}/**************************************************************************Function:    Btn_ShakeDescription: 使用定时器中断,做按键消抖延时Input:       - pBtn 按键控制结构体             - site 按键位置Return:      执行标志**************************************************************************/static _Bool Btn_Shake(BtnControl_pst pBtn, uint8_t site){    // 开启中断延时消抖    if (!pBtn->bDelay)    {        pBtn->bExe   = 0;        pBtn->num    = 0;        pBtn->val    = 0;        pBtn->bDelay = 1;                // 置位延时标志        pBtn->site   = site;             // 保存按键电平    }    // 抖动处理    else if (pBtn->site != site)         // 检测是否抖动    {        pBtn->bDelay = 0;                // 清零延时标志    }    // 按键动作处理    else if (pBtn->bExe)    {        pBtn->bExe = 0;                  // 清零执行标志        if (++(pBtn->num) >= NUM_SHAKE)  // 消抖n次        {            pBtn->bDelay = 0;            // 清零计时标志            return 1;                    // ===执行===        }    }    return 0;                            // ===不执行===}

二、头文件button.h

定义了消抖时间,按键类型。

#ifndef _BUTTON_H_#define _BUTTON_H_#include "includes.h"// 时间常数(最大为255)#define TIMER_1MS_SHAKE_BTN      1     // 1 * 5    = 5ms     实际为4    ~5ms#define TIMER_10MS_SHAKE_BTN     1     // 10 * 5   = 50ms    实际为40   ~50ms#define TIMER_10MS_SHAKE_100MS   2     // 20 * 5   = 100ms   实际为90   ~100ms#define TIMER_10MS_SHAKE_300MS   6     // 60 * 5   = 300ms   实际为290  ~300ms#define TIMER_10MS_SHAKE_500MS   10    // 100 * 5  = 500ms   实际为490  ~500ms#define TIMER_10MS_SHAKE_700MS   14    // 140 * 5  = 700ms   实际为690  ~700ms#define TIMER_10MS_SHAKE_1200MS  24    // 240 * 5  = 1200ms  实际为1190 ~1200ms#define TIMER_10MS_SHAKE_3000MS  60    // 600 * 5  = 3000ms  实际为2990 ~3000ms#define TIMER_10MS_SHAKE_5000MS  100   // 1000 * 5 = 5000ms  实际为4990 ~5000ms#define TIMER_10MS_SHAKE_12S     240   // 2400 * 5 = 12000ms 实际为11990~12000ms// 消抖次数#define NUM_SHAKE                5// 单按键状态statustypedef enum BtnStaSingle{    S_NULL,               // 无动作    S_DOWN,               // 按下    S_PRESS,              // 长按    S_UP                  // 抬起} BtnStaSingle_st, *BtnStaSingle_pst;// 按键位置#define SITE_DOWN  0      // 按下#define SITE_UP    1      // 抬起// 按键控制typedef struct BtnControl{    uint8_t status:2;     // 按键状态(枚举BtnStaSingle)    uint8_t bAction:1;    // 动作标志    uint8_t bDelay:1;     // 消抖延时标志    uint8_t bExe:1;       // 消抖延时执行标志    uint8_t site:1;       // 按键位置    uint8_t num;          // 消抖次数[0,255]    uint8_t val;          // 消抖延时计算值[0,255]} BtnControl_st, *BtnControl_pst;void Btn_InitNull(BtnControl_pst pBtn);void Btn_InitPress(BtnControl_pst pBtn);void Btn_Scan(BtnControl_pst pBtn, _Bool bPin);/**************************************************************************Function:    Timer_BtnShakeDescription: 按键消抖计时宏函数Input:       - stBtn 按键变量             - tDown 按下消抖时间             - tUp   抬起消抖时间Return:      no**************************************************************************/#define Timer_BtnShake(stBtn, tDown, tUp)        \{                                                \    if ((stBtn).bDelay)                          \    {                                            \        ++(stBtn).val;                           \        switch ((stBtn).status)                  \        {                                        \        case S_NULL:                             \            if ((stBtn).val >= (tDown))          \            {                                    \                (stBtn).val  = 0;                \                (stBtn).bExe = 1;                \            }                                    \            break;                               \        case S_PRESS:                            \            if ((stBtn).val >= (tUp))            \            {                                    \                (stBtn).val  = 0;                \                (stBtn).bExe = 1;                \            }                                    \            break;                               \        default:                                 \            break;                               \        }                                        \    }                                            \}#endif  /* _BUTTON_H_ */

三、应用文件user.c

1、设置单片机定时器,写中断服务函数。
2、自定义按键变量,初始化按键变量参数。
3、在中断服务里调用按键消抖计时宏函数。
4、在while里扫描按键状态,根据得到的状态值做处理。
程序里做了2、3、4步骤,第1步根据不同的单片机去写。

// 端口设置#define PIN_BUTTON    RA0      // 按键volatile BtnControl_st  g_stBtn;/**************************************************************************Function:    mainDescription: 主函数Input:       noReturn:      no**************************************************************************/void main(void){    Btn_InitNull(&g_stBtn);    // 按键状态初始设为“无动作”    while (1)    {        OperateProc();         // 按键操作    }}/**************************************************************************Function:    IsrDescription: 定时器中断服务 1msInput:       noReturn:      no**************************************************************************/void interrupt Isr(){    // ==================按键消抖延时==================    Timer_BtnShake(g_stBtn, TIMER_1MS_SHAKE_BTN, TIMER_1MS_SHAKE_BTN);}/**************************************************************************Function:    OperateProcDescription: 操作处理Input:       noReturn:      no**************************************************************************/void OperateProc(void){    Btn_Scan(&g_stBtn, PIN_BUTTON);  // 按键扫描    switch (g_stBtn.status)    {    case S_DOWN:  // ===按下===        break;    case S_PRESS: // ===长按===        break;    case S_UP:    // ===抬起===        break;    default:        break;    }}