当前位置:网站首页>STM32按键状态机2——状态简化与增加长按功能
STM32按键状态机2——状态简化与增加长按功能
2022-07-06 10:01:00 【码农爱学习】
上篇文章,以按键消抖功能,介绍了状态机的基本原理与使用方法。
上篇的状态图如下:
由于只检测按下与松开,并具备按键消抖功能,因此用到了如上的4个状态,按下抖动和松开抖动是两个独立的状态,并且这两个抖动的状态,也是可以在多次循环中连续运行的,这个状态机的循环周期设置的为10ms,当在抖动状态连续检测到某一电平5次后,即认为消抖完成,进入下一个稳定状态。
对于同一个功能,状态图不是一成不变的,对于按键消抖,还可以将两个抖动状态共用一个抖动状态来表示。
1 消抖状态简化
1.1 状态图
将按下抖动与松开抖动共用一个抖动状态来表示,同时需要将状态机的循环周期设置为50ms,这样,抖动状态只需经过一次,通过电平高低即可判定是否真的为按键抖动。简化后的状态图如下:
为了能在抖动状态时,区分前一状态是松开还是按下,进而判断此次是抖动还是按键真的动作,需要增加一个状态来记录前一状态
KEY_STATUS g_keyStatus = KS_RELEASE; //当前循环结束的(状态机的)状态
KEY_STATUS g_nowKeyStatus = KS_RELEASE; //当前状态(每次循环后与g_keyStatus保持一致)
KEY_STATUS g_lastKeyStatus = KS_RELEASE; //上次状态(用于记录前一状态以区分状态的来源)
注意:此处的g_lastKeyStatus用于记录前一状态,上篇文章中也有这个变量,但作用不同,上篇文章中此变量的作用与此处的g_nowKeyStatus作用相同。
1.2 代码
对照简化后的状态图,编写对应的状态机逻辑代码:
void key_status_check()
{
switch(g_keyStatus)
{
//按键释放(初始状态)
case KS_RELEASE:
{
//检测到低电平,先进行消抖
if (KEY0 == 0)
{
g_keyStatus = KS_SHAKE;
}
}
break;
//抖动
case KS_SHAKE:
{
if (KEY0 == 1)
{
g_keyStatus = KS_RELEASE;
if (KS_PRESS == g_lastKeyStatus)
{
printf("=====> key release\r\n");
}
}
else
{
g_keyStatus = KS_PRESS;
if (KS_RELEASE == g_lastKeyStatus)
{
printf("=====> key press\r\n");
}
}
}
break;
//稳定短按
case KS_PRESS:
{
//检测到高电平,先进行消抖
if (KEY0 == 1)
{
g_keyStatus = KS_SHAKE;
}
}
break;
default:break;
}
if (g_keyStatus != g_nowKeyStatus)
{
g_lastKeyStatus = g_nowKeyStatus;
g_nowKeyStatus = g_keyStatus;
printf("new key status:%d(%s)\r\n", g_keyStatus, key_status_name[g_keyStatus]);
}
}
注意g_lastKeyStatus变量的作用。
1.3 测试
2 增加长按功能
在检测按下与松开的基础上,再增加长按功能,在状态图中需要增加一个长按状态。然后,对照着状态图修改代码即可。
同样,根据是否需要区分两种抖动状态以及状态机循环周期的不同,可以有两种状态图。
2.1 未简化的状态图
先来看一下循环周期10ms,区分按下抖动与松开抖动这种情况增加长按功能后的状态图:
状态图理清逻辑后,根据状态图,修改对应的代码即可,这里不再贴代码,完整代码可去我的代码仓库查看
2.2 简化的状态图
下面再来看简化消抖状态的具体长按功能的状态机图:
对比可以发现,简化的状态图,状态可以少一个,不过抖动的状态,会有更多的输入和输出,因为目前每隔状态都有经过这个状态。
如果对于抖动检测的要求不高,也可以只保留按下抖动的逻辑,松开抖动的分支去掉,直接跳到松开状态,可以再次简化状态逻辑。
2.3 代码
根据状态图图,编写对应的状态机逻辑代码,如下:
void key_status_check()
{
switch(g_keyStatus)
{
//按键释放(初始状态)
case KS_RELEASE:
{
//检测到低电平,先进行消抖
if (KEY0 == 0)
{
g_keyStatus = KS_SHAKE;
}
}
break;
//抖动
case KS_SHAKE:
{
if (KEY0 == 1)
{
g_keyStatus = KS_RELEASE;
if (KS_SHORT_PRESS == g_lastKeyStatus || KS_LONG_PRESS == g_lastKeyStatus)
{
printf("=====> key release\r\n");
}
}
else
{
if (KS_RELEASE == g_lastKeyStatus)
{
g_PressTimeCnt = 0;
g_keyStatus = KS_SHORT_PRESS;
printf("=====> key short press\r\n");
}
else if (KS_SHORT_PRESS == g_lastKeyStatus)
{
g_keyStatus = KS_SHORT_PRESS;
}
else
{
}
}
}
break;
//稳定短按
case KS_SHORT_PRESS:
{
//检测到高电平,先进行消抖
if (KEY0 == 1)
{
g_keyStatus = KS_SHAKE;
}
g_PressTimeCnt++;
if (g_PressTimeCnt == 20) //1000ms
{
g_keyStatus = KS_LONG_PRESS;
printf("=====> key long press\r\n");
}
}
break;
//稳定长按
case KS_LONG_PRESS:
{
//检测到高电平,先进行消抖
if (KEY0 == 1)
{
g_keyStatus = KS_SHAKE;
}
g_PressTimeCnt++;
if (g_PressTimeCnt % 20 == 0) //每隔1000ms打印一次
{
printf("=====> key long press:%d\r\n", g_PressTimeCnt/20);
}
}
break;
default:break;
}
if (g_keyStatus != g_nowKeyStatus)
{
g_lastKeyStatus = g_nowKeyStatus;
g_nowKeyStatus = g_keyStatus;
printf("new key status:%d(%s)\r\n", g_keyStatus, key_status_name[g_keyStatus]);
}
}
注意,在抖动状态,当检测为高电平(按键松开),不管前一状态是短按还是长按,下一状态都是松开状态。
2.4 测试
3 总结
本篇继续介绍状态机的使用,在上篇的基础上,通过简化按键去抖逻辑,并增加按键长按功能,进一步介绍状态图的修改与状态机代码的实现,并通过实际测试,演示状态机的运行效果。
边栏推荐
- OpenCV中如何使用滚动条动态调整参数
- Sqoop I have everything you want
- Awk command exercise
- PyTorch 提取中间层特征?
- The art of Engineering (1): try to package things that do not need to be exposed
- Mysqlimport imports data files into the database
- 二分(整数二分、实数二分)
- [rapid environment construction] openharmony 10 minute tutorial (cub pie)
- sql语句优化,order by desc速度优化
- F200——搭载基于模型设计的国产开源飞控系统无人机
猜你喜欢
OpenCV中如何使用滚动条动态调整参数
Solution qui ne peut pas être retournée après la mise à jour du navigateur Web flutter
Getting started with pytest ----- test case rules
Summary of Android interview questions of Dachang in 2022 (I) (including answers)
RB157-ASEMI整流桥RB157
历史上的今天:Google 之母出生;同一天诞生的两位图灵奖先驱
[elastic] elastic lacks xpack and cannot create template unknown setting index lifecycle. name index. lifecycle. rollover_ alias
BearPi-HM_ Nano development board "flower protector" case
The easycvr authorization expiration page cannot be logged in. How to solve it?
分布式(一致性协议)之领导人选举( DotNext.Net.Cluster 实现Raft 选举 )
随机推荐
Smart street lamp based on stm32+ Huawei cloud IOT design
Alibaba brand data bank: introduction to the most complete data bank
Cool Lehman has a variety of AI digital human images to create a vr virtual exhibition hall with a sense of technology
Spark calculation operator and some small details in liunx
编译原理——预测表C语言实现
带你穿越古罗马,元宇宙巴士来啦 #Invisible Cities
adb常用命令
Grafana 9 is officially released, which is easier to use and more cool!
C # nanoframework lighting and key esp32
What is the reason why the video cannot be played normally after the easycvr access device turns on the audio?
FlutterWeb浏览器刷新后无法回退的解决方案
[introduction to MySQL] the first sentence · first time in the "database" Mainland
The shell generates JSON arrays and inserts them into the database
The art of Engineering
《ASP.NET Core 6框架揭秘》样章发布[200页/5章]
Unity tips - draw aiming Center
Nodejs developer roadmap 2022 zero foundation Learning Guide
Xin'an Second Edition: Chapter 12 network security audit technology principle and application learning notes
重磅!蚂蚁开源可信隐私计算框架“隐语”,主流技术灵活组装、开发者友好分层设计...
Optimization of middle alignment of loading style of device player in easycvr electronic map