色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

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 總結

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

審核編輯 黃昊宇

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

    關注

    6035

    文章

    44554

    瀏覽量

    634650
  • 嵌入式
    +關注

    關注

    5082

    文章

    19104

    瀏覽量

    304810
  • STM32
    +關注

    關注

    2270

    文章

    10895

    瀏覽量

    355740
  • 狀態機
    +關注

    關注

    2

    文章

    492

    瀏覽量

    27529
收藏 人收藏

    評論

    相關推薦

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

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

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

    本篇繼續介紹狀態機的使用,在上篇的基礎上,通過簡化按鍵去抖邏輯,并增加按鍵長按功能,進一步介紹狀態圖的修改與
    的頭像 發表于 09-03 21:26 ?4101次閱讀
    <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 ?1.9w次閱讀
    基于<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 ?7374次閱讀
    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 ?2726次閱讀
    <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 ?9451次閱讀
    主站蜘蛛池模板: 国产Av男人的天堂精品良久| 巨污全肉np一女多男| 欧美日韩精品不卡在线观看| 亚洲国产日韩制服在线观看 | xart欧美一区在线播放| 精品久久久久久电影网| 深夜释放自己在线观看| 99热这里只有精品9| 久久成人免费大片| 性生生活大片又黄又| 草草久久久无码国产专区全集观看| 久久精品综合电影| 性派对xxxhd| 国产成人高清视频| 欧美精品成人久久网站| 在线观看免费精品国产| 国产亚洲人成网站在线观看播放 | 无码任你躁久久久久久久| TUBE8最新日本护士| 美女逼逼毛茸茸| 一个人在线观看免费视频| 国产三级在线观看视频| 日日射夜夜干夜夜插在线播放| 99久久国产宗和精品1上映| 久久精品亚洲| 妖精视频免费高清观看| 国产亚洲精品久久7777777| 无码国产成人777爽死在线观看| mm625亚洲人成电影网| 男女夜晚在爽视频免费观看| 中文字幕爆乳JULIA女教师| 精品久久中文字幕有码| 亚洲精品色婷婷在线蜜芽| 国产欧美一区二区精品仙草咪| 入禽太深视频免费视频| 草莓视频cm.888tw| 强伦姧久久久久久久久久| 99在线观看免费| 欧美精品3atv一区二区三区| 99re2.久久热最新地址| 免费光看午夜请高视频|