按鍵處理的幾種方法_第1頁
按鍵處理的幾種方法_第2頁
按鍵處理的幾種方法_第3頁
按鍵處理的幾種方法_第4頁
按鍵處理的幾種方法_第5頁
已閱讀5頁,還剩11頁未讀, 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

1、新型的按鍵掃描程序核心算法:unsigned char Trg;unsigned char Release;unsigned char Cont;void KeyRead( void ) unsigned char ReadData = PINB0xff; / 1 讀鍵值Trg = ReadData & (ReadData Cont); / 2 得到按下觸發值Release=(ReadDataTrgCont); /3 得到釋放觸發值 Cont = ReadData; /4 得到所有未釋放的鍵值下面是程序解釋:Trg(triger) 代表的是觸發,Cont(continue)代表的是連續

2、按下。1:讀PORTB的端口數據,取反,然后送到ReadData 臨時變量里面保存起來。2:算法1,用來計算觸發變量的。一個位與操作,一個異或操作,我想學過C語言都應該懂吧?Trg為全局變量,其它程序可以直接引用。3:算法2,用來計算連續變量。我們最常用的按鍵接法如下:AVR是有內部上拉功能的,但是為了說明問題,我是特意用外部上拉電阻。那么,按鍵沒有按下的時候,讀端口數據為1,如果按鍵按下,那么端口讀到0。下面就看看具體幾種情況之下,這算法是怎么一回事。(1) 沒有按鍵的時候端口為0xff,ReadData讀端口并且取反,很顯然,就是 0x00 了。Trg = ReadData & (

3、ReadData Cont); (初始狀態下,Cont也是為0的)很簡單的數學計算,因為ReadData為0,則它和任何數“相與”,結果也是為0的。Cont = ReadData; 保存Cont 其實就是等于ReadData,為0;結果就是:ReadData 0;Trg 0;Cont 0;(2) 第一次PB0按下的情況端口數據為0xfe,ReadData讀端口并且取反,很顯然,就是 0x01 了。Trg = ReadData & (ReadData Cont); 因為這是第一次按下,所以Cont是上次的值,應為為0。那么這個式子的值也不難算,也就是 Trg = 0x01 & (

4、0x010x00) = 0x01Cont = ReadData = 0x01;結果就是:ReadData 0x01;Trg 0x01;Trg只會在這個時候對應位的值為1,其它時候都為0Cont 0x01;(3) PB0按著不松(長按鍵)的情況端口數據為0xfe,ReadData讀端口并且取反是 0x01 了。Trg = ReadData & (ReadData Cont); 因為這是連續按下,所以Cont是上次的值,應為為0x01。那么這個式子就變成了 Trg = 0x01 & (0x010x01) = 0x00Cont = ReadData = 0x01;結果就是:ReadD

5、ata 0x01;Trg 0x00;Cont 0x01;因為現在按鍵是長按著,所以MCU會每個一定時間(20ms左右)不斷的執行這個函數,那么下次執行的時候情況會是怎么樣的呢?ReadData 0x01;這個不會變,因為按鍵沒有松開Trg ReadData & (ReadData Cont) 0x01 & (0x01 0x01) = 0 ,只要按鍵沒有松開,這個Trg值永遠為 0 !Cont 0x01;只要按鍵沒有松開,這個值永遠是0x01?。?) 按鍵松開的情況端口數據為0xff,ReadData讀端口并且取反是 0x00 了。Trg = ReadData & (Re

6、adData Cont) = 0x00 & (0x000x01) = 0x00Cont = ReadData = 0x00;結果就是:ReadData 0x00;Trg 0x00;Cont 0x00;很顯然,這個回到了初始狀態,也就是沒有按鍵按下的狀態??偨Y一下,不知道想懂了沒有?其實很簡單,答案如下:Trg 表示的就是觸發的意思,也就是跳變,只要有按鍵按下(電平從1到0的跳變),那么Trg在對應按鍵的位上面會置一,我們用了PB0則Trg的值為0x01,類似,如果我們PB7按下的話,Trg 的值就應該為 0x80 ,這個很好理解,還有,最關鍵的地方,Trg 的值每次按下只會出現一次,然

