【RTT大赛作品连载】 按键滤波,按下,松手,长按,短按

描述

    本文主要以AB32VG1作为主控,结合板载按键实现按键的软件滤波,按下时间判断(长按,短按),按下判断,松手判断等,可以应对各种按键使用的场合,多种按键方式结合使用可以在只有一个按键的情况下实现多种按键操作逻辑。

一、创建工程

    创建工程比较简单,在这里不在赘述,可以参考官方的操作文档:https://file.elecfans.com/web2/M00/14/6F/pYYBAGE-y4WAGoojANBtfI0No2g719.pdf

 

二、按键逻辑初始化

    1. 创建按键线程

static void KEY_ThreadManage(void)
{
    rt_thread_t key_thread;

    key_thread = rt_thread_create("KEY Thread Manage",     /*线程名字*/
                                   KEY_ManageEntry,/*线程入口函数*/
                                   RT_NULL, /*线程入口函数参数*/
                                   2048,    /*线程栈大小*/
                                   5,       /*线程优先级*/
                                   10);     /*线程时间片*/
                                   
    rt_thread_startup (key_thread);
}

 

    2. 按钮初始化

    初始化函数需要在mian函数的while循环之前调用,也可以使用RT-Thread提供的硬件初始化宏来初始化。

本程序中设置了按键的状态有三种:

typedef enum
{
    KEY_PRESSED  = 0u,
    KEY_RELEASED = 1u,
    KEY_UNKNOW   = 2u
} E_KeySt;

主要作用:

    1)设置按键引脚;

    2)设置引脚状态为输入;

    3)设置按键滤波结构体,设置按键初始状态为UNKNOW

原理图如下:

S2 — PF1

S3 — PF0

S4 — PA2

滤波

 

void KEY_AppInit(void)
{
    uint8_t i = 0u;

    Key_pin.Key1 = rt_pin_get("PF.1");
    Key_pin.Key2 = rt_pin_get("PF.0");
    Key_pin.Key3 = rt_pin_get("PA.2");

    rt_pin_mode(Key_pin.Key1, PIN_MODE_INPUT);
    rt_pin_mode(Key_pin.Key2, PIN_MODE_INPUT);
    rt_pin_mode(Key_pin.Key3, PIN_MODE_INPUT);

    for(i=0; i

 

三、按键滤波

    按键滤波逻辑:检测按键引脚状态是否连续40ms都为低电平,如果都为低电平的话就认为是真的按下了,逻辑如下,修改KEY_SW_FILTER_THD可以修改按键的滤波时间,当前值为4,按键线程的运行周期为10ms,所以滤波时间为40ms:

static void KEY_KeySwFilterCounting(S_KeyStatusStr *paraKeySta)
{
    if(0u == paraKeySta->m_key_pin_st)
    {
        if(paraKeySta->m_filter_cnt >= KEY_SW_FILTER_THD)
        {
            paraKeySta->m_status = KEY_PRESSED;
        }
        else
        {
            paraKeySta->m_filter_cnt ++;
        }
    }
    else
    {
        paraKeySta->m_filter_cnt = 0u;
        paraKeySta->m_status = KEY_RELEASED;
    }
}

 

四、按键按下状态判断
    按键按下状态的判断逻辑:

    1)代码中有一个变量定义为用于记录上一个周期的按键按下的状态

static E_KeySt Last_KeyStatus[KEY_NUM] = {KEY_UNKNOW, KEY_UNKNOW, KEY_UNKNOW};

    2)读取滤波之后的按键状态变量

    3)如果上一次按键的状态为KEY_RELEASED,本次的按键状态为KEY_PRESSED,则认为按键按下了

        if((KEY_PRESSED == KEY_GetKeyStatus(i))
            && (KEY_RELEASED== Last_KeyStatus[i]))
        {
            key_Pressed[i] = KEY_PRESSED;
        }

 

