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

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

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

3天內不再提示

單片機短按、長按實現方法

strongerHuang ? 來源:TopSemic嵌入式 ? 2023-06-08 16:43 ? 次閱讀

電子產品中經常用到按鍵,尤其是經常需要MCU判斷短按長按這兩種動作,本篇我們來專門聊下這個話題

只談理論太無聊,我們還是結合著實際應用來說明。之前寫過一篇關于《CH573第一篇:實現自拍桿藍牙遙控器1》的文章,例子默認的功能是藍牙連接后不斷的發送數據,從而不斷的拍照。而實際中的遙控器通常是按一次按鍵,控制一次,我們在來實現該功能。

16063702-05d8-11ee-962d-dac502259ad0.png

板子上只有兩個按鍵,一個是RESET按鍵,一個是DOWNLOAD按鍵,我們使用DOWNLAOD按鍵,按鍵的一端接GND,另外一端接CH573的PB22引腳。

161f458a-05d8-11ee-962d-dac502259ad0.png

原理圖中有一個NC的C5,但是實際板子上我卻沒有找到它,可能是版本不一致。

提前說明一下:CH573的代碼里跑了TMOS(Task Management Operating System),可以理解為一個簡單的操作系統,所以下面的代碼一般的裸機代碼看著略有不同,不過核心思想都是一樣的,用在其他地方也很容易移植,只需要將其中的定時器部分改寫即可。

最初我是這么做的,把PB22配置為上拉輸入,開啟下降沿中斷,在中斷服務函數里,啟動一個事件,執行藍牙發送。代碼如下:

voidKey_Init()
{
GPIOB_ModeCfg(GPIO_Pin_22,GPIO_ModeIN_PU);
GPIOB_ITModeCfg(GPIO_Pin_22,GPIO_ITMode_FallEdge);
PFIC_EnableIRQ(GPIO_B_IRQn);
}
voidGPIOB_IRQHandler(void)
{
if(GPIOB_ReadPortPin(GPIO_Pin_22)==0)
{
GPIOB_ClearITFlagBit(GPIO_Pin_22);
tmos_set_event(hidEmuTaskId,START_REPORT_EVT);
}
}

這么寫能工作,但是有問題,就是經常會出現按一下誤判為多次按下。原因大家應該都清楚,因為按鍵存在抖動,所以一次按下有可能進入多次進入中斷。

理想中的按下-彈起波形是這樣的:

162958e0-05d8-11ee-962d-dac502259ad0.png

但是實際由于按鍵抖動的存在,實際的波形可能是這樣的:

1638a066-05d8-11ee-962d-dac502259ad0.png

不信的話你可以接上示波器看看,或者軟件驗證,比如在GPIO中斷服務函數里,設置一個全局變量,讓它每次進入中斷后加1,按按鍵觀察這個變量的值。

那么該如何消除抖動呢?一種方法是硬件消抖,即按鍵兩端并聯一個小電容(電容大小由按鍵的機械特性來決定),另外一種方法是我們今天要重點介紹的軟件消抖。

方法一:常用的加延時函數

在中斷服務函數中加一個比如10ms的延時函數,延時時間的長短取決于實際所用的按鍵特性,只要延時時間比抖動時間略大即可。原理很簡單,加了延時就避開了抖動的這段時間,在延時之后判斷引腳電平,如果為低電平就表示是按下。

voidGPIOB_IRQHandler(void)
{
if(GPIOB_ReadPortPin(GPIO_Pin_22)==0)
{
mDelaymS(10);
if(GPIOB_ReadPortPin(GPIO_Pin_22)==0)
tmos_set_event(hidEmuTaskId,START_REPORT_EVT);
GPIOB_ClearITFlagBit(GPIO_Pin_22);
}
}

這個方法很簡單,但是不好的地方是延時占用MCU資源。尤其是這里的BLE應用,在中斷服務函數中執行時間長會引起藍牙連接中斷,所以這里不能這么用,我實際測試當按鍵按快一點就很容易引起藍牙連接中斷。

方法二:加定時器

它的原理和方法一類似,只不過是不在中斷服務函數中阻塞等待,而是用一個定時器,代碼如下:

