0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

闲来无事玩单片机呀 2021-12-06 09:23 次阅读

本文主要以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

poYBAGGqFY6Ae6-3AAAoQKbRhtg315.png

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

pYYBAGGqHRGANUz2AALpzzOwAxg160.png

八、代码实现

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

代码直接粘贴可能存在遗漏,建议移步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
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 滤波
    +关注

    关注

    10

    文章

    621

    浏览量

    56200
  • 按键
    +关注

    关注

    4

    文章

    220

    浏览量

    57321
  • RT-Thread
    +关注

    关注

    31

    文章

    1131

    浏览量

    38818
收藏 人收藏

    评论

    相关推荐

    RTT大赛作品连载】AB32VG1评估板到货控制彩灯测试

    RTT大赛作品连载】AB32VG1评估板到货控制彩灯测试篇;接下来看看在如何AB32VG1评估板控制彩灯! 在RT-ThreadStudio新建项目到对应开发配置及下载及验证测试!
    的头像 发表于 11-07 19:39 4807次阅读
    【<b class='flag-5'>RTT</b><b class='flag-5'>大赛</b><b class='flag-5'>作品</b><b class='flag-5'>连载</b>】AB32VG1评估板到货控制彩灯测试

    RTT大赛作品连载】AB32VG1评估板 音乐播放器

    RTT大赛作品连载】AB32VG1评估板 音乐播放器
    的头像 发表于 11-12 21:11 5842次阅读
    【<b class='flag-5'>RTT</b><b class='flag-5'>大赛</b><b class='flag-5'>作品</b><b class='flag-5'>连载</b>】AB32VG1评估板 音乐播放器

    RTT大赛作品连载】中科蓝讯AB32VG1开发板开箱篇

    介绍电路原理图分析接口说明,AB32VG1开发板是以中科蓝讯(Bluetrum)公司推出的基于RISC-V架构的高配置芯片AB5301A为核心所组成的。【RTT大赛作品连载】中科蓝讯A
    的头像 发表于 11-13 10:01 9586次阅读
    【<b class='flag-5'>RTT</b><b class='flag-5'>大赛</b><b class='flag-5'>作品</b><b class='flag-5'>连载</b>】中科蓝讯AB32VG1开发板开箱篇

    求助:单片机一键长按短按按键实现的c程序有问题

    单片机一键长按短按按键实现的c程序有问题,实在不知道是哪里有问题,请帮助修改一,谢谢!功能如下:长按2秒灯全亮(我用的开发板),
    发表于 06-03 16:55

    跪求基于verilog的短按键长按键的程序

    小弟新手,只会短按键的程序,跪求基于verilog的短按键长按键的程序,不胜感激
    发表于 03-18 14:47

    CY方案,想做一个按键短按长按功能

    请教各位大神,我在用CY方案时,需要做一个按键短按长按功能,一直没成功,代码如下:if (index == 0x00) // 按键
    发表于 05-26 17:01

    mico按键长按短按怎么实现

    mico按键长按短按怎么实现?
    发表于 07-31 17:02

    HI3861驱动【通用按键框架-单击,长按,连发(带加速);组合键;组合长按

    忘记了松手的抖动,这个松手抖动也是我工作中遇到的问题,特此分享一,处理按键滤波需要处理
    发表于 11-13 22:33

    【文章连载】RT-Thread创新应用大赛文章汇总

    连载】中科蓝讯AB32VG1开发板开箱篇专栏作者:煲仔卤煮的炼钢【RTT大赛作品连载】CH32V103开发板资料及上电首测专栏作者:AB32
    发表于 10-11 15:13

    stm32按键长按/短按怎么实现?

    stm32按键长按/短按怎么实现?
    发表于 12-02 07:41

    实现单片机按键长按短按功能的方法

    写在前面 一般我们在写单片机程序的时候都要用到按键,在按键较少的情况我们需要一个按键可以返回不同的
    发表于 12-06 07:40

    单片机状态机按键长按短按实现

    本文只介绍主要代码段,完整代码可参考我的“蓝桥杯单片机状态机按键和松开实现不同功能”蓝桥杯单片机状态机按键长按
    发表于 01-06 08:26

    按键长按短按效果

    按键长按短按效果 C51单片机源码,KEIL源文件,C语言编写
    发表于 06-20 16:15 54次下载

    基于状态机的单片机按键短按长按功能的实现

    本文主要介绍了基于状态机的单片机按键短按长按功能的实现,按键的击键过程也是一种状态的切换,也可以看着是一个状态机,一个按键的击键过程包括:按
    发表于 12-28 08:43 1.8w次阅读
    基于状态机的单片机<b class='flag-5'>按键</b><b class='flag-5'>短按</b><b class='flag-5'>长按</b>功能的实现

    瑞萨单片机之外部中断实现按键长按短按(二)

    瑞萨单片机通过外部中断实现按键长按短按
    发表于 11-22 14:21 18次下载
    瑞萨单片机之外部中断实现<b class='flag-5'>按键</b>的<b class='flag-5'>长按</b>与<b class='flag-5'>短按</b>(二)