7、后立刻被清除,完全不需要人工去干預。所以按鍵功能處理程序不會重復執行,省下了一大堆的條件判斷,這個可是精粹哦!Cont代表的是長按鍵,如果PB0按著不放,那么Cont的值就為 0x01,相對應,PB7按著不放,那么Cont的值應該為0x80,同樣很好理解。因為有了這個支持,那么按鍵處理就變得很爽了,下面看應用:應用一:一次觸發的按鍵處理假設PB0為蜂鳴器按鍵,按一下,蜂鳴器beep的響一聲。這個很簡單,但是大家以前是怎么做的呢?對比一下看誰的方便?#define KEY_BEEP 0x01void KeyProc(void) if (Trg & KEY_BEEP) / 如果按下的是KE

8、Y_BEEP Beep(); / 執行蜂鳴器處理函數 怎么樣?夠和諧不?記得前面解釋說Trg的精粹是什么?精粹就是只會出現一次。所以你按下按鍵的話,Trg & KEY_BEEP 為“真”的情況只會出現一次,所以處理起來非常的方便,蜂鳴器也不會沒事亂叫,hoho或者你會認為這個處理簡單,沒有問題,我們繼續。應用2:長按鍵的處理項目中經常會遇到一些要求,例如:一個按鍵如果短按一下執行功能A,如果長按2秒不放的話會執行功能B,又或者是要求3秒按著不放,計數連加什么什么的功能.這里具個簡單例子,為了只是說明原理,PB0是模式按鍵,短按則切換模式,PB1就是加,如果長按的話則連加(玩過電子表吧?

9、沒錯,就是那個?。?define KEY_MODE 0x01 / 模式按鍵#define KEY_PLUS 0x02 / 加void KeyProc(void) if (Trg & KEY_MODE) / 如果按下的是KEY_MODE,而且你常按這按鍵也沒有用, /它是不會執行第二次的哦 , 必須先松開再按下 Mode+; / 模式寄存器加1,當然,這里只是演示,你可以執行你想 / 執行的任何代碼 if (Cont & KEY_PLUS) / 如果“加”按鍵被按著不放 cnt_plus+; / 計時 if (cnt_plus > 100) / 20ms*100 = 2S

10、如果時間到 Func(); / 你需要的執行的程序 應用3:點觸型按鍵和開關型按鍵的混合使用點觸形按鍵估計用的最多,特別是單片機。開關型其實也很常見,例如家里的電燈,那些按下就不松開,除非關。這是兩種按鍵形式的處理原理也沒啥特別,但是你有沒有想過,如果一個系統里面這兩種按鍵是怎么處理的?我想起了我以前的處理,分開兩個非常類似的處理程序,現在看起來真的是笨的不行了,但是也沒有辦法啊,結構決定了程序。不過現在好了,用上面介紹的辦法,很輕松就可以搞定。原理么?可能你也會想到,對于點觸開關,按照上面的辦法處理一次按下和長按,對于開關型,我們只需要處理Cont就OK了,為什么?很簡單嘛,把它當成是一個長

11、按鍵,這樣就找到了共同點,屏蔽了所有的細節。程序就不給了,完全就是應用2的內容,在這里提為了就是說明原理好了,這個好用的按鍵處理算是說完了??赡軙信笥褧?,為什么不說延時消抖問題?哈哈,被看穿了。果然不能偷懶。下面談談這個問題,順便也就非常簡單的談談我自己用時間片輪辦法,以及是如何消抖的。延時消抖的辦法是非常傳統,也就是 第一次判斷有按鍵,延時一定的時間(一般習慣是20ms)再讀端口,如果兩次讀到的數據一樣,說明了是真正的按鍵,而不是抖動,則進入按鍵處理程序。當然,不要跟我說你delay(20)那樣去死循環去,真是那樣的話,我衷心的建議你先放下手上所有的東西,好好的去了解一下操作系統的分時工

12、作原理,大概知道思想就可以,不需要詳細看原理,否則你永遠逃不出“菜鳥”這個圈子。當然我也是菜鳥。我的意思是,真正的單片機入門,是從學會處理多任務開始的,這個也是學校程序跟公司程序的最大差別。當然,本文不是專門說這個的,所以也不獻丑了。我的主程序架構是這樣的:volatile unsigned char Intrcnt;void InterruptHandle() / 中斷服務程序 Intrcnt+; / 1ms 中斷1次,可變void main(void) SysInit(); while(1) / 每20ms 執行一次大循環 KeyRead(); / 將每個子程序都掃描一遍 KeyProc(

13、); Func1(); Funt2(); while(1) if (Intrcnt>20) / 一直在等,直到20ms時間到 Intrcnt="0" break; / 返回主循環 貌似扯遠了,回到我們剛才的問題,也就是怎么做按鍵消抖處理。我們將讀按鍵的程序放在了主循環,也就是說,每20ms我們會執行一次KeyRead()函數來得到新的Trg 和 Cont 值。好了,下面是我的消抖部分:很簡單基本架構如上,我自己比較喜歡的,一直在用。當然,和這個配合,每個子程序必須執行時間不長,更加不能死循環,一般采用有限狀態機的辦法來實現,具體參考其它資料咯。懂得基本原理之后,至于怎

14、么用就大家慢慢思考了,我想也難不到聰明的工程師們。例如還有一些處理,怎么判斷按鍵釋放?很簡單,Trg 和Cont都為0 則肯定已經釋放了。把程序稍改一下,可以兼容所有的電平變化:Unsigned char PreKey;Unsigned char NewKey;Volaitile unsigned char KeyCode;Void ReadKey(void)PreKey = NewKey;NewKey = Pinx;KeyCode = PreKeyNewKeyKeyCode; /注意:等式左邊的KeyCode是本次讀按鍵的結果,等式右邊的KeyCode是上次讀按鍵的結果KeyCode 是全局

15、變量,和Cont一樣。題目:多功能按鍵設計。利用一個I/O口,接一個按鍵,實現3功能操作:單擊 + 雙擊 + 長按。 =用戶基本操作定義: 1。短按操作:按鍵按下,按下時間<1s,屬于一次短按操作 2。長按操作:按鍵按下,按下時間>1s,屬于一次長按操作在正常0.5s內無按鍵操作為啟始按鍵掃描條件下,掃描按鍵將產生以下3種按鍵事件: 1。長按事件:任何1次出現的長按操作都屬于長按事件 2。單擊事件:1次短按操作后,間隔0.5內沒有短按操作 3。雙擊事件:2次短按操作間隔時間<0.5s,則2次短按操作為1次雙擊事件,且2次短按都取消特別操作情況定義: 1。短按操作和長按操作間隔

16、<0.5s,以及,長按操作和短按操作間隔<0.5s,均不產生雙擊事件 2。連續n次(n為奇數)短按操作,且間隔均<0.5s,產生(n-1)/2次雙擊事件+1次單擊事件 3。連續n次(n為偶數)短按操作,且間隔均<0.5s,產生n/2次雙擊事件對按鍵操作者的建議: 由于按鍵的多功能性質,建議操作者每次在單擊/長按/雙擊按鍵事件發生后,隔0.5s后再進行下一次的按鍵操作。因為在特別操作情況下,程序是保證按定義進行判斷和處理的,主要是怕操作者自己記不清楚導致操作失誤。對軟件設計者的要求: 1。應該全面進行分析,給出嚴格定義和判斷條件,如上所示。如果自己都不清楚,你的設計出的系

17、統就不穩定,不可靠。 2。在1的基礎上,編寫出符合要求的程序,并進行全面測試。/*=低層按鍵(I/0)掃描函數,即低層按鍵設備驅動,只返回無鍵、短按和長按。具體雙擊不在此處判斷。參考本人教材的例9-1,稍微有變化。教材中為連_發。=*/#define key_input PIND.7 / 按鍵輸入口#define N_key 0 /無鍵#define S_key 1 /單鍵#define D_key 2 /雙鍵#define L_key 3 /長鍵#define key_state_0 0#define key_state_1 1#define key_state_2 2unsigned ch

18、ar key_driver(void) static unsigned char key_state = key_state_0, key_time = 0; unsigned char key_press, key_return = N_key; key_press = key_input; / 讀按鍵I/O電平 switch (key_state) case key_state_0: / 按鍵初始態 if (!key_press) key_state = key_state_1; / 鍵被按下,狀態轉換到按鍵消抖和確認狀態 break; case key_state_1: / 按鍵消抖與確

19、認態 if (!key_press) key_time = 0; / key_state = key_state_2; / 按鍵仍然處于按下,消抖完成,狀態轉換到按下鍵時間的計時狀態,但返回的還是無鍵事件 else key_state = key_state_0; / 按鍵已抬起,轉換到按鍵初始態。此處完成和實現軟件消抖,其實按鍵的按下和釋放都在此消抖的。 break; case key_state_2: if(key_press) key_return = S_key; / 此時按鍵釋放,說明是產生一次短操作,回送S_key key_state = key_state_0; / 轉換到按鍵初

20、始態 else if (+key_time >= 100) / 繼續按下,計時加10ms(10ms為本函數循環執行間隔) key_return = L_key; / 按下時間>1000ms,此按鍵為長按操作,返回長鍵事件 key_state = key_state_3; / 轉換到等待按鍵釋放狀態 break; case key_state_3: / 等待按鍵釋放狀態,此狀態只返回無按鍵事件 if (key_press) key_state = key_state_0; /按鍵已釋放,轉換到按鍵初始態 break; return key_return;/*=中間層按鍵處理函數,調用

21、低層函數一次,處理雙擊事件的判斷,返回上層正確的無鍵、單鍵、雙鍵、長鍵4個按鍵事件。本函數由上層循環調用,間隔10ms=*/unsigned char key_read(void) static unsigned char key_m = key_state_0, key_time_1 = 0; unsigned char key_return = N_key,key_temp; key_temp = key_driver(); switch(key_m) case key_state_0: if (key_temp = S_key ) key_time_1 = 0; / 第1次單擊,不返回,

22、到下個狀態判斷后面是否出現雙擊 key_m = key_state_1; else key_return = key_temp; / 對于無鍵、長鍵,返回原事件 break; case key_state_1: if (key_temp = S_key) / 又一次單擊(間隔肯定<500ms) key_return = D_key; / 返回雙擊鍵事件,回初始狀態 key_m = key_state_0; else / 這里500ms內肯定讀到的都是無鍵事件,因為長鍵>1000ms,在1s前低層返回的都是無鍵 if(+key_time_1 >= 50) key_return

23、= S_key; / 500ms內沒有再次出現單鍵事件,返回上一次的單鍵事件 key_m = key_state_0; / 返回初始狀態 break; return key_return; 下面,根據程序分析按鍵事件的反映時間:1。對于長鍵,按下超過1s馬上響應,反映最快2。對于雙鍵,第2次按鍵釋放后馬上得到反映。3。對于單鍵,釋放后延時拖后500ms才能響應,反映最慢。這個與需要判斷后面是否有雙擊操作有關,只能這樣。實際應用中,可以調整兩次單擊間隔時間定義,比如為300ms,這樣單擊的響應回快一點,單按鍵操作人員需要加快按鍵的操作過程。如果產品是針對老年人的,這個時間不易太短,因為年紀大的人

24、,反映和動作都比較慢。 當然,上面兩段可以合在一起。我這樣做的目的,是為了可以方便的擴展為N擊(當然,需要做修改)??墒亲畹讓拥木褪亲罨镜牟僮魈幚矶贪春烷L按,不用改動的。至于雙擊,還是N擊,在中間層處理。這就是程序設計中分層結構的優點。測試代碼環境如下: interrupt TIM0_COMP void timer0_comp_isr(void) / 定時器10ms中斷服務 time_10ms_ok = 1;main(viod) . while if (time_10ms_ok) /每10ms執行一次, time_10ms_ok =0; key = key_read(); /= 10ms一次

25、調用按鍵中間層函數,根據返回鍵值,點亮不同的LED燈,全面測試按鍵操作是否正常 if (key = L_key) ./點亮A_LED,關閉B_LED和C_LED else if(key = D_key) ./點亮B_LED,關閉A_LED和C_LED else if(key = S_key) ./點亮C_LED,關閉A_LED和B_LED =單個按鍵復用:單擊,長按,雙擊。2011-09-16 11:13閑著無事在網上逛,產生按鍵復用的想法。前些天找按鍵復用程序,在網上很難找到,有些收費的代碼是我們不會買的。所以借鑒了一位老師的代碼,自己改了改。剛開始調試不成功,后來成了。/*實驗目的:按鍵的長按,短按,雙擊檢測*/#include <reg52.h>#define uint unsigned int#define uchar unsigned charuchar key_num; /按鍵計數變量bit key_long_flag,key_short_flag,key_double_flag; /長按標志位,短按標志位,雙擊標志位sbit key=P10; /獨立按鍵接P10/*ms延時函數*/void delay_ms(uint ms) u

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論