voidGPIOB_IRQHandler(void)
{
if(GPIOB_ReadPortPin(GPIO_Pin_22)==0)
{
GPIOB_ClearITFlagBit(GPIO_Pin_22);

tmos_stop_task(hidEmuTaskId,START_DEBOUNCE_EVT);
tmos_start_task(hidEmuTaskId,START_DEBOUNCE_EVT,16);
}
}
if(events&START_DEBOUNCE_EVT)
{
if(GPIOB_ReadPortPin(GPIO_Pin_22)==0)
{
PRINT("shortpress
");
tmos_set_event(hidEmuTaskId,START_REPORT_EVT);
}

return(events^START_DEBOUNCE_EVT);
}

它的邏輯是每次抖動的下降沿重新開啟10ms定時器,在定時器時間到之后判斷IO電平狀態來判斷按鍵是否按下。

需要注意的是:10ms定時器不是一個周期性的定時器,它是一次性的,即時間到了之后就停止計時了。另外每次進中斷后先讓定時器重新重頭開始計時。如果大家用其他代碼實現時要注意這兩點。

此方法的好處不像加延時函數那樣占用MCU資源。我實際測試這個方法可用,不會引起藍牙連接中斷。

以上介紹了使用中斷的方式來判斷按鍵短按,可以看到它判斷的依據是按鍵按下(由高電平變到低電平)這個狀態。下面在方法二的基礎上我們來實現長按的檢測,判斷長按的依據是按下后持續的維持一段時間低電平。代碼如下:

if(events&START_DEBOUNCE_EVT)
{
if(GPIOB_ReadPortPin(GPIO_Pin_22)==0)
{
PRINT("shortpress
");
tmos_set_event(hidEmuTaskId,START_REPORT_EVT);
tmos_start_task(hidEmuTaskId,START_LONGCHECK_TIMER,16);
}

return(events^START_DEBOUNCE_EVT);
}
if(events&START_LONGCHECK_TIMER)
{
staticintcnt=0;
if(GPIOB_ReadPortPin(GPIO_Pin_22)==0)
{
cnt++;
if(cnt>100)
{
PRINT("longpress
");
tmos_stop_task(hidEmuTaskId,START_LONGCHECK_TIMER);
cnt=0;
}
else
tmos_start_task(hidEmuTaskId,START_LONGCHECK_TIMER,16);
}
else
{
cnt=0;
tmos_stop_task(hidEmuTaskId,START_LONGCHECK_TIMER);
}

return(events^START_LONGCHECK_TIMER);
}

實現的邏輯是:當檢測到短按時,再開啟一個10ms定時器,在定時器到時之中判斷電平狀態,如果為低電平,就讓cnt變量加1,否則cnt=0,當cnt>100,即低電平持續1s認為是長按。我在這里當判斷到長按之后或者IO變高之后會停止掉這個定時器,否則周期定時,因為沒必要一直開著定時器。

除了上述的中斷方式,還可以使用輪詢的方式來實現,代碼如下:

voidKey_Init()
{
GPIOB_ModeCfg(GPIO_Pin_22,GPIO_ModeIN_PU);
}
if(events&START_KEYSCAN_EVT)
{
KeyScan();
tmos_start_task(hidEmuTaskId,START_KEYSCAN_EVT,160);//100ms執行一次KeyScan()
return(events^START_KEYSCAN_EVT);
}
boolkey_press_flag=false;//按下標志
boolkey_long_press_flag=false;//長按標志

voidKeyScan()
{
if(GPIOB_ReadPortPin(GPIO_Pin_22)==0)//低電平
{
if(key_press_flag==false)
tmos_start_task(hidEmuTaskId,START_LONGCHECK_TIMER,1600);//啟動1s定時器

key_press_flag=true;//置位按下標志
}
elseif(key_press_flag==true)//高電平同時按鍵被按下過,表示是按下后的彈起
{
key_press_flag=false;//清除按下標志

if(key_long_press_flag==false)//短按后的彈起
{
tmos_stop_task(hidEmuTaskId,START_LONGCHECK_TIMER);
PRINT("shortpress
");
tmos_set_event(hidEmuTaskId,START_REPORT_EVT);
}
else//長按后的彈起
{
key_long_press_flag=false;
}
}
else
{
key_press_flag=false;
key_long_press_flag=false;
}

}
if(events&START_LONGCHECK_TIMER)
{
key_long_press_flag=true;
PRINT("longpress
");
return(events^START_LONGCHECK_TIMER);
}

上面的這段代碼初次看著有點繞,但是看明白了之后會覺得這個實現邏輯還是挺好的,注釋寫了,這里不再詳細解釋了,我在多個項目里使用的都是它。它兼顧了去抖和短按/長按的檢測,并且長按可以判斷出長按按下/長按彈起。短按是檢測到彈起時認為是短按動作。另外如果想同時支持多個長按,也很方便添加。

輪詢和中斷各有優缺點,大家可以根據實際情況來選擇,你一般常用哪種方式呢?


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

    關注

    6037

    文章

    44562

    瀏覽量

    635753
  • 操作系統
    +關注

    關注

    37

    文章

    6836

    瀏覽量

    123361
  • 定時器
    +關注

    關注

    23

    文章

    3250

    瀏覽量

    114897

原文標題:單片機短按、長按實現方法

文章出處:【微信號:strongerHuang,微信公眾號:strongerHuang】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    求助:單片機一鍵長按短按按鍵實現的c程序有問題

    單片機一鍵長按短按按鍵實現的c程序有問題,實在不知道是哪里有問題,請幫助修改一下,謝謝!功能如下:長按2秒燈全亮(我用的開發板),
    發表于 06-03 16:55

    求助!如何使飛思卡爾s128單片機鍵盤長按短按出現不同的...

    如何使s128單片機鍵盤長按短按出現不同的現象(反應),就是該怎么改變程序
    發表于 11-25 18:57

    單片機如何區別按鍵長按短按

      單片機工程師在面試的過程中,經常會碰到一些相同的問題,筆者總結了十個提問率較高的問題,供大家參考。現在我們來分析單片機工程師常遇面試問題之二:單片機如何區別按鍵長按
    發表于 01-14 16:59

    如何通過外部中斷實現按鍵的長按短按

    瑞薩單片機通過外部中斷實現按鍵的長按短按
    發表于 12-01 07:57

    stm32按鍵的長按/短按怎么實現

    stm32按鍵的長按/短按怎么實現
    發表于 12-02 07:41

    實現單片機按鍵長按短按功能的方法

    寫在前面?一般我們在寫單片機程序的時候都要用到按鍵,在按鍵較少的情況下我們需要一個按鍵可以返回不同的按下結果,也就是長按短按。程序實現?大致思路是按鍵按下時打開定時器,按鍵松開時關閉
    發表于 12-06 07:40

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

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

    按鍵長按短按效果

    按鍵長按短按效果 C51單片機源碼,KEIL源文件,C語言編寫
    發表于 06-20 16:15 ?64次下載

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

    本文主要介紹了基于狀態單片機按鍵短按長按功能的實現,按鍵的擊鍵過程也是一種狀態的切換,也可以看著是一個狀態
    發表于 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>功能的<b class='flag-5'>實現</b>

    單片機按鍵進行長按短按的流程分析和程序代碼免費下載

    在寫單片機程序的過程中,難免會遇到按鍵的寫法,比如一個按鍵實現長按短按。本文只針對這些操作說明一下自己按鍵的思想。可應用到實際工程中。按鍵處理過程:設置一個按鍵標志,按下時為1,松開
    發表于 09-19 17:20 ?9次下載
    <b class='flag-5'>單片機</b>按鍵進行<b class='flag-5'>長按</b>和<b class='flag-5'>短按</b>的流程分析和程序代碼免費下載

    使用單片機實現按鍵長按短按效果的C語言程序免費下載

    本文檔的主要內容詳細介紹的是使用單片機實現按鍵長按短按效果的C語言程序免費下載。
    發表于 11-26 17:31 ?56次下載

    瑞薩單片機之外部中斷實現按鍵的長按短按(二)

    瑞薩單片機通過外部中斷實現按鍵的長按短按
    發表于 11-22 14:21 ?20次下載
    瑞薩<b class='flag-5'>單片機</b>之外部中斷<b class='flag-5'>實現</b>按鍵的<b class='flag-5'>長按</b>與<b class='flag-5'>短按</b>(二)

    如何實現單片機按鍵長按短按功能

    寫在前面?一般我們在寫單片機程序的時候都要用到按鍵,在按鍵較少的情況下我們需要一個按鍵可以返回不同的按下結果,也就是長按短按。程序實現?大致思路是按鍵按下時打開定時器,按鍵松開時關閉
    發表于 11-23 18:06 ?39次下載
    如何<b class='flag-5'>實現</b><b class='flag-5'>單片機</b>按鍵<b class='flag-5'>長按</b>和<b class='flag-5'>短按</b>功能

    如何區分按鈕的短按長按

    怎樣區分按鈕的短按(按下后松開)與長按(按下并保持一段時間)。說實話,在工業現場,按鈕長按實現某個功能使用的并不多。
    的頭像 發表于 02-07 13:53 ?3728次閱讀
    如何區分按鈕的<b class='flag-5'>短按</b>與<b class='flag-5'>長按</b>?

    基于89C51單片機的按鍵長按短按效果源程序

    基于89C51單片機的按鍵長按短按效果源程序
    發表于 05-16 09:45 ?18次下載
    主站蜘蛛池模板: 亚洲 欧美 另类 综合 日韩| 欧美网站免费| 国内一区二区| 美女扒开尿口给男人捅| 国内精品一区二区在线观看| 美女18黄| 精品综合久久88色鬼首页| 四虎最新永久在线精品免费| 网www天堂资源在线| 老师我好爽再深一点好大| 亚洲免费毛片| 9久热久re爱免费精品视频| 伊人久久大香线蕉综合高清| 亚欧精品一区二区三区| 美女扒开尿口让男生添 漫画| 一级毛片一级黄片| 色福利视频| 美女黄页免费| 成年网站在线播放| 天天看天天摸色天天综合网| 狠狠插狠狠插| 在线成人精品国产区免费| 性欧美激情在线观看| 黄视频日本| 国产h在线观看| 在线毛片网| 日本特级黄色大片| 四虎国产精品永免费| 欧美爽爽网| 成人精品一区二区不卡视频| 国产美女免费观看| 午夜免费毛片| 天天干天天操天天射| 国产aa| 亚洲欧美日本视频| 亚洲韩国在线一卡二卡| 欧美人与禽交| 97色资源| jinv在线视频| tom影院亚洲国产一区二区| 四虎三级|