打印
[经验分享]

按键扫描函数,松手检测

[复制链接]
194|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
elsaflower|  楼主 | 2024-12-29 15:44 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
首先说明一下我这个按键扫描函数的作用,我要实现的是长按按键就关闭MCU所有外设,即进入睡眠模式,睡眠之后可以使用这个按键进行唤醒MCU,那么这里就要考虑一个误唤醒的问题,所以思路是长按之后进行一个假睡眠(我这里的表现就是关闭小灯),松手之后才会真正意义上的执行睡眠指令,开启中断,进入睡眠模式。

对于准确的应用按键,那么首先要了解按键的几种状态:

①刚开始都是松开的;

②使用时由松开到按下;

③一直按下不松开;这里还涉及到是否要连续有效还是单次有效;

④由按下到松开;

⑤一直松开;

首先说明几个变量的作用:

1、Release_cnt:松手之后或者没有按下按键进行累加,用以按下按键松手之后的消抖;

2、Presse_cnt:按键按下进行累加,消抖作用;

3、Key1_Flag:按键按下标志,设置按键状态,防止重复触发的作用;

4、Key1_Pressed:标志位,为1表示按键确认按下了;

5、Key1_Function:也是一个标志位,为1去执行相应的操作;

6、Key1_Released:标志位:为1表示按键按下有效并且确认松手了;

下面是一个大概的流程图;



下面是具体的按键扫描函数,长按关机,松手有效,单次触发;

void KeyScan(void)
{
    //单纯短按按键
    if(!KEY1)
    {
        Release_cnt = 0;
        if(!Key1_Flag)
        {
            Presse_cnt++;
            if(Presse_cnt >= 1000)                //1s长按防抖
            {
                Key1_Flag = 1;                        //设置按键状态,防止重复触发
                Key1_Pressed = 1;
                Key1_Function = 1;
            }
        }
    }
    else
    {
        if(Key1_Pressed)
        {
            Release_cnt++;
            if(Release_cnt >= 50)                //50ms释放防抖
            {
                Key1_Pressed = 0;
                Key1_Released = 1;
            }
        }
        Presse_cnt = 0;
        Key1_Flag = 0;
    }
}
下面是主函数里的while循环,Key1_Function这个标志长按不松手就置1,现象就是P20引脚电平拉高,熄灭小灯;松手之后Key1_Released置1,就开启中断进入睡眠;

while (1)
    {
        delay_ms(1);

        KeyScan();
        if(Key1_Function)
        {
            Key1_Function = 0;
            printf("Sleep Ready.\r\n");
            P20 = 1;    //LED OFF(关闭外设,准备进入休眠)
        }
        if(Key1_Released)
        {
            Key1_Released = 0;
            printf("MCU Sleep.\r\n");

            IE0  = 0;   //外中断0标志位
            EX0 = 1;    //INT0 Enable

            IT0 = 1;        //INT0 下降沿中断      
        //  IT0 = 0;        //INT0 上升,下降沿中断  

            _nop_();
            _nop_();
            PCON |= 0x02;   //Sleep
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            printf("MCU Wakeup.\r\n");
            P20 = 0;    //LED ON
        }
    }
最后注意嗷,相应的判断标志在进入之后一定要清0。

-----------------------------------------------------------分割线-------------------------------------------------------------

下面是一个新的按键扫描函数,实际主体和上面思路是一样的,只是多了一个两个按键同时按下的操作,这里所说的定时其实可以使用变量累加来替换;

我猜测这个应该会有一个问题,也就是假如你同时按下的操作很慢然后松手,会执行单个按键短按的操作;

#include <stdbool.h>

#include <stdint.h>

#define SHORT_PRESS_TIME 100 // 短按阈值(单位:毫秒)

#define LONG_PRESS_TIME 1000 // 长按阈值(单位:毫秒)

typedef enum {

    BUTTON_IDLE,

    BUTTON_PRESSED,

    BUTTON_SHORT_PRESS,

    BUTTON_LONG_PRESS

} ButtonState;

typedef struct {

    bool isPressed;         // 当前按键是否被按下

    uint32_t pressTime;     // 按键按下时的时间

    ButtonState state;      // 按键的状态

} Button;

Button button1 = {false, 0, BUTTON_IDLE};

Button button2 = {false, 0, BUTTON_IDLE};

uint32_t getCurrentTime(); // 获取当前时间的函数,单位:毫秒

bool isButton1Pressed();   // 检测BUTTON1是否被按下

bool isButton2Pressed();   // 检测BUTTON2是否被按下

void handleShortPress(Button* btn);

void handleLongPress(Button* btn);

void handleSimultaneousPress();

void scanButtons()

{

    uint32_t currentTime = getCurrentTime();

    // 更新BUTTON1状态

    if (isButton1Pressed())

    {

        if (!button1.isPressed)

        {

            button1.isPressed = true;

            button1.pressTime = currentTime;

            button1.state = BUTTON_PRESSED;

        }

        else if ((currentTime - button1.pressTime) >= LONG_PRESS_TIME)

        {

            button1.state = BUTTON_LONG_PRESS;

            handleLongPress(&button1);

        }

    }

    else

    {

        if (button1.isPressed)

        {

            if (button1.state == BUTTON_PRESSED && (currentTime - button1.pressTime) < LONG_PRESS_TIME)

            {

                button1.state = BUTTON_SHORT_PRESS;

                handleShortPress(&button1);

            }

            button1.isPressed = false;

            button1.state = BUTTON_IDLE;

        }

    }

    // 更新BUTTON2状态

    if (isButton2Pressed())

    {

        if (!button2.isPressed)

        {

            button2.isPressed = true;

            button2.pressTime = currentTime;

            button2.state = BUTTON_PRESSED;

        }

        else if ((currentTime - button2.pressTime) >= LONG_PRESS_TIME)

        {

            button2.state = BUTTON_LONG_PRESS;

            handleLongPress(&button2);

        }

    }

    else

    {

        if (button2.isPressed)

        {

            if (button2.state == BUTTON_PRESSED && (currentTime - button2.pressTime) < LONG_PRESS_TIME)

            {

                button2.state = BUTTON_SHORT_PRESS;

                handleShortPress(&button2);

            }

            button2.isPressed = false;

            button2.state = BUTTON_IDLE;

        }

    }

    // 检查两个按键同时按下

    if (button1.isPressed && button2.isPressed)

    {

        handleSimultaneousPress();

    }

}

void handleShortPress(Button* btn) {

    if (btn == &button1) {

        // 执行BUTTON1短按操作

    } else if (btn == &button2) {

        // 执行BUTTON2短按操作

    }

}

void handleLongPress(Button* btn) {

    if (btn == &button1) {

        // 执行BUTTON1长按操作

    } else if (btn == &button2) {

        // 执行BUTTON2长按操作

    }

}

void handleSimultaneousPress() {

    // 执行两个按键同时按下的操作

}


使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

31

主题

1301

帖子

0

粉丝