99精品伊人亚洲|最近国产中文炮友|九草在线视频支援|AV网站大全最新|美女黄片免费观看|国产精品资源视频|精彩无码视频一区|91大神在线后入|伊人终合在线播放|久草综合久久中文

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

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

3天內不再提示

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

碼農(nóng)愛學習 ? 來源:碼農(nóng)愛學習 ? 作者:碼農(nóng)愛學習 ? 2022-09-04 17:05 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

上篇文章,介紹了將按鍵檢測增加長按功能,并將按下抖動與松開抖動共用一個抖動狀態(tài)來表示,其狀態(tài)圖如下:

pYYBAGMTVcKAAzPKAABa-BfEo28672.png

仔細研究這個狀態(tài)圖,其它還存在一些問題:

短按狀態(tài),只要按下去,不需要等按鍵再釋放,就會觸發(fā)短按事件。對于需要按下再松開作為一次短按的應用來說,此狀態(tài)圖也不滿足需求

長按狀態(tài),必須先經(jīng)過短按狀態(tài),即長按按鍵,會先觸發(fā)一個短按,再觸發(fā)一個長按。如果實際應用中需要分別使用短按和長按,則此狀態(tài)圖不滿足要求

本篇,就來解決上述兩個問題,并再增加一個按鍵雙擊檢測,實現(xiàn)一個功能更全面的按鍵檢測。

1 增加雙擊檢測

增加一個雙擊檢測,需要增加兩個狀態(tài):

等待再次按下

確認第2次按下

同時,之前的“短按狀態(tài)”和“長按狀態(tài)”分別改為“確認按下”和“確認長按”。

1.1 狀態(tài)圖修改

修改后的狀態(tài)圖如下,有以下幾點需要注意:

確認按下”不是短按觸發(fā)的條件,需要等松開后,經(jīng)消抖進入到“等待再次按下”一段時間后(200ms),沒有再次被按下,才觸發(fā)短按事件,這樣就解決了本篇開頭提到的第1個問題

確認按下”不是短按觸發(fā)的條件,另一個用途是,當此狀態(tài)繼續(xù)保持按下狀態(tài)一段時間后(1s),則會單獨觸發(fā)長按事件,同時進入到“確認長按”狀態(tài),這樣就解決了本篇開頭提到的第2個問題

對于雙擊事件的檢測,首先按下按鍵進入“確認按下”狀態(tài),然后在1s內松開進入“等待再次按下”狀態(tài),接著在200ms內再次按下進入“確認第2次按下”狀態(tài),然后在1s內松開,即可觸發(fā)雙擊事件,并同時進入“穩(wěn)定松開”狀態(tài)

注意,在“確認第2次按下”狀態(tài)下,如果在1s內沒有松開,也會進入到“確認長按”狀態(tài)

poYBAGMUaY-AEN6DAACzMOOUn5E684.png

1.2 程序編寫

