0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀(guān)看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

STM32按鍵狀態(tài)機(jī)2——狀態(tài)簡(jiǎn)化與增加長(zhǎng)按功能

碼農(nóng)愛(ài)學(xué)習(xí) ? 來(lái)源:碼農(nóng)愛(ài)學(xué)習(xí) ? 作者:碼農(nóng)愛(ài)學(xué)習(xí) ? 2022-09-03 21:26 ? 次閱讀

上篇文章,以按鍵消抖功能,介紹了狀態(tài)機(jī)的基本原理與使用方法。

上篇的狀態(tài)圖如下:

pYYBAGMTVW2AbP_JAABRjnFQAbg846.png

由于只檢測(cè)按下與松開(kāi),并具備按鍵消抖功能,因此用到了如上的4個(gè)狀態(tài),按下抖動(dòng)和松開(kāi)抖動(dòng)是兩個(gè)獨(dú)立的狀態(tài),并且這兩個(gè)抖動(dòng)的狀態(tài),也是可以在多次循環(huán)中連續(xù)運(yùn)行的,這個(gè)狀態(tài)機(jī)的循環(huán)周期設(shè)置的為10ms,當(dāng)在抖動(dòng)狀態(tài)連續(xù)檢測(cè)到某一電平5次后,即認(rèn)為消抖完成,進(jìn)入下一個(gè)穩(wěn)定狀態(tài)。

對(duì)于同一個(gè)功能,狀態(tài)圖不是一成不變的,對(duì)于按鍵消抖,還可以將兩個(gè)抖動(dòng)狀態(tài)共用一個(gè)抖動(dòng)狀態(tài)來(lái)表示。

1 消抖狀態(tài)簡(jiǎn)化

1.1 狀態(tài)圖

將按下抖動(dòng)與松開(kāi)抖動(dòng)共用一個(gè)抖動(dòng)狀態(tài)來(lái)表示,同時(shí)需要將狀態(tài)機(jī)的循環(huán)周期設(shè)置為50ms,這樣,抖動(dòng)狀態(tài)只需經(jīng)過(guò)一次,通過(guò)電平高低即可判定是否真的為按鍵抖動(dòng)。簡(jiǎn)化后的狀態(tài)圖如下:

pYYBAGMTVX6ALtdvAAA60lHhaz8625.png

為了能在抖動(dòng)狀態(tài)時(shí),區(qū)分前一狀態(tài)是松開(kāi)還是按下,進(jìn)而判斷此次是抖動(dòng)還是按鍵真的動(dòng)作,需要增加一個(gè)狀態(tài)來(lái)記錄前一狀態(tài)

KEY_STATUS g_keyStatus = KS_RELEASE; //當(dāng)前循環(huán)結(jié)束的(狀態(tài)機(jī)的)狀態(tài)
KEY_STATUS g_nowKeyStatus = KS_RELEASE; //當(dāng)前狀態(tài)(每次循環(huán)后與g_keyStatus保持一致)
KEY_STATUS g_lastKeyStatus = KS_RELEASE; //上次狀態(tài)(用于記錄前一狀態(tài)以區(qū)分狀態(tài)的來(lái)源)

注意:此處的g_lastKeyStatus用于記錄前一狀態(tài),上篇文章中也有這個(gè)變量,但作用不同,上篇文章中此變量的作用與此處的g_nowKeyStatus作用相同。

1.2 代碼

對(duì)照簡(jiǎn)化后的狀態(tài)圖,編寫(xiě)對(duì)應(yīng)的狀態(tài)機(jī)邏輯代碼:

