状态机按键消抖

文章介绍了如何使用状态机实现嵌入式系统的按键消抖功能,避免由于机械抖动导致的误读。通过定义按键状态、结构体和状态检测函数,实现了非阻塞式的消抖方法,适用于STM32F407平台,且提供了相关代码示例。

嵌入式_状态机按键消抖

状态机,FSM(Finite State Machine),也称为同步有限状态机从。指的是在同步电路系统中使用的,跟随同步时钟变化的,状态数量有限的状态机,简称有限状态机。



前言

此代码是在STMF407平台使用标准库函数实现的,需要移植时请根据实际情况进行分析和修改。

按键抖动:按键抖动时间的长短由按键的机械特性决定,一般为5ms~10ms。这是一个很重要的时间参数,在很多场合都要用到。按键稳定闭合时间的长短则是由操作人员的按键动作决定的,一般为零点几秒至数秒。键抖动会引起一次按键被误读多次。为确保单片机对按键的一次闭合仅作一次处理,必须去除键抖动。在键闭合稳定时读取键的状态,并且必须判别到按键释放到稳定状态后再去作处理。
在这里插入图片描述

一般软件消抖一般又是直接一个简短延时Delay函数,数据阻塞式消抖效率低下,占用MCU资源,最近研究了一下状态机消抖,不占用MCU资源的非阻塞消抖。
传统硬件消抖:利用电容的充放电特性来对抖动过程中产生的电压毛刺进行平滑处理,从而实现消抖。在按键的两端并联一个0.1uf的电容
在这里插入图片描述


一、状态机消抖原理

如图:
初始状态:图以黑色方框表示,此时按键没有按下,MCU会检测到有一个初始电平(可以是高电平也可以是低电平),此时状态没有边沿信号触发,触次数为0,当有手按这个按键时候会产生毛刺,当检测到首次与初始电平不一样的电平信号时,就会变为初始抖动状态。

初始抖动状态:图以右上角灰色方框表示,接上文,按键状态变为初始抖动状态,会持续记录与初始电平不一样的电平信号触发次数,当持续N次时表示已经是持续的反转信号了说明按键确实按下了,此时就会直接跳转到反转状态,表示按键确实被按下。如果某一次检测到的信号还是和初始电平一样,那么就会重新置为初始状态,重新记录触发次数,直至持续N次的反转信号才会跳转到反转状态。

反转状态:图以白色方框表示,接上文,此时按键确实是按下状态,MCU会检测到一个反转电平(与初始状态电平相反),此状态没有边沿信号触发时触次数为0,当有手重新按这个按键或松开按键时候会产生毛刺,当检测到首次与反转电平不一样的电平信号时,就会变为反转抖动状态。

反转抖动状态:图以左下角灰色方框表示,接上文,按键状态变为反转抖动状态,会持续记录与反转电平不一样的电平信号触发次数,当持续N次时表示已经是持续的另一种信号了说明按键确实重新按下或松开,此时就会直接跳转到初始状态,表示按键确实被重新按下或松开。如果某一次检测到的信号还是和反转电平一样,那么就会重新置为反转状态,重新记录触发次数,直至持续N次的反转信号才会跳转到初始状态。

在这里插入图片描述

二、实现步骤

提示:本代码基于STM32F407标准库写的,主义修改及兼容性

1、一共有四个按键,定义一个按键表:

typedef enum 									// 按键表,
{
   
   
	KEY0 = 0,
	KEY1,
	KEY2,
	KEY3,
	KEY_NUM, 										// 必须要有的记录按钮数量,必须在最后
}KEY_LIST;

2、再定义一个按键属性结构体

代码如下(示例):

typedef struct
{
   
   
	uint8_t	KeysNum;						//序号
	GPIO_TypeDef*	GPIOX;					//端口
	uint16_t GPIO_PinsNum;					//引脚号
	uint16 KEY_TIMECOUNT;					//时间计数器
	GPIO_Pulltype GPIO_Pull;				//初始状态(未按下时候电平 0/1)
	KEY_STATUS key_NowStatus;				//按键当前状态
	uint8_t Key_Event;						//按键事件
}KEY_COMPONENTS;

3、再定义一个按键状态

代码如下(示例):

#define ENUM_ITEM(ITEM) ITEM,					//逗号不可省略
#define ENUM_STRING(ITEM) #ITEM,

#define KEY_STATUS_ENUM(STATUS) 	               \
		STATUS(KS_RELEASE)       		/*稳定松开状态*/       \
		STATUS(KS_PRESS_SHAKE)   		/*按下抖动状态*/       \
		STATUS(KS_PRESS)         		/*稳定按下状态*/       \
		STATUS(KS_RELEASE_SHAKE) 		/*松开抖动状态*/       \
		STATUS(KS_NUM)           		/*状态总数(无效状态)*/  \

4、接口函数

extern void ScanKey(void);								//持续扫描函数
extern KEY_STATUS key_status_check(uint Key_index);		//状态检测函数
extern uint8_t Key_GetPinsVolt(uint8_t Pin_index);		//获取GPIO电平函数

5、按键结构体数据定义以及状态检测切换函数实现

KEY_COMPONENTS Key_TestGrop[KEYSNUMBERS] =
{
   
   
	{
   
   0,GPIOE,GPIO_Pin_4,0,PuLL_UP,KS_RELEASE,0},			//key0
	{
   
   1,GPIOE,GPIO_Pin_3,0,PuLL_UP,KS_RELEASE,0},			//key1
	{
   
   2,GPIOE
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值