在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

STM32按鍵消抖——入門狀態機思維

碼農愛學習 ? 來源:碼農愛學習 ? 作者:碼農愛學習 ? 2022-09-02 21:54 ? 次閱讀

嵌入式軟件開發中,狀態機編程是一個十分重要的編程思想,它也是嵌入式開發中一個常用的編程框架。掌握了狀態機編程思想,可以更加邏輯清晰的實現復雜的業務邏輯功能。

1 狀態機思想

狀態機,或稱有限狀態機FSM(Finite State Machine),是一種重要的編程思想。

狀態機有3要素:狀態事件響應

狀態:系統處在什么狀態?

事件:發生了什么事?

響應:此狀態下發生了這樣的事,系統要如何處理?

狀態機編程前,首先要根據需要實現的功能,整理出一個對應的狀態轉換圖(狀態機圖),然后就可以根據這個狀態轉換圖,套用狀態機編程模板,實現對應是狀態機代碼了。

狀態機編程主要有 3 種方法:switch-case 法表格驅動法函數指針法,本篇先介紹最簡單也最易理解的switch-case 法

2 狀態機實例

下面以按鍵消抖功能,來介紹switch-case 法的狀態機編程思路。

2.1 按鈕消抖狀態轉換圖

狀態機機編程前,首先要明確的對應功能的狀態機需要幾個狀態,本例的按鍵功能,只檢測最基礎的按下與松開狀態(暫不實現長按、雙擊等狀態),并增加對應的按鈕去抖功能,因此,需要用到4個狀態:

穩定松開狀態

按下抖動狀態

穩定按下狀態

松開抖動狀態

對應的狀態轉換圖如下:

poYBAGMSCi2AVy31AAA8AKcyDe0236.png

由于按鍵通常處于松開狀態,這里讓狀態機的初始化狀態為松開狀態,然后在這4個狀態中來回切換。

圖中的VT代表按鍵檢測到電平,VT=0即檢測到低電平,可能是按鍵按下,由初始的“穩定松開”狀態轉為“按下抖動”狀態

當持續檢測到低電平(VT=0)一段時間后,認為消抖完成,由“按下抖動”狀態轉為“穩定按下”狀態

在“按下抖動”狀態時,在指定的一段時間內,再次檢測到高電平(VT=1),說明確實是按鈕抖動(比如按鍵被快速撥動了一下又彈起,或強烈震動導致的按鍵抖動),則由“按下抖動”狀態轉為“穩定松開”狀態

2.2 編程實現

2.2.1 狀態定義

對應上面的按鈕狀態圖,可以知道需要用到4個狀態:

穩定松開狀態(KS_RELEASE)

按下抖動狀態(KS_PRESS_SHAKE)

穩定按下狀態(KS_PRESS)

松開抖動狀態(KS_RELEASE_SHAKE)

這里使用枚舉來定義這4個狀態。為了在調試時,能夠把對應狀態名稱以字符串的形式打印出來,這里使用宏定義的一個小技巧:

#符號+自定義的枚舉名稱

即可自動轉變為字符串形式,再將這些字符串放到const char* key_status_name[]數組中,便可通過數組的形式訪問這些狀態的字符串名稱形式。