void key_status_check()
{
	switch(g_keyStatus)
	{
		//按鍵釋放(初始狀態(tài))
		case KS_RELEASE:
		{
			//檢測(cè)到低電平,先進(jìn)行消抖
			if (KEY0 == 0)
			{
				g_keyStatus = KS_SHAKE;
			}
		}
		break;
		
		//抖動(dòng)
		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;
		
		//穩(wěn)定短按
		case KS_PRESS:
		{
			//檢測(cè)到高電平,先進(jìn)行消抖
			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 測(cè)試

pYYBAGMTVbGAMAUNAAB4Xv-VoTs974.png

2 增加長(zhǎng)按功能

在檢測(cè)按下與松開(kāi)的基礎(chǔ)上,再增加長(zhǎng)按功能,在狀態(tài)圖中需要增加一個(gè)長(zhǎng)按狀態(tài)。然后,對(duì)照著狀態(tài)圖修改代碼即可。

同樣,根據(jù)是否需要區(qū)分兩種抖動(dòng)狀態(tài)以及狀態(tài)機(jī)循環(huán)周期的不同,可以有兩種狀態(tài)圖。

2.1 未簡(jiǎn)化的狀態(tài)圖

先來(lái)看一下循環(huán)周期10ms,區(qū)分按下抖動(dòng)與松開(kāi)抖動(dòng)這種情況增加長(zhǎng)按功能后的狀態(tài)圖:

poYBAGMTVbyAWqczAABtAHqK4L0837.png

狀態(tài)圖理清邏輯后,根據(jù)狀態(tài)圖,修改對(duì)應(yīng)的代碼即可,這里不再貼代碼,完整代碼可去我的代碼倉(cāng)庫(kù)查看(文末閱讀原文直達(dá)~)

2.2 簡(jiǎn)化的狀態(tài)圖

下面再來(lái)看簡(jiǎn)化消抖狀態(tài)的具體長(zhǎng)按功能的狀態(tài)機(jī)圖:

pYYBAGMTVcKAAzPKAABa-BfEo28672.png

對(duì)比可以發(fā)現(xiàn),簡(jiǎn)化的狀態(tài)圖,狀態(tài)可以少一個(gè),不過(guò)抖動(dòng)的狀態(tài),會(huì)有更多的輸入和輸出,因?yàn)槟壳懊扛魻顟B(tài)都有經(jīng)過(guò)這個(gè)狀態(tài)。

如果對(duì)于抖動(dòng)檢測(cè)的要求不高,也可以只保留按下抖動(dòng)的邏輯,松開(kāi)抖動(dòng)的分支去掉,直接跳到松開(kāi)狀態(tài),可以再次簡(jiǎn)化狀態(tài)邏輯。

2.3 代碼

根據(jù)狀態(tài)圖圖,編寫(xiě)對(duì)應(yīng)的狀態(tài)機(jī)邏輯代碼,如下:

void key_status_check()
{
	switch(g_keyStatus)
	{
		//按鍵釋放(初始狀態(tài))
		case KS_RELEASE:
		{
			//檢測(cè)到低電平,先進(jìn)行消抖
			if (KEY0 == 0)
			{
				g_keyStatus = KS_SHAKE;
			}
		}
		break;
		
		//抖動(dòng)
		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;
		
		//穩(wěn)定短按
		case KS_SHORT_PRESS:
		{
			//檢測(cè)到高電平,先進(jìn)行消抖
			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;
		
	    //穩(wěn)定長(zhǎng)按
		case KS_LONG_PRESS:
		{
			//檢測(cè)到高電平,先進(jìn)行消抖
			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]);
	}
}

注意,在抖動(dòng)狀態(tài),當(dāng)檢測(cè)為高電平(按鍵松開(kāi)),不管前一狀態(tài)是短按還是長(zhǎng)按,下一狀態(tài)都是松開(kāi)狀態(tài)。

2.4 測(cè)試

pYYBAGMTVeWADc--AACvIpyovcU938.png

3 總結(jié)

本篇繼續(xù)介紹狀態(tài)機(jī)的使用,在上篇的基礎(chǔ)上,通過(guò)簡(jiǎn)化按鍵去抖邏輯,并增加按鍵長(zhǎng)按功能,進(jìn)一步介紹狀態(tài)圖的修改與狀態(tài)機(jī)代碼的實(shí)現(xiàn),并通過(guò)實(shí)際測(cè)試,演示狀態(tài)機(jī)的運(yùn)行效果。

審核編輯 黃昊宇

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀(guān)點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 嵌入式
    +關(guān)注

    關(guān)注

    5052

    文章

    18914

    瀏覽量

    300846
  • STM32
    +關(guān)注

    關(guān)注

    2263

    文章

    10847

    瀏覽量

    353797
  • 狀態(tài)機(jī)
    +關(guān)注

    關(guān)注

    2

    文章

    490

    瀏覽量

    27436
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    STM32按鍵消抖——入門(mén)狀態(tài)機(jī)思維

    本篇介紹了嵌入式軟件開(kāi)發(fā)中常用的狀態(tài)機(jī)編程實(shí)現(xiàn),并通過(guò)按鍵消抖實(shí)例,以常用的switch-case形式,實(shí)現(xiàn)了對(duì)應(yīng)的狀態(tài)機(jī)編程代碼實(shí)現(xiàn),并通過(guò)測(cè)試,串口打印對(duì)應(yīng)狀態(tài),分析
    的頭像 發(fā)表于 09-02 21:54 ?4708次閱讀
    <b class='flag-5'>STM32</b><b class='flag-5'>按鍵</b>消抖——入門(mén)<b class='flag-5'>狀態(tài)機(jī)</b>思維

    STM32按鍵狀態(tài)機(jī)3——增加雙擊與功能優(yōu)化

    本篇在前兩篇按鍵狀態(tài)機(jī)的基礎(chǔ)上,繼續(xù)介紹增加按鍵的雙擊功能,并解決之前狀態(tài)存在的兩個(gè)問(wèn)題,通過(guò)實(shí)測(cè)驗(yàn)證,演示短按、
    的頭像 發(fā)表于 09-04 17:05 ?2024次閱讀
    <b class='flag-5'>STM32</b><b class='flag-5'>按鍵</b><b class='flag-5'>狀態(tài)機(jī)</b>3——<b class='flag-5'>增加</b>雙擊與<b class='flag-5'>功能</b>優(yōu)化

    單片機(jī)狀態(tài)機(jī)按鍵長(zhǎng)按和短按實(shí)現(xiàn)

    本文只介紹主要代碼段,完整代碼可參考我的“藍(lán)橋杯單片機(jī)狀態(tài)機(jī)按鍵按下和松開(kāi)實(shí)現(xiàn)不同功能”藍(lán)橋杯單片機(jī)狀態(tài)
    發(fā)表于 01-06 08:26

    請(qǐng)問(wèn)按鍵狀態(tài)機(jī)長(zhǎng)按和短按測(cè)試該怎樣去實(shí)現(xiàn)呢

    什么是按鍵消抖呢?按鍵狀態(tài)機(jī)長(zhǎng)按和短按測(cè)試該怎樣去實(shí)現(xiàn)呢?
    發(fā)表于 01-20 06:45

    利用狀態(tài)機(jī)按鍵消抖程序

    利用狀態(tài)機(jī)按鍵消抖程序講解,很好的資料下載吧。
    發(fā)表于 01-11 09:32 ?30次下載

    狀態(tài)機(jī)原理及用法

    狀態(tài)機(jī)原理及用法狀態(tài)機(jī)原理及用法狀態(tài)機(jī)原理及用法
    發(fā)表于 03-15 15:25 ?0次下載

    基于狀態(tài)機(jī)的單片機(jī)按鍵短按長(zhǎng)按功能的實(shí)現(xiàn)

    本文主要介紹了基于狀態(tài)機(jī)的單片機(jī)按鍵短按長(zhǎng)按功能的實(shí)現(xiàn),按鍵的擊鍵過(guò)程也是一種
    發(fā)表于 12-28 08:43 ?1.9w次閱讀
    基于<b class='flag-5'>狀態(tài)機(jī)</b>的單片<b class='flag-5'>機(jī)</b><b class='flag-5'>按鍵</b>短按<b class='flag-5'>長(zhǎng)按</b><b class='flag-5'>功能</b>的實(shí)現(xiàn)

    狀態(tài)機(jī)如何簡(jiǎn)化PLC程序的編寫(xiě)

    在PLC程序的編寫(xiě)過(guò)程中,可以使用狀態(tài)機(jī)的控制思路,將一些復(fù)雜的控制過(guò)程使用狀態(tài)機(jī)的方法處理。這里簡(jiǎn)單給大家介紹一下什么是狀態(tài)機(jī)?如下圖所示,為一個(gè)狀態(tài)機(jī)
    的頭像 發(fā)表于 09-10 14:44 ?3793次閱讀
    <b class='flag-5'>狀態(tài)機(jī)</b>如何<b class='flag-5'>簡(jiǎn)化</b>PLC程序的編寫(xiě)

    基于STM32F103C8T6的多按鍵檢測(cè) | 有限狀態(tài)機(jī)短按、長(zhǎng)按識(shí)別 | 標(biāo)準(zhǔn)庫(kù)函數(shù)實(shí)現(xiàn)方法

    制作航模遙控器需要用到多按鍵檢測(cè),使用有限狀態(tài)機(jī)實(shí)現(xiàn)檢測(cè)短按、長(zhǎng)按,修正了原文中的一些錯(cuò)誤
    發(fā)表于 11-26 11:21 ?36次下載
    基于<b class='flag-5'>STM32</b>F103C8T6的多<b class='flag-5'>按鍵</b>檢測(cè) | 有限<b class='flag-5'>狀態(tài)機(jī)</b>短按、<b class='flag-5'>長(zhǎng)按</b>識(shí)別 | 標(biāo)準(zhǔn)庫(kù)函數(shù)實(shí)現(xiàn)方法

    基于STM32按鍵的防抖和松開(kāi)處理:狀態(tài)機(jī)

    用延時(shí)和while();去處理按鍵很浪費(fèi)資源,這里我們用定時(shí)器來(lái)做一個(gè)按鍵的處理-狀態(tài)機(jī);typedef enum {KEY_RELEASED,KEY_PRESSED,KEY_PROCESSED
    發(fā)表于 12-09 09:21 ?7次下載
    基于<b class='flag-5'>STM32</b><b class='flag-5'>按鍵</b>的防抖和松開(kāi)處理:<b class='flag-5'>狀態(tài)機(jī)</b>

    狀態(tài)模式(狀態(tài)機(jī))

    share,作者:亞索老哥)),原來(lái)狀態(tài)機(jī)還可以這么簡(jiǎn)單地玩~~亞索老哥提出的狀態(tài)機(jī)六步法(1)、定義狀態(tài)接口(2)、定義系統(tǒng)當(dāng)前狀態(tài)指針
    發(fā)表于 12-16 16:53 ?8次下載
    <b class='flag-5'>狀態(tài)</b>模式(<b class='flag-5'>狀態(tài)機(jī)</b>)

    STM32實(shí)現(xiàn)按鍵有限狀態(tài)機(jī)(超詳細(xì),易移植)

    STM32實(shí)現(xiàn)按鍵有限狀態(tài)機(jī)(超詳細(xì),易移植)一、狀態(tài)機(jī)簡(jiǎn)而言之,狀態(tài)機(jī)是使不同狀態(tài)之間的改變以
    發(fā)表于 12-17 18:37 ?26次下載
    <b class='flag-5'>STM32</b>實(shí)現(xiàn)<b class='flag-5'>按鍵</b>有限<b class='flag-5'>狀態(tài)機(jī)</b>(超詳細(xì),易移植)

    藍(lán)橋杯單片機(jī)狀態(tài)機(jī)按鍵按下和松開(kāi)實(shí)現(xiàn)不同功能

    藍(lán)橋杯單片機(jī)狀態(tài)機(jī)按鍵按下和松開(kāi)實(shí)現(xiàn)不同功能獨(dú)立按鍵狀態(tài)機(jī)讀取函數(shù)key_flag 鍵值讀取標(biāo)志
    發(fā)表于 12-29 19:25 ?20次下載
    藍(lán)橋杯單片<b class='flag-5'>機(jī)</b><b class='flag-5'>狀態(tài)機(jī)</b><b class='flag-5'>按鍵</b>按下和松開(kāi)實(shí)現(xiàn)不同<b class='flag-5'>功能</b>

    按鍵狀態(tài)機(jī)代碼

    自己寫(xiě)的按鍵狀態(tài)機(jī),需要的時(shí)候根據(jù)情況修改一下
    發(fā)表于 03-27 10:42 ?7次下載

    什么是狀態(tài)機(jī)狀態(tài)機(jī)的種類(lèi)與實(shí)現(xiàn)

    狀態(tài)機(jī),又稱(chēng)有限狀態(tài)機(jī)(Finite State Machine,F(xiàn)SM)或米利狀態(tài)機(jī)(Mealy Machine),是一種描述系統(tǒng)狀態(tài)變化的模型。在芯片設(shè)計(jì)中,
    的頭像 發(fā)表于 10-19 10:27 ?8601次閱讀