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

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

3天内不再提示

STM32按键状态机2——状态简化与增加长按功能

码农爱学习 来源:码农爱学习 作者:码农爱学习 2022-09-03 21:26 次阅读

上篇文章,以按键消抖功能,介绍了状态机的基本原理与使用方法。

上篇的状态图如下:

pYYBAGMTVW2AbP_JAABRjnFQAbg846.png

由于只检测按下与松开,并具备按键消抖功能,因此用到了如上的4个状态,按下抖动和松开抖动是两个独立的状态,并且这两个抖动的状态,也是可以在多次循环中连续运行的,这个状态机的循环周期设置的为10ms,当在抖动状态连续检测到某一电平5次后,即认为消抖完成,进入下一个稳定状态。

对于同一个功能,状态图不是一成不变的,对于按键消抖,还可以将两个抖动状态共用一个抖动状态来表示。

1 消抖状态简化

1.1 状态图

将按下抖动与松开抖动共用一个抖动状态来表示,同时需要将状态机的循环周期设置为50ms,这样,抖动状态只需经过一次,通过电平高低即可判定是否真的为按键抖动。简化后的状态图如下:

pYYBAGMTVX6ALtdvAAA60lHhaz8625.png

为了能在抖动状态时,区分前一状态是松开还是按下,进而判断此次是抖动还是按键真的动作,需要增加一个状态来记录前一状态

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 测试

pYYBAGMTVbGAMAUNAAB4Xv-VoTs974.png

2 增加长按功能

在检测按下与松开的基础上,再增加长按功能,在状态图中需要增加一个长按状态。然后,对照着状态图修改代码即可。

同样,根据是否需要区分两种抖动状态以及状态机循环周期的不同,可以有两种状态图。

2.1 未简化的状态图

先来看一下循环周期10ms,区分按下抖动与松开抖动这种情况增加长按功能后的状态图:

poYBAGMTVbyAWqczAABtAHqK4L0837.png

状态图理清逻辑后,根据状态图,修改对应的代码即可,这里不再贴代码,完整代码可去我的代码仓库查看(文末阅读原文直达~)

2.2 简化的状态图

下面再来看简化消抖状态的具体长按功能的状态机图:

pYYBAGMTVcKAAzPKAABa-BfEo28672.png

对比可以发现,简化的状态图,状态可以少一个,不过抖动的状态,会有更多的输入和输出,因为目前每隔状态都有经过这个状态。

如果对于抖动检测的要求不高,也可以只保留按下抖动的逻辑,松开抖动的分支去掉,直接跳到松开状态,可以再次简化状态逻辑。

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 测试

pYYBAGMTVeWADc--AACvIpyovcU938.png

3 总结

本篇继续介绍状态机的使用,在上篇的基础上,通过简化按键去抖逻辑,并增加按键长按功能,进一步介绍状态图的修改与状态机代码的实现,并通过实际测试,演示状态机的运行效果。

审核编辑 黄昊宇

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式
    +关注

    关注

    4981

    文章

    18274

    浏览量

    288364
  • STM32
    +关注

    关注

    2239

    文章

    10671

    浏览量

    348720
  • 状态机
    +关注

    关注

    2

    文章

    486

    浏览量

    27161
收藏 人收藏

    评论

    相关推荐

    STM32按键消抖——入门状态机思维

    本篇介绍了嵌入式软件开发中常用的状态机编程实现,并通过按键消抖实例,以常用的switch-case形式,实现了对应的状态机编程代码实现,并通过测试,串口打印对应状态,分析
    的头像 发表于 09-02 21:54 4278次阅读
    <b class='flag-5'>STM32</b><b class='flag-5'>按键</b>消抖——入门<b class='flag-5'>状态机</b>思维

    STM32按键状态机3——增加双击与功能优化

    本篇在前两篇按键状态机的基础上,继续介绍增加按键的双击功能,并解决之前状态存在的两个问题,通过实测验证,演示短按、
    的头像 发表于 09-04 17:05 1608次阅读
    <b class='flag-5'>STM32</b><b class='flag-5'>按键</b><b class='flag-5'>状态机</b>3——<b class='flag-5'>增加</b>双击与<b class='flag-5'>功能</b>优化

    状态机编程

    状态机编程基于状态机按键输入软件接口设计一般的教课书中给出的按键输入软件接口程序通常非常简单,在程序中一旦检测到按键输入口为低电平时(图9
    发表于 07-10 18:00

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

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

    如何利用状态机进行编程呢

    很多上升沿或下降沿,会引起误判。这里我们使用状态机的方式去处理,使用状态机还有一个好处就是可以很方便的去判断长按,短按,双击等状态。当触摸屏有触点按下时,PENIRQ 引脚会输出低电平
    发表于 01-13 07:18

    请问按键状态机长按和短按测试该怎样去实现呢

    什么是按键消抖呢?按键状态机长按和短按测试该怎样去实现呢?
    发表于 01-20 06:45

    如何利用STM32去实现一种按键有限状态机

    STM32实现按键有限状态机(超详细,易移植)一、状态机简而言之,状态机是使不同状态之间的改变以
    发表于 02-16 06:58

    独立按键状态机读取函数的过程分享

    蓝桥杯单片状态机按键按下和松开实现不同功能独立按键状态机读取函数key_flag 键值读取标志
    发表于 02-23 06:20

    利用状态机按键消抖程序

    利用状态机按键消抖程序讲解,很好的资料下载吧。
    发表于 01-11 09:32 30次下载

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

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

    基于STM32F103C8T6的多按键检测 | 有限状态机短按、长按识别 | 标准库函数实现方法

    制作航模遥控器需要用到多按键检测,使用有限状态机实现检测短按、长按,修正了原文中的一些错误
    发表于 11-26 11:21 36次下载
    基于<b class='flag-5'>STM32</b>F103C8T6的多<b class='flag-5'>按键</b>检测 | 有限<b class='flag-5'>状态机</b>短按、<b class='flag-5'>长按</b>识别 | 标准库函数实现方法

    基于STM32按键的防抖和松开处理:状态机

    用延时和while();去处理按键很浪费资源,这里我们用定时器来做一个按键的处理-状态机;typedef enum {KEY_RELEASED,KEY_PRESSED,KEY_PROCESSED
    发表于 12-09 09:21 7次下载
    基于<b class='flag-5'>STM32</b><b class='flag-5'>按键</b>的防抖和松开处理:<b class='flag-5'>状态机</b>

    STM32实现按键有限状态机(超详细,易移植)

    STM32实现按键有限状态机(超详细,易移植)一、状态机简而言之,状态机是使不同状态之间的改变以
    发表于 12-17 18:37 25次下载
    <b class='flag-5'>STM32</b>实现<b class='flag-5'>按键</b>有限<b class='flag-5'>状态机</b>(超详细,易移植)

    蓝桥杯单片机状态机按键按下和松开实现不同功能

    蓝桥杯单片机状态机按键按下和松开实现不同功能独立按键状态机读取函数key_flag 键值读取标志位key 主函数中得到键值key_press
    发表于 12-29 19:25 20次下载
    蓝桥杯单片机<b class='flag-5'>状态机</b><b class='flag-5'>按键</b>按下和松开实现不同<b class='flag-5'>功能</b>

    按键状态机代码

    自己写的按键状态机,需要的时候根据情况修改一下
    发表于 03-27 10:42 6次下载