五、按键松手状态判断

    与按键的按下逻辑相似,不同点在于上一次的按键按下状态为KEY_PRESSE,这一次为KEY_RELEASED就认为按键释放了。

        if((KEY_RELEASED == KEY_GetKeyStatus(i))
            && (KEY_PRESSED == Last_KeyStatus[i]))
        {
            key_Pressed[i] = KEY_RELEASED;
        }

 

六、按键按下时间判断

    按键按下时间可以用来区别按键是长安还是短按,可以用一个按键实现两种或多种功能。

具体实现方式需要结合按键松手判断一起时间,当按键按下的时候需要一个counter来记录按键按下的时间,然后按键松手的时候读取这个counter值的时间来判断是长按还是短按。

时间counter的累积逻辑为:

if((KEY_PRESSED == KEY_GetKeyStatus(i))
            && (KEY_PRESSED == Last_KeyStatus[i]))
        {
            key_pressed_counter[i] ++;
        }

 

七、实现效果

按钮按下会打印:Key [1,2,3] Pressed

按钮松开会打印:Key [1,2,3] Released, 同时会打印按下的时间:Hold Key [1,2,3] for xxx ms

滤波

 

八、代码实现

    贴上完整代码实现,有问题欢迎指正

 

代码直接粘贴可能存在遗漏,建议移步gitee:https://gitee.com/hehung/ab32-vg1_-rt-thread

 

.c文件

#include "app_key.h"
#include "board.h"

typedef struct
{
   uint8_t Key1;
   uint8_t Key2;
   uint8_t Key3;
} S_key_pin;

typedef struct
{
   uint8_t m_filter_cnt;
   E_KeySt m_status;
   uint8_t m_key_pin_st;
} S_KeyStatusStr;

S_key_pin Key_pin;
S_KeyStatusStr Key_Status[KEY_NUM];
E_KeySt key_Pressed[KEY_NUM] = {KEY_UNKNOW, KEY_UNKNOW, KEY_UNKNOW};
uint16_t key_pressed_counter[KEY_NUM] = {0, 0, 0};


static void KEY_ReadKeyLevel(void);
static void KEY_KeySwFilterCounting(S_KeyStatusStr *paraKeySta);
static void KEY_KeySwFilter(void);
static void KEY_ManageEntry(void *parameter);
static void KEY_ThreadManage(void);
static void KEY_JudgeKeyPressed(void);


