首先說(shuō)明:這是一個(gè)失敗的按鍵掃描程序。它的前身是機(jī)智云的STM32按鍵掃描代碼。 不管是用什么芯片,按鍵掃描的延時(shí)去抖總是令人心痛,費(fèi)CPU費(fèi)電費(fèi)時(shí)間,于是各種各樣好玩有趣的按鍵掃描代碼誕生了。就比如我曾經(jīng)下載的這個(gè)機(jī)智云的代碼,使用狀態(tài)機(jī)+事件驅(qū)動(dòng),看起來(lái)非常漂亮。 使用狀態(tài)機(jī)和一個(gè)定時(shí)器,就可以去除消抖延時(shí),提高按鍵掃描效率,還可以在里面添加各種各樣的功能判斷,好處說(shuō)不完吶。 而事件驅(qū)動(dòng),把按鍵和按鍵對(duì)應(yīng)的功能隔離開,使用函數(shù)指針連接,這樣分隔開了按鍵掃描和事件處理。回想起多級(jí)菜單,每一級(jí)菜單按鍵功能都不一樣,處理起來(lái)簡(jiǎn)直就是噩夢(mèng)。如果用事件機(jī)制來(lái)做的話,就可以通過函數(shù)指針動(dòng)態(tài)改變按鍵功能,終于把重復(fù)混亂的變量和代碼送進(jìn)了回收站。 最近放假實(shí)在是心動(dòng),我想,如果能把它用在51上該多好呀,于是乎就動(dòng)手了。但是當(dāng)我興沖沖地把它改了好半天,終于用在51上的時(shí)候,程序直接掛掉了——51速度太慢,消抖檢測(cè)周期內(nèi)不能跑完回調(diào)函數(shù),于是就會(huì)死機(jī)。 實(shí)驗(yàn)環(huán)境是STC12C5A60S2 11.0592MHz 代碼8級(jí)優(yōu)化 對(duì)于51單片機(jī)來(lái)說(shuō),這個(gè)程序致命的缺點(diǎn): 1. 51速度不夠,如上所述。我試著把KeyHandle函數(shù)里后三個(gè)功能的檢測(cè)注釋掉,就不會(huì)死機(jī)了。但是這不是寫這段程序的初衷,所以不能這么做。 2. 51內(nèi)存不夠。這段程序在定義4個(gè)按鍵3個(gè)事件的時(shí)候RAM占用量就過百了,看著51那可憐巴巴的128字節(jié)RAM,我都有點(diǎn)不忍了。至于STC自帶的擴(kuò)展的RAM,速度實(shí)在是不夠,如果定義到xdata,回調(diào)函數(shù)里很簡(jiǎn)短的操作都會(huì)死機(jī)。
結(jié)果是失敗了,芯片配置不行,但是代碼還是很有趣的。雖然下面說(shuō)的這些因?yàn)?1的速度被限制了,但是我還是想說(shuō)一說(shuō),都是實(shí)際問題。 以往的按鍵掃描,按鍵IO口要用sbit或者#define,離掃描函數(shù)隔得老遠(yuǎn),16進(jìn)制鍵碼還得自己算,算錯(cuò)了就不響應(yīng),功能函數(shù)就更不忍直視了,和消抖攪和在一起…… 再看這個(gè)按鍵掃描: 1. 按鍵IO直接在初始化函數(shù)里用字符串輸入,支持任意IO口連接的矩陣鍵盤和單線開關(guān)按鍵。 - void KeyInit(void) //按鍵掃描初始化
- {
- SingleKey[EnumKey_Left].IOPort1 = "P34"; SingleKey[EnumKey_Left].IOPort2 = "P30"; //注冊(cè)按鍵 Port1必須是IO口 Port2是IO口或"GND"
- SingleKey[EnumKey_Right].IOPort1 = "P35"; SingleKey[EnumKey_Right].IOPort2 = "P30";
- SingleKey[EnumKey_Up].IOPort1 = "P36"; SingleKey[EnumKey_Up].IOPort2 = "P30";
- SingleKey[EnumKey_Down].IOPort1 = "P37"; SingleKey[EnumKey_Down].IOPort2 = "P30";
- ...
復(fù)制代碼 矩陣鍵盤不一定要接在一個(gè)8 位的整組IO 上。對(duì)于40 腳直插的單片機(jī)來(lái)說(shuō),這反而復(fù)雜了些。但是呢,看看那些一不丟丟的小可憐單片機(jī),比如STC15W408AS 的16腳封裝,一組完整引出的IO 都沒有,要是在這樣的單片機(jī)上用傳統(tǒng)的方式應(yīng)用4x4 的矩陣鍵盤,那處理起來(lái)可難受死了……
10.png (71.78 KB, 下載次數(shù): 53)
下載附件
2021-9-14 20:07 上傳
2. 按鍵編碼就是從0開始到最大按鍵支持?jǐn)?shù)量-1 ,放在一個(gè)enum枚舉里面,鍵碼就是移位,不用算,直接復(fù)制粘貼就可以。還需要把下面#define的按鍵成員總數(shù)也一起改了,注意不要超過最大值,最大值在KeyScan.h里定義,如果有需要可以修改。 - enum EnumUserKey //按鍵編號(hào)和鍵值枚舉 編號(hào)從0開始 不得超過(KEY_MAX_NUMBER-1)
- {
- EnumKey_Up = 0, EnumKey_Up_TriggerValue = 1<<EnumKey_Up,
- EnumKey_Down = 1, EnumKey_Down_TriggerValue = 1<<EnumKey_Down,
- EnumKey_Left = 2, EnumKey_Left_TriggerValue = 1<<EnumKey_Left,
- EnumKey_Right = 3, EnumKey_Right_TriggerValue = 1<<EnumKey_Right
- };
復(fù)制代碼
3. 功能函數(shù)作為事件單獨(dú)定義,我改進(jìn)了一下原來(lái)的代碼,讓功能和按鍵互相獨(dú)立,用戶自定義觸發(fā)方式或按鍵組合,再用函數(shù)指針連接想要觸發(fā)的事件,邏輯簡(jiǎn)潔清晰。 還需要把上面#define的用戶自定義的功能總數(shù)一起改了,就是KeyFuncs成員的數(shù)量,不一定和事件函數(shù)或者按鍵數(shù)量一致,只要內(nèi)存夠用,想要多少就要多少。
- void Key7ShortPressEvent(void)
- {
- static u8 i=0;
- i = (i+1)%CountOfArray(table);
- display(i);
- }
- void Key12ShortPressEvent(void)
- {
- static u8 i=0;
- i = (i-1)%CountOfArray(table);
- display(i);
- }
- void Key17_22ShortPressEvent(void)
- {
- Uart_SendString("Func2! \r\n");
- //這個(gè)太慢了 會(huì)死機(jī)! 放主函數(shù)里也不行 串口被打斷了就會(huì)卡死
- }
復(fù)制代碼- KeyFuncs[0].TriggerValue = EnumKey_Up_TriggerValue; //需要響應(yīng)的鍵值 注意是鍵值! 不是鍵編號(hào)! 組合按鍵用或
- KeyFuncs[0].SingleClick = Key7ShortPressEvent; //注冊(cè)回調(diào)函數(shù)
- KeyFuncs[1].TriggerValue = EnumKey_Down_TriggerValue; //需要響應(yīng)的鍵值 注意是鍵值! 不是鍵編號(hào)! 組合按鍵用或
- KeyFuncs[1].SingleClick = Key12ShortPressEvent; //注冊(cè)回調(diào)函數(shù)
- KeyFuncs[2].TriggerValue = EnumKey_Left_TriggerValue | EnumKey_Right_TriggerValue; //需要響應(yīng)的鍵值 注意是鍵值! 不是鍵編號(hào)! 組合按鍵用或
- KeyFuncs[2].MultiPress = Key17_22ShortPressEvent; //注冊(cè)回調(diào)函數(shù)
復(fù)制代碼
到這里就算是完成了按鍵驅(qū)動(dòng)的應(yīng)用,這個(gè)思路是不是比傳統(tǒng)的方式簡(jiǎn)單多了,嘿嘿。 除非要修改按鍵消抖的時(shí)間常數(shù),或者刪減按鍵功能(長(zhǎng)按短按判定等),或者改變軟件支持的按鍵數(shù)量,不然不需要修改KeyScan.c和KeyScan.h,這樣就完全分離了驅(qū)動(dòng)和應(yīng)用,不管是移植維護(hù)還是調(diào)試,都非常方便。
說(shuō)了這么多,結(jié)果不還是不能用嗎?我用STC12C5A60S2 11.0592MHz速度確實(shí)不夠,不過現(xiàn)在STC15W內(nèi)部IRC時(shí)鐘可以飆到30MHz,我沒有試過,不知道夠不夠。就算51用不了,移植到別的單片機(jī)上也是不錯(cuò)的。狀態(tài)機(jī)和事件驅(qū)動(dòng)的思路可以放到很多應(yīng)用里去,雖然這是一個(gè)失敗的程序,但是到目前為止還沒發(fā)現(xiàn)邏輯問題,只是受硬件配置限制,就當(dāng)是一次學(xué)習(xí)的過程吧。 失敗是成功之母。
GizwitsMCUSTM32F103C8x20170428114156281c5df12c.zip
(725.67 KB, 下載次數(shù): 19)
2018-10-9 10:50 上傳
點(diǎn)擊文件名下載附件
機(jī)智云的 下載積分: 黑幣 -5
狀態(tài)機(jī)按鍵20181008bak.zip
(63.99 KB, 下載次數(shù): 20)
2018-10-9 10:50 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
|