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

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

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

3天內不再提示

STM32按鍵狀態機3——增加雙擊與功能優化

碼農愛學習 ? 來源:碼農愛學習 ? 作者:碼農愛學習 ? 2022-09-04 17:05 ? 次閱讀

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

pYYBAGMTVcKAAzPKAABa-BfEo28672.png

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

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

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

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

1 增加雙擊檢測

增加一個雙擊檢測,需要增加兩個狀態:

等待再次按下

確認第2次按下

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

1.1 狀態圖修改

修改后的狀態圖如下,有以下幾點需要注意:

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

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

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

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

poYBAGMUaY-AEN6DAACzMOOUn5E684.png

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) 
			{
				//從松開狀態來的抖動
				if (KS_RELEASE == g_lastKeyStatus)
				{
					g_keyStatus = KS_RELEASE;
				}
				//從等待再次按下狀態來的抖動
				else if (KS_WAIT_PRESS_AGAIN == g_lastKeyStatus)
				{
					g_keyStatus = KS_WAIT_PRESS_AGAIN;
				}
				//從確認按下狀態來
				else if (KS_AFFIRM_SHORT_PRESS == g_lastKeyStatus)
				{
					g_WaitPressAgainCnt = 0;
					g_keyStatus = KS_WAIT_PRESS_AGAIN;
				}
				//從確認再次按下狀態來
				else if (KS_AFFIRM_PRESS_AGAIN == g_lastKeyStatus)
				{
					printf("=====> key double press\r\n");
					g_keyStatus = KS_RELEASE;
				}
				//從確認長按狀態來
				else if (KS_AFFIRM_LONG_PRESS == g_lastKeyStatus)
				{
					g_keyStatus = KS_RELEASE;
				}
				else
				{
					printf("err!\r\n");
				}
			}
			else
			{
				//從確認按下狀態來的抖動
				if (KS_AFFIRM_SHORT_PRESS == g_lastKeyStatus)
				{
					g_keyStatus = KS_AFFIRM_SHORT_PRESS;
				}
		        //從第2次按下狀態來的抖動
				else if (KS_AFFIRM_PRESS_AGAIN == g_lastKeyStatus)
				{
					g_keyStatus = KS_AFFIRM_PRESS_AGAIN;
				}
				//從確認長按狀態來的抖動
				else if (KS_AFFIRM_LONG_PRESS == g_lastKeyStatus)
				{
					g_keyStatus = KS_AFFIRM_LONG_PRESS;
				}
				//從松開狀態而來
				else if (KS_RELEASE == g_lastKeyStatus)
				{
					g_PressTimeCnt = 0;
					g_keyStatus = KS_AFFIRM_SHORT_PRESS;
					//printf("=====> key short press\r\n");
				}
				//從等待再次看下(的松開)狀態而來
				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]);
	}
}

最后注釋掉的一句是調試打印,調試時可打開,方便觀察狀態變化

1.3 測試

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

poYBAGMUaeGAAoP2AAEtu7uP7lU210.png

還有從確認第2次按下狀態到達的長按狀態:

pYYBAGMUaeeANCNHAAByVtpyQgE552.png

2 功能優化

上面的代碼實現,是在主函數中,每50ms延時執行一次狀態機循環(主函數代碼如下),僅用做演示按鍵狀態機的運行機制。

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

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

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

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

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

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

//定時器3中斷服務程序
void TIM3_IRQHandler(void)   //TIM3中斷
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)  //檢查TIM3更新中斷發生與否
	{
		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 總結

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

審核編輯 黃昊宇

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

    關注

    6040

    文章

    44605

    瀏覽量

    637209
  • 嵌入式
    +關注

    關注

    5089

    文章

    19161

    瀏覽量

    306661
  • STM32
    +關注

    關注

    2270

    文章

    10918

    瀏覽量

    356890
  • 狀態機
    +關注

    關注

    2

    文章

    492

    瀏覽量

    27607
收藏 人收藏

    評論

    相關推薦

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

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

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

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

    單片狀態機按鍵長按和短按實現

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

    利用狀態機按鍵消抖程序

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

    狀態機原理及用法

    狀態機原理及用法狀態機原理及用法狀態機原理及用法
    發表于 03-15 15:25 ?0次下載

    基于狀態機的單片按鍵短按長按功能的實現

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

    FPGA:狀態機簡述

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

    使用Synplify設計安全的VHDL狀態機

    Synplify的優勢之一是有限狀態機編譯器。 這是一個強大的功能,不僅具有自動檢測狀態機中的狀態的能力源代碼,并使用順序編碼,灰色編碼或一鍵編碼實現它們。但也要進行可達性分析,以確定
    發表于 04-07 09:20 ?12次下載
    使用Synplify設計安全的VHDL<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>

    狀態模式(狀態機)

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

    STM32實現按鍵有限狀態機(超詳細,易移植)

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

    藍橋杯單片狀態機按鍵按下和松開實現不同功能

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

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

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

    按鍵狀態機代碼

    自己寫的按鍵狀態機,需要的時候根據情況修改一下
    發表于 03-27 10:42 ?8次下載

    什么是狀態機狀態機的種類與實現

    狀態機,又稱有限狀態機(Finite State Machine,FSM)或米利狀態機(Mealy Machine),是一種描述系統狀態變化的模型。在芯片設計中,
    的頭像 發表于 10-19 10:27 ?9887次閱讀
    主站蜘蛛池模板: 午夜啪| 人与牲动交bbbbxxxx| 日本特黄绿像大片免费看| 国模福利| 久久青青成人亚洲精品| 色久月| 538porm在线看国产亚洲| 天堂在线视频| 小雪被老外黑人撑破了| 成年人在线网站| 黄色毛片免费| 老色鬼久久综合第一| 日本黄视频网站| 色福利网| 深夜释放自己vlog糖心旧版本 | 久草热线视频| 男人的天堂视频在线| 青草91| 欧美xxxxx精品| 日本一道dvd在线中文字幕| 日本黄色高清视频| 黄色香蕉网| 第九色| 一级特黄aaaaaa大片| 一级片视频在线观看| 男女一级特黄a大片| 久久天天躁狠狠躁夜夜躁| 免费看曰批女人爽的视频网址| 国产精品福利久久| 2018天天干夜夜操| 免费性网站| 99久久久久国产精品免费| 不卡视频免费在线观看| 天天摸天天碰色综合网| 四虎免费影院4hu永久免费| 六九视频在线观看| 亚洲天天做日日做天天欢毛片| 国产理论视频| 久久性生活| 亚洲高清免费在线观看| 五月婷婷伊人网|