此外,為了不重復書寫枚舉名稱與對應的枚舉字符串(#+枚舉名稱),進一步使用宏定義的方式,只定義一次狀態,然后通過下面兩條宏定義,實現對枚舉項枚舉項對應的字符串的分別獲取:

#define ENUM_ITEM(ITEM) ITEM,

#define ENUM_STRING(ITEM) #ITEM,

具體是宏定義、枚舉定義與枚舉名稱數組聲明如下:

#define ENUM_ITEM(ITEM) ITEM,
#define ENUM_STRING(ITEM) #ITEM,

#define KEY_STATUS_ENUM(STATUS)                   \
	STATUS(KS_RELEASE)       /*穩定松開狀態*/       \
	STATUS(KS_PRESS_SHAKE)   /*按下抖動狀態*/       \
	STATUS(KS_PRESS)         /*穩定按下狀態*/       \
	STATUS(KS_RELEASE_SHAKE) /*松開抖動狀態*/       \
	STATUS(KS_NUM)           /*狀態總數(無效狀態)*/  \
	
typedef enum
{
	KEY_STATUS_ENUM(ENUM_ITEM)
}KEY_STATUS;

const char* key_status_name[] = {
	KEY_STATUS_ENUM(ENUM_STRING)
};

宏定義不便理解的,可以將宏定義分別帶入,轉為最終的結果,理解替代后的具體形式,比如下面的宏定義帶入替換示意:

/*
KEY_STATUS_ENUM(STATUS) --> STATUS(KS_RELEASE) ... STATUS(KS_NUM)

KEY_STATUS_ENUM(ENUM_ITEM)
--> ENUM_ITEM(KS_RELEASE) ... ENUM_ITEM(KS_NUM)
--> KS_RELEASE, ... KS_NUM,

KEY_STATUS_ENUM(ENUM_STRING)
--> ENUM_STRING(KS_RELEASE) ... ENUM_STRING(KS_NUM)
--> #KS_RELEASE, ... #KS_NUM,
*/

2.2.2 狀態機實現

下面是狀態機的具體實現:

狀態機函數key_status_check在一個循環中,被每隔10ms調用一次

定義一個g_keyStatus表示狀態機所處的狀態

在每個循環中,switch根據當前的狀態,執行對應狀態所需要執行的邏輯

定義一個g_DebounceCnt用于消抖時間計算,當持續進入消抖狀態,每次循環(10ms)中將此值加1,持續一定次數(5次,即50ms),認為是穩定的按下或松開,消抖完成,跳轉到穩定方向或穩定松開狀態

在每個狀態的執行邏輯中,當檢測到某些條件滿足時,跳轉到其它的狀態

通過狀態的不斷跳轉,實現狀態機的運行

此外,為方便觀察狀態機中狀態的變化,定義了一個g_lastKeyStatus表示前一狀態,當狀態發生變化時,可以將狀態名稱打印出來

KEY_STATUS g_keyStatus = KS_RELEASE; //當前按鍵的狀態
KEY_STATUS g_lastKeyStatus = KS_NUM; //上一狀態
int g_DebounceCnt = 0; //消抖時間計數

void key_status_check()
{
	switch(g_keyStatus)
	{
		//按鍵釋放(初始狀態)
		case KS_RELEASE:
		{
			//檢測到低電平,先進行消抖
			if (KEY0 == 0)
			{
				g_keyStatus = KS_PRESS_SHAKE;
				g_DebounceCnt = 0;
			}
		}
		break;
		
		//按下抖動
		case KS_PRESS_SHAKE:
		{
			g_DebounceCnt++;
			
			//確實是抖動
			if (KEY0 == 1)
			{
				g_keyStatus = KS_RELEASE;
			}
			//消抖完成
			else if (g_DebounceCnt == 5)
			{
				g_keyStatus = KS_PRESS;
				printf("=====> key press\r\n");
			}
		}
		break;
		
		//穩定按下
		case KS_PRESS:
		{
			//檢測到高電平,先進行消抖
			if (KEY0 == 1)
			{
				g_keyStatus = KS_RELEASE_SHAKE;
				g_DebounceCnt = 0;
			}
		}
		break;
		
		//松開抖動
		case KS_RELEASE_SHAKE:
		{
			g_DebounceCnt++;
			
			//確實是抖動
			if (KEY0 == 0)
			{
				g_keyStatus = KS_PRESS;
			}
			//消抖完成
			else if (g_DebounceCnt == 5)
			{
				g_keyStatus = KS_RELEASE;
				printf("=====> key release\r\n");
			}
		}
		break;
		
		default:break;
	}
	
	if (g_keyStatus != g_lastKeyStatus)
	{
		g_lastKeyStatus = g_keyStatus;
		printf("new key status:%d(%s)\r\n", g_keyStatus, key_status_name[g_keyStatus]);
	}
}

int main(void)
{	
	delay_init();	    //延時函數初始化	  
	KEY_Init();
	uart_init(115200);
	printf("hello\r\n");
	
	while(1)
	{
		key_status_check();
		delay_ms(10);
	}
}

注:本例程需要使用一個按鍵,需要初始化對應的GPIO,這里不再貼代碼。

2.3 使用測試

將完整的代碼編譯后燒錄到板子中,連接串口,按下與松開按鍵,觀察串口輸出信息。

我的測試輸出信息如下:

pYYBAGMSCpeADWb3AACpThu0Gj0100.png

前兩次撥動按鍵模擬按鈕抖動的情況,可以看到串口打印出兩次從松開到按下抖動的狀態切換。

然后是按下按鍵,再松開按鍵,可以看到狀態的變化:松開 -> 按下抖動 -> 按下 -> 松開抖動 -> 松開

3 總結

本篇介紹了嵌入式軟件開發中常用的狀態機編程實現,并通過按鍵消抖實例,以常用的switch-case形式,實現了對應的狀態機編程代碼實現,并通過測試,串口打印對應狀態,分析狀態機的狀態跳轉過程。

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 單片機
    +關注

    關注

    6057

    文章

    44806

    瀏覽量

    644103
  • 嵌入式
    +關注

    關注

    5121

    文章

    19421

    瀏覽量

    312640
  • STM32
    +關注

    關注

    2282

    文章

    10983

    瀏覽量

    360982
  • 狀態機
    +關注

    關注

    2

    文章

    493

    瀏覽量

    27951
收藏 人收藏

    評論

    相關推薦

    STM32按鍵狀態機2——狀態簡化與增加長按功能

    本篇繼續介紹狀態機的使用,在上篇的基礎上,通過簡化按鍵邏輯,并增加按鍵長按功能,進一步介紹狀態圖的修改與
    的頭像 發表于 09-03 21:26 ?4418次閱讀
    <b class='flag-5'>STM32</b><b class='flag-5'>按鍵</b><b class='flag-5'>狀態機</b>2——<b class='flag-5'>狀態</b>簡化與增加長按功能

    【連載視頻教程(八)】小梅哥FPGA設計思想與驗證方法視頻教程之基于狀態機的獨立按鍵

    ,主要通過獨立按鍵這樣一個實驗,來進一步舉例講解狀態機的設計思想,獨立按鍵
    發表于 09-29 14:19

    利用狀態機按鍵程序

    與過程分離. 把和按鍵狀態相關的東西統統塞到結構里, 把的代碼放在一個函數中.//key.h 頭文件
    發表于 02-18 19:58

    怎樣去設計一個基于stm32標準庫獨立按鍵的多按鍵狀態機

    寫在前面??一般引用都寫在最后,但是這篇博文對我這個狀態機的影響很大,我這里有許多借鑒他的思維。所以寫在前面,如有侵權立即刪除簡單按鍵檢測??一開始學習單片的時候我接觸到
    發表于 12-09 07:48

    STM32單片按鍵和FPGA按鍵的相關資料分享

    寫在前面:STM32單片按鍵和FPGA按鍵
    發表于 01-18 06:39

    請問按鍵狀態機的長按和短按測試該怎樣去實現呢

    什么是按鍵呢?按鍵狀態機的長按和短按測試該怎樣去實現呢?
    發表于 01-20 06:45

    如何用狀態機法實現單片矩陣鍵盤的控制

    看了藍橋杯單片的培訓視頻,發現用狀態機法實現矩陣鍵盤時左邊兩列沒有用,這是因為P36、P37口實際是P42、P44口,所以我們在用行列掃描法時會出錯。但習慣了
    發表于 02-17 07:47

    基于FPGA的按鍵電路設計

    采用了VHDL語言編程的設計方法,通過FPGA來實現按鍵的硬件電路。論述了基于計數器、RS觸發器和狀態機3種方法來實現按鍵
    發表于 12-05 14:13 ?224次下載

    利用狀態機按鍵程序

    利用狀態機按鍵程序講解,很好的資料下載吧。
    發表于 01-11 09:32 ?30次下載

    VHDL—按鍵

    達到去抖動的目的。本例中用狀態機實現了電路:端口描述:clk 輸入檢測時鐘;reset 復位信號;din 原始按鍵信號輸入; dout 去抖動輸出信號。
    發表于 11-11 17:17 ?2次下載

    使用狀態機按鍵處理方法電子鐘程序免費下載

    之前的電子鐘程序中,用的按鍵處理方法是10ms的延時,這種方法效率比較低所以現在利用狀態機原理重寫一下,效率很高啊 4個獨立按鍵中用到
    發表于 07-09 17:41 ?8次下載
    使用<b class='flag-5'>狀態機</b>的<b class='flag-5'>按鍵</b><b class='flag-5'>消</b><b class='flag-5'>抖</b>處理方法電子鐘程序免費下載

    使用51單片實現按鍵的資料和程序免費下載

    抖動是機械按鍵存在的現象,是必須要進行處理的。一般處理有兩種方式:一種是硬件,另一種是軟件。硬件
    發表于 07-05 17:41 ?5次下載
    使用51單片<b class='flag-5'>機</b>實現<b class='flag-5'>按鍵</b><b class='flag-5'>消</b><b class='flag-5'>抖</b>的資料和程序免費下載

    基于stm32標準庫獨立按鍵的多按鍵狀態機的實現

    寫在前面??一般引用都寫在最后,但是這篇博文對我這個狀態機的影響很大,我這里有許多借鑒他的思維。所以寫在前面,如有侵權立即刪除簡單按鍵檢測??一開始學習單片的時候我接觸到
    發表于 11-26 13:36 ?25次下載
    基于<b class='flag-5'>stm32</b>標準庫獨立<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 ?8次下載
    基于<b class='flag-5'>STM32</b><b class='flag-5'>按鍵</b>的防<b class='flag-5'>抖</b>和松開處理:<b class='flag-5'>狀態機</b>

    狀態機法實現藍橋杯單片矩陣鍵盤的控制

    看了藍橋杯單片的培訓視頻,發現用狀態機法實現矩陣鍵盤時左邊兩列沒有用,這是因為P36、P37口實際是P42、P44口,所以我們在用行列掃描法時會出錯。但習慣了
    發表于 12-20 19:42 ?6次下載
    用<b class='flag-5'>狀態機</b><b class='flag-5'>消</b><b class='flag-5'>抖</b>法實現藍橋杯單片<b class='flag-5'>機</b>矩陣鍵盤的控制
    主站蜘蛛池模板: 久久午夜视频 | 日本一区二区三区视频在线 | 欧美日韩高清一本大道免费 | 久久久综合视频 | 色综合天天射 | 国产成人午夜片在线观看 | 久久999 | 级毛片| 国产午夜精品视频 | 午夜影视在线免费观看 | 亚洲国产成人久久精品图片 | 天天玩夜夜操 | 天堂网站| 美女扒开尿口让男人捅 | 生活片一级性 | 老色批视频| 久久看精品| 亚洲黄色小视频 | 5555kkkk香蕉在线观看 | 午夜免费理论片在线看 | 欧美性野久久久久久久久 | 婷婷 色天使 | 中文字幕在线第一页 | 午夜免费福利影院 | 起碰免费视频 | japanese色系国产在线高清 | www.狠狠操.com | 国产免费好大好硬视频 | 亚洲一区在线播放 | 免费人成在线观看网站品爱网日本 | 日日艹 | 美女性爽视频国产免费 | 色伊人久久| 四虎884tt紧急大通知 | 夜夜摸天天操 | bt天堂网在线www资源 | 最刺激黄a大片免费网站 | 高清午夜线观看免费 | 特级一级全黄毛片免费 | h版欧美一区二区三区四区 h网站亚洲 | 欧美黄又粗暴一进一出抽搐 |