void KEY_AppInit(void)
{
   uint8_t i = 0u;

   Key_pin.Key1 = rt_pin_get("PF.1");
   Key_pin.Key2 = rt_pin_get("PF.0");
   Key_pin.Key3 = rt_pin_get("PA.2");

   rt_pin_mode(Key_pin.Key1, PIN_MODE_INPUT);
   rt_pin_mode(Key_pin.Key2, PIN_MODE_INPUT);
   rt_pin_mode(Key_pin.Key3, PIN_MODE_INPUT);

   for(i=0; i   {
       Key_Status[i].m_filter_cnt = 0u;
       Key_Status[i].m_key_pin_st = 0u;
       Key_Status[i].m_status = KEY_UNKNOW;
   }

   KEY_ThreadManage();
}

E_KeySt KEY_GetKeyStatus(uint8_t paraKeyNum)
{
   return Key_Status[paraKeyNum].m_status;
}

E_KeySt KEY_GetKeyPressedStatus(uint8_t paraKeyNum)
{
   return key_Pressed[paraKeyNum];
}


static void KEY_ReadKeyLevel(void)
{
   Key_Status[KEY_NUM_1].m_key_pin_st = (uint8_t)rt_pin_read(Key_pin.Key1);
   Key_Status[KEY_NUM_2].m_key_pin_st = (uint8_t)rt_pin_read(Key_pin.Key2);
   Key_Status[KEY_NUM_3].m_key_pin_st = (uint8_t)rt_pin_read(Key_pin.Key3);
}

static void KEY_KeySwFilterCounting(S_KeyStatusStr *paraKeySta)
{
   if(0u == paraKeySta->m_key_pin_st)
   {
       if(paraKeySta->m_filter_cnt >= KEY_SW_FILTER_THD)
       {
           paraKeySta->m_status = KEY_PRESSED;
       }
       else
       {
           paraKeySta->m_filter_cnt ++;
       }
   }
   else
   {
       paraKeySta->m_filter_cnt = 0u;
       paraKeySta->m_status = KEY_RELEASED;
   }
}

static void KEY_KeySwFilter(void)
{
   KEY_KeySwFilterCounting(&Key_Status[KEY_NUM_1]);
   KEY_KeySwFilterCounting(&Key_Status[KEY_NUM_2]);
   KEY_KeySwFilterCounting(&Key_Status[KEY_NUM_3]);
}

static void KEY_JudgeKeyPressed(void)
{
   uint8_t i = 0u;
   static E_KeySt Last_KeyStatus[KEY_NUM] = {KEY_UNKNOW, KEY_UNKNOW, KEY_UNKNOW};

   for(i=0u; i   {
       /*Key pressed this cycle*/
       if((KEY_PRESSED == KEY_GetKeyStatus(i))
           && (KEY_RELEASED == Last_KeyStatus[i]))
       {
           key_Pressed[i] = KEY_PRESSED;
           key_pressed_counter[i] = 0u;
           rt_kprintf("KEY: Key %d Pressedn", i);

       }
       else if((KEY_RELEASED == KEY_GetKeyStatus(i))
           && (KEY_PRESSED == Last_KeyStatus[i]))
       {
           key_Pressed[i] = KEY_RELEASED;
           rt_kprintf("KEY: Key %d Releasedn", i);
           rt_kprintf("KEY: Hold Key for %d msn", key_pressed_counter[i]*10);
       }
       else if((KEY_PRESSED == KEY_GetKeyStatus(i))
           && (KEY_PRESSED == Last_KeyStatus[i]))
       {
           key_pressed_counter[i] ++;
       }

       Last_KeyStatus[i] = KEY_GetKeyStatus(i);
   }
}

static void KEY_ManageEntry(void *parameter)
{
   while(1)
   {
       KEY_ReadKeyLevel();
       KEY_KeySwFilter();
       KEY_JudgeKeyPressed();
       rt_thread_mdelay(10);
   }
}

static void KEY_ThreadManage(void)
{
   rt_thread_t key_thread;

   key_thread = rt_thread_create("KEY Thread Manage",     /*线程名字*/
                                  KEY_ManageEntry,/*线程入口函数*/
                                  RT_NULL, /*线程入口函数参数*/
                                  2048,    /*线程栈大小*/
                                  5,       /*线程优先级*/
                                  10);     /*线程时间片*/

   if(key_thread != RT_NULL)
   {
       rt_kprintf("KEY Thread Created Success!n");
       rt_thread_startup (key_thread);
   }
   else
   {
       rt_kprintf("KEY Thread Create Failed!n");
   }
}

 

.h文件

#ifndef APPLICATIONS_APP_KEY_H_
#define APPLICATIONS_APP_KEY_H_

#include "stdint.h"

typedef enum
{
    KEY_PRESSED  = 0u,
    KEY_RELEASED = 1u,
    KEY_UNKNOW   = 2u
} E_KeySt;

#define KEY_NUM                           (3u)
#define KEY_NUM_1                         (0u)
#define KEY_NUM_2                         (1u)
#define KEY_NUM_3                         (2u)

#define KEY_SW_FILTER_THD                 (4u)

#define KEY_SAMPLE_PERIOD                 (10u)
#define KEY_HOLD_SHORT_TIME               (500u) /*ms*/
#define KEY_HOLD_MIDDLE_TIME              (1500u) /*ms*/
#define KEY_HOLD_LONG_TIME                (1500u) /*ms*/

extern E_KeySt KEY_GetKeyStatus(uint8_t paraKeyNum);
extern E_KeySt KEY_GetKeyPressedStatus(uint8_t paraKeyNum);

void KEY_AppInit(void);

#endif
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分