根據(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) 
			{
				//從松開狀態(tài)來的抖動
				if (KS_RELEASE == g_lastKeyStatus)
				{
					g_keyStatus = KS_RELEASE;
				}
				//從等待再次按下狀態(tài)來的抖動
				else if (KS_WAIT_PRESS_AGAIN == g_lastKeyStatus)
				{
					g_keyStatus = KS_WAIT_PRESS_AGAIN;
				}
				//從確認按下狀態(tài)來
				else if (KS_AFFIRM_SHORT_PRESS == g_lastKeyStatus)
				{
					g_WaitPressAgainCnt = 0;
					g_keyStatus = KS_WAIT_PRESS_AGAIN;
				}
				//從確認再次按下狀態(tài)來
				else if (KS_AFFIRM_PRESS_AGAIN == g_lastKeyStatus)
				{
					printf("=====> key double press\r\n");
					g_keyStatus = KS_RELEASE;
				}
				//從確認長按狀態(tài)來
				else if (KS_AFFIRM_LONG_PRESS == g_lastKeyStatus)
				{
					g_keyStatus = KS_RELEASE;
				}
				else
				{
					printf("err!\r\n");
				}
			}
			else
			{
				//從確認按下狀態(tài)來的抖動
				if (KS_AFFIRM_SHORT_PRESS == g_lastKeyStatus)
				{
					g_keyStatus = KS_AFFIRM_SHORT_PRESS;
				}
		        //從第2次按下狀態(tài)來的抖動
				else if (KS_AFFIRM_PRESS_AGAIN == g_lastKeyStatus)
				{
					g_keyStatus = KS_AFFIRM_PRESS_AGAIN;
				}
				//從確認長按狀態(tài)來的抖動
				else if (KS_AFFIRM_LONG_PRESS == g_lastKeyStatus)
				{
					g_keyStatus = KS_AFFIRM_LONG_PRESS;
				}
				//從松開狀態(tài)而來
				else if (KS_RELEASE == g_lastKeyStatus)
				{
					g_PressTimeCnt = 0;
					g_keyStatus = KS_AFFIRM_SHORT_PRESS;
					//printf("=====> key short press\r\n");
				}
				//從等待再次看下(的松開)狀態(tài)而來
				else if (KS_WAIT_PRESS_AGAIN == g_lastKeyStatus)
				{
					g_Press2TimeCnt = 0;
					g_keyStatus = KS_AFFIRM_PRESS_AGAIN;
				}
				else
				{
					printf("err!\r\n");
				}
			}
		}
		break;
		
		//確認按下
		case KS_AFFIRM_SHORT_PRESS:
		{
			//檢測到高電平,先進行消抖
			if (KEY0 == 1)
			{
				g_keyStatus = KS_SHAKE;
			}
			else
			{
				if (g_LongPressTimeCnt % 20 == 0) //每隔1000ms打印一次
				{
					printf("=====> key long press:%d\r\n", g_LongPressTimeCnt/20);
					
					keyEvent = KE_LONG_PRESS;
				}
				g_LongPressTimeCnt++;
			}
		}
		break;
		
		//等待再次按下
		case KS_WAIT_PRESS_AGAIN:
		{
			//檢測到低電平,先進行消抖
			if (KEY0 == 0)
			{
				g_keyStatus = KS_SHAKE;
			}
			
			g_WaitPressAgainCnt++;
			if (g_WaitPressAgainCnt == 4) //200ms沒有再次按下
			{
				printf("=====> key single press\r\n");
				g_keyStatus = KS_RELEASE;
			}
		}
		break;
		
		//確認第2次按下
		case KS_AFFIRM_PRESS_AGAIN:
		{
			//檢測到高電平,先進行消抖
			if (KEY0 == 1)
			{
				g_keyStatus = KS_SHAKE;
			}
			
			g_Press2TimeCnt++;
			if (g_Press2TimeCnt == 20) //1000ms
			{
				g_LongPressTimeCnt = 0;
				g_keyStatus = KS_AFFIRM_LONG_PRESS;
			}
		}
		break;
		
	    //確認長按
		case KS_AFFIRM_LONG_PRESS:
		{
			//檢測到高電平,先進行消抖
			if (KEY0 == 1)
			{
				g_keyStatus = KS_SHAKE;
			}
			
			g_LongPressTimeCnt++;
			if (g_LongPressTimeCnt % 20 == 0) //每隔1000ms打印一次
			{
				printf("=====> key long press:%d\r\n", g_LongPressTimeCnt/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)變化

1.3 測試

短按、長按、雙擊的測試結果如下:

poYBAGMUaeGAAoP2AAEtu7uP7lU210.png

還有從確認第2次按下狀態(tài)到達的長按狀態(tài):

pYYBAGMUaeeANCNHAAByVtpyQgE552.png

2 功能優(yōu)化

上面的代碼實現(xiàn),是在主函數(shù)中,每50ms延時執(zhí)行一次狀態(tài)機循環(huán)(主函數(shù)代碼如下),僅用做演示按鍵狀態(tài)機的運行機制。

int main(void)
{	
	delay_init();
	KEY_Init();
	uart_init(115200);

	printf("hello\r\n");
	
	while(1)
	{
		key_status_check();
		delay_ms(50);
	}
}

實際開發(fā)中,按鍵檢測程序,應該作為一個獨立的模塊運行,當檢測到某一按鍵狀態(tài)觸發(fā)時,通知應用程序來使用。

對于stm32裸機開發(fā)來說,可以將按鍵狀態(tài)機放到一個定時器中斷服務函數(shù)中運行,當檢測到某一按鍵狀態(tài)觸發(fā)后,通知應用程序:

//主函數(shù)
int main(void)
{	
	delay_init();
	KEY_Init();
	uart_init(115200);
	TIM3_Int_Init(500-1,7200-1); //調用定時器使得50ms產(chǎn)生一個中斷

	printf("hello\r\n");
	
	while(1)
	{
	}
}

//定時器3中斷服務程序
void TIM3_IRQHandler(void)   //TIM3中斷
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //檢查TIM3更新中斷發(fā)生與否
	{
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx更新中斷標志 
		
		KEY_EVENT keyEvent = key_status_check();
		switch (keyEvent)
		{
			case KE_SHORT_PRESS:  printf("檢測到單擊\r\n"); break;
			case KE_DOUBLE_PRESS: printf("檢測到雙擊\r\n"); break;
			case KE_LONG_PRESS:   printf("檢測到長按\r\n"); break;
			default:break;
		}
	}
}

3 總結

本篇在前兩篇按鍵狀態(tài)機的基礎上,繼續(xù)介紹增加按鍵的雙擊功能,并解決之前狀態(tài)存在的兩個問題,通過實測驗證,演示短按、長按、雙擊的使用效果。最后對代碼結構進行優(yōu)化,使其更符合實際開發(fā)應用。

審核編輯 黃昊宇

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

    關注

    6067

    文章

    44992

    瀏覽量

    650648
  • 嵌入式
    +關注

    關注

    5152

    文章

    19676

    瀏覽量

    317700
  • STM32
    +關注

    關注

    2293

    文章

    11032

    瀏覽量

    365124
  • 狀態(tài)機
    +關注

    關注

    2

    文章

    493

    瀏覽量

    28258
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    STM32按鍵消抖——入門狀態(tài)機思維

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

    STM32按鍵狀態(tài)機2——狀態(tài)簡化與增加長按功能

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

    單片狀態(tài)機按鍵長按和短按實現(xiàn)

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

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

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

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

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

    基于狀態(tài)機的單片按鍵短按長按功能的實現(xiàn)

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

    FPGA:狀態(tài)機簡述

    本文目錄 前言 狀態(tài)機簡介 狀態(tài)機分類 Mealy 型狀態(tài)機 Moore 型狀態(tài)機 狀態(tài)機描述 一段式
    的頭像 發(fā)表于 11-05 17:58 ?8060次閱讀
    FPGA:<b class='flag-5'>狀態(tài)機</b>簡述

    使用Synplify設計安全的VHDL狀態(tài)機

    Synplify的優(yōu)勢之一是有限狀態(tài)機編譯器。 這是一個強大的功能,不僅具有自動檢測狀態(tài)機中的狀態(tài)的能力源代碼,并使用順序編碼,灰色編碼或一鍵編碼實現(xiàn)它們。但也要進行可達性分析,以確定
    發(fā)表于 04-07 09:20 ?12次下載
    使用Synplify設計安全的VHDL<b class='flag-5'>狀態(tài)機</b>

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

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

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

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

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

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

    藍橋杯單片狀態(tài)機按鍵按下和松開實現(xiàn)不同功能

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

    STM32狀態(tài)機編程實例——全自動洗衣(上)

    本篇實現(xiàn)了一款全自動洗衣的基礎洗衣控制流程,可實現(xiàn)不同水位與清洗次數(shù)的設置,以及任務的暫停與繼續(xù)。此外,通過對之前按鍵狀態(tài)機的進一步優(yōu)化修改,實現(xiàn)了
    的頭像 發(fā)表于 09-06 08:47 ?3684次閱讀
    <b class='flag-5'>STM32</b><b class='flag-5'>狀態(tài)機</b>編程實例——全自動洗衣<b class='flag-5'>機</b>(上)

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

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

    什么是狀態(tài)機?狀態(tài)機的種類與實現(xiàn)

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