当前位置:网站首页>STM32按键状态机2——状态简化与增加长按功能
STM32按键状态机2——状态简化与增加长按功能
2022-07-07 00:04: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 总结
本篇继续介绍状态机的使用,在上篇的基础上,通过简化按键去抖逻辑,并增加按键长按功能,进一步介绍状态图的修改与状态机代码的实现,并通过实际测试,演示状态机的运行效果。
边栏推荐
- English语法_名词 - 所有格
- 论文阅读【Open-book Video Captioning with Retrieve-Copy-Generate Network】
- Introduction to distributed transactions
- Go 語言的 Context 詳解
- 力扣102题:二叉树的层序遍历
- Design, configuration and points for attention of network arbitrary source multicast (ASM) simulation using OPNET
- 数据中心为什么需要一套基础设施可视化管理系统
- C#可空类型
- English grammar_ Noun possessive
- Différenciation et introduction des services groupés, distribués et microservices
猜你喜欢
4. Object mapping Mapster
上海字节面试问题及薪资福利
拼多多商品详情接口、拼多多商品基本信息、拼多多商品属性接口
Mapbox Chinese map address
Digital innovation driven guide
5. Data access - entityframework integration
bat 批示处理详解
How digitalization affects workflow automation
Message queuing: how to ensure that messages are not lost
The year of the tiger is coming. Come and make a wish. I heard that the wish will come true
随机推荐
往图片添加椒盐噪声或高斯噪声
Mybaits之多表查询(联合查询、嵌套查询)
集群、分布式、微服務的區別和介紹
Lombok插件
Hcip eighth operation
nodejs获取客户端ip
软件测试面试技巧
Leakage relay jelr-250fg
What are the common message queues?
纪念下,我从CSDN搬家到博客园啦!
Three level menu data implementation, nested three-level menu data
C#可空类型
Photo selector collectionview
基于NCF的多模块协同实例
Unity让摄像机一直跟随在玩家后上方
Simple case of SSM framework
分布式事务解决方案之TCC
Design, configuration and points for attention of network arbitrary source multicast (ASM) simulation using OPNET
Nodejs get client IP
English语法_名词 - 所有格