上篇文章,以按鍵消抖功能,介紹了狀態(tài)機的基本原理與使用方法。
上篇的狀態(tài)圖如下:
![pYYBAGMTVW2AbP_JAABRjnFQAbg846.png](https://file.elecfans.com/web2/M00/67/6F/pYYBAGMTVW2AbP_JAABRjnFQAbg846.png)
由于只檢測按下與松開,并具備按鍵消抖功能,因此用到了如上的4個狀態(tài),按下抖動和松開抖動是兩個獨立的狀態(tài),并且這兩個抖動的狀態(tài),也是可以在多次循環(huán)中連續(xù)運行的,這個狀態(tài)機的循環(huán)周期設置的為10ms,當在抖動狀態(tài)連續(xù)檢測到某一電平5次后,即認為消抖完成,進入下一個穩(wěn)定狀態(tài)。
對于同一個功能,狀態(tài)圖不是一成不變的,對于按鍵消抖,還可以將兩個抖動狀態(tài)共用一個抖動狀態(tài)來表示。
1 消抖狀態(tài)簡化
1.1 狀態(tài)圖
將按下抖動與松開抖動共用一個抖動狀態(tài)來表示,同時需要將狀態(tài)機的循環(huán)周期設置為50ms,這樣,抖動狀態(tài)只需經過一次,通過電平高低即可判定是否真的為按鍵抖動。簡化后的狀態(tài)圖如下:
![pYYBAGMTVX6ALtdvAAA60lHhaz8625.png](https://file.elecfans.com/web2/M00/67/6F/pYYBAGMTVX6ALtdvAAA60lHhaz8625.png)
為了能在抖動狀態(tài)時,區(qū)分前一狀態(tài)是松開還是按下,進而判斷此次是抖動還是按鍵真的動作,需要增加一個狀態(tài)來記錄前一狀態(tài)
KEY_STATUS g_keyStatus = KS_RELEASE; //當前循環(huán)結束的(狀態(tài)機的)狀態(tài)
KEY_STATUS g_nowKeyStatus = KS_RELEASE; //當前狀態(tài)(每次循環(huán)后與g_keyStatus保持一致)
KEY_STATUS g_lastKeyStatus = KS_RELEASE; //上次狀態(tài)(用于記錄前一狀態(tài)以區(qū)分狀態(tài)的來源)
注意:此處的g_lastKeyStatus用于記錄前一狀態(tài),上篇文章中也有這個變量,但作用不同,上篇文章中此變量的作用與此處的g_nowKeyStatus作用相同。
1.2 代碼
對照簡化后的狀態(tài)圖,編寫對應的狀態(tài)機邏輯代碼:
void key_status_check()
{
switch(g_keyStatus)
{
//按鍵釋放(初始狀態(tài))
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;
//穩(wěn)定短按
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](https://file.elecfans.com/web2/M00/67/6F/pYYBAGMTVbGAMAUNAAB4Xv-VoTs974.png)
2 增加長按功能
在檢測按下與松開的基礎上,再增加長按功能,在狀態(tài)圖中需要增加一個長按狀態(tài)。然后,對照著狀態(tài)圖修改代碼即可。
同樣,根據(jù)是否需要區(qū)分兩種抖動狀態(tài)以及狀態(tài)機循環(huán)周期的不同,可以有兩種狀態(tài)圖。
2.1 未簡化的狀態(tài)圖
先來看一下循環(huán)周期10ms,區(qū)分按下抖動與松開抖動這種情況增加長按功能后的狀態(tài)圖:
![poYBAGMTVbyAWqczAABtAHqK4L0837.png](https://file.elecfans.com/web2/M00/66/D5/poYBAGMTVbyAWqczAABtAHqK4L0837.png)
狀態(tài)圖理清邏輯后,根據(jù)狀態(tài)圖,修改對應的代碼即可,這里不再貼代碼,完整代碼可去我的代碼倉庫查看(文末閱讀原文直達~)
2.2 簡化的狀態(tài)圖
下面再來看簡化消抖狀態(tài)的具體長按功能的狀態(tài)機圖:
![pYYBAGMTVcKAAzPKAABa-BfEo28672.png](https://file.elecfans.com/web2/M00/67/6F/pYYBAGMTVcKAAzPKAABa-BfEo28672.png)
對比可以發(fā)現(xiàn),簡化的狀態(tài)圖,狀態(tài)可以少一個,不過抖動的狀態(tài),會有更多的輸入和輸出,因為目前每隔狀態(tài)都有經過這個狀態(tài)。
如果對于抖動檢測的要求不高,也可以只保留按下抖動的邏輯,松開抖動的分支去掉,直接跳到松開狀態(tài),可以再次簡化狀態(tài)邏輯。
2.3 代碼
根據(jù)狀態(tài)圖圖,編寫對應的狀態(tài)機邏輯代碼,如下:
void key_status_check()
{
switch(g_keyStatus)
{
//按鍵釋放(初始狀態(tài))
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;
//穩(wěn)定短按
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;
//穩(wěn)定長按
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]);
}
}
注意,在抖動狀態(tài),當檢測為高電平(按鍵松開),不管前一狀態(tài)是短按還是長按,下一狀態(tài)都是松開狀態(tài)。
2.4 測試
![pYYBAGMTVeWADc--AACvIpyovcU938.png](https://file.elecfans.com/web2/M00/67/6F/pYYBAGMTVeWADc--AACvIpyovcU938.png)
3 總結
本篇繼續(xù)介紹狀態(tài)機的使用,在上篇的基礎上,通過簡化按鍵去抖邏輯,并增加按鍵長按功能,進一步介紹狀態(tài)圖的修改與狀態(tài)機代碼的實現(xiàn),并通過實際測試,演示狀態(tài)機的運行效果。
審核編輯 黃昊宇
-
嵌入式
+關注
關注
5092文章
19177瀏覽量
307655 -
STM32
+關注
關注
2272文章
10923瀏覽量
357556 -
狀態(tài)機
+關注
關注
2文章
492瀏覽量
27647
發(fā)布評論請先 登錄
相關推薦
STM32按鍵消抖——入門狀態(tài)機思維
![<b class='flag-5'>STM32</b><b class='flag-5'>按鍵</b>消抖——入門<b class='flag-5'>狀態(tài)機</b>思維](https://file.elecfans.com//web2/M00/66/B8/poYBAGMSCtqAel3uAABuULXEgOM429.png)
STM32按鍵狀態(tài)機3——增加雙擊與功能優(yōu)化
![<b class='flag-5'>STM32</b><b class='flag-5'>按鍵</b><b class='flag-5'>狀態(tài)機</b>3——<b class='flag-5'>增加</b>雙擊與<b class='flag-5'>功能</b>優(yōu)化](https://file.elecfans.com/web2/M00/67/6F/pYYBAGMTVcKAAzPKAABa-BfEo28672.png)
單片機狀態(tài)機按鍵長按和短按實現(xiàn)
基于狀態(tài)機的單片機按鍵短按長按功能的實現(xiàn)
![基于<b class='flag-5'>狀態(tài)機</b>的單片<b class='flag-5'>機</b><b class='flag-5'>按鍵</b>短按<b class='flag-5'>長按</b><b class='flag-5'>功能</b>的實現(xiàn)](https://file1.elecfans.com//web2/M00/A7/1E/wKgZomUMQn2AC-71AABInne3axk814.png)
狀態(tài)機如何簡化PLC程序的編寫
基于STM32F103C8T6的多按鍵檢測 | 有限狀態(tài)機短按、長按識別 | 標準庫函數(shù)實現(xiàn)方法
![基于<b class='flag-5'>STM32</b>F103C8T6的多<b class='flag-5'>按鍵</b>檢測 | 有限<b class='flag-5'>狀態(tài)機</b>短按、<b class='flag-5'>長按</b>識別 | 標準庫函數(shù)實現(xiàn)方法](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
基于STM32按鍵的防抖和松開處理:狀態(tài)機
![基于<b class='flag-5'>STM32</b><b class='flag-5'>按鍵</b>的防抖和松開處理:<b class='flag-5'>狀態(tài)機</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
狀態(tài)模式(狀態(tài)機)
![<b class='flag-5'>狀態(tài)</b>模式(<b class='flag-5'>狀態(tài)機</b>)](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
STM32實現(xiàn)按鍵有限狀態(tài)機(超詳細,易移植)
![<b class='flag-5'>STM32</b>實現(xiàn)<b class='flag-5'>按鍵</b>有限<b class='flag-5'>狀態(tài)機</b>(超詳細,易移植)](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
藍橋杯單片機狀態(tài)機按鍵按下和松開實現(xiàn)不同功能
![藍橋杯單片<b class='flag-5'>機</b><b class='flag-5'>狀態(tài)機</b><b class='flag-5'>按鍵</b>按下和松開實現(xiàn)不同<b class='flag-5'>功能</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
評論