当前位置:网站首页>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 总结
本篇继续介绍状态机的使用,在上篇的基础上,通过简化按键去抖逻辑,并增加按键长按功能,进一步介绍状态图的修改与状态机代码的实现,并通过实际测试,演示状态机的运行效果。
边栏推荐
- 一体化实时 HTAP 数据库 StoneDB,如何替换 MySQL 并实现近百倍性能提升
- Xin'an Second Edition: Chapter 25 mobile application security requirements analysis and security protection engineering learning notes
- Flet教程之 13 ListView最常用的滚动控件 基础入门(教程含源码)
- How to output special symbols in shell
- 李书福为何要亲自挂帅造手机?
- The art of Engineering (3): do not rely on each other between functions of code robustness
- PyTorch 提取中间层特征?
- Basic configuration and use of spark
- Wordcloud colormap color set and custom colors
- QT中Model-View-Delegate委托代理机制用法介绍
猜你喜欢
How to solve the error "press any to exit" when deploying multiple easycvr on one server?
Getting started with pytest ----- test case pre post, firmware
JMeter interface test response data garbled
RB157-ASEMI整流桥RB157
FMT开源自驾仪 | FMT中间件:一种高实时的分布式日志模块Mlog
Basic configuration and use of spark
Unity粒子特效系列-闪星星的宝箱
sql语句优化,order by desc速度优化
Chrome prompts the solution of "your company management" (the startup page is bound to the company's official website and cannot be modified)
Pourquoi Li shufu a - t - il construit son téléphone portable?
随机推荐
Spark accumulator and broadcast variables and beginners of sparksql
Guidelines for preparing for the 2022 soft exam information security engineer exam
OpenCV中如何使用滚动条动态调整参数
编译原理——自上而下分析与递归下降分析构造(笔记)
kivy教程之在 Kivy 中支持中文以构建跨平台应用程序(教程含源码)
EasyCVR电子地图中设备播放器loading样式的居中对齐优化
[ASM] introduction and use of bytecode operation classwriter class
node の SQLite
Fleet tutorial 13 basic introduction to listview's most commonly used scroll controls (tutorial includes source code)
Hongmeng introduction and development environment construction
The integrated real-time HTAP database stonedb, how to replace MySQL and achieve nearly a hundredfold performance improvement
重磅硬核 | 一文聊透对象在 JVM 中的内存布局,以及内存对齐和压缩指针的原理及应用
Xin'an Second Edition; Chapter 11 learning notes on the principle and application of network physical isolation technology
Distributed (consistency protocol) leader election (dotnext.net.cluster implements raft election)
Remote code execution penetration test - B module test
Solid principle
Openharmony developer documentation open source project
Zen integration nails, bugs, needs, etc. are reminded by nails
【MySQL入门】第三话 · MySQL中常见的数据类型
Easy introduction to SQL (1): addition, deletion, modification and simple query