單片機按鍵輸入設計方法詳解


學習過單片機技術的人都知道,單片機的按鍵輸入一般可分為簡單的獨立式按鍵輸入及行列式鍵盤輸入兩種。圖1為簡單的獨立式鍵盤輸入示意圖,獨立式鍵盤輸入適合於按鍵輸入不多的情況(<5個按鍵),具有佔用口線較少、軟件編寫簡單容易等特點。

單片機按鍵輸入設計方法詳解

圖1

圖2為行列式鍵盤輸入示意圖,列線接P1.0~P1.3,行線接P1.4~P1.7。行列式鍵盤輸入適合於按鍵輸入多的情況,如有16個按鍵輸入,用簡單按鍵輸入用要佔用2個輸入口(共16位),而使用行列式鍵盤輸入只需佔用一個輸入口(8位)。但行列式鍵盤輸入軟件編寫較複雜,對初學者而言有一定的難度。

單片機按鍵輸入設計方法詳解

圖2

以上略談了一下按鍵輸入的情況。在很多狀態下,按鍵輸入的值要同時要在LED數碼管上顯示出來。如一個按鍵設計為輸入遞增(加法)鍵,可以設計成每點按一下,數值遞增加1,同時在LED數碼管上顯示出來;也可設計成持續按下時,數值以一定時間間隔(如0.3秒)累加。但是當欲輸入值較大時(如三位LED數碼管作輸入顯示時的輸入值最大為999),則可能按下鍵的時間太長(最長達300秒),看來這種方式只適用於一位或至多兩位數值(最大99)的輸入。當然你也可多設幾個鍵,每個鍵只負責一位數值的輸入,但這樣會佔用較多的口線,浪費寶貴的硬件資源。

大家可能見到過,一些進口的溫度控制器(如日本RKC INSTRUMENT INC. 生產的REX_C700溫控器)的面板設計為:溫度測量值用4位LED數碼管顯示,輸入設定值顯示也用4位LED數碼管,輸入按鍵只有4個,一個為"模式設定鍵",一個為"左移鍵",另兩個為"加法鍵"、"減法鍵"。欲輸入設定值(溫控值)時,按一下"模式設定鍵",程序進入設定狀態,此時輸入設定值顯示的4位LED數碼管中,個位顯示最亮(穩定顯示),而十、百、千位顯示較暗(有閃爍感),說明可對個位進行輸入。按下"加法鍵"或"減法鍵",即可輸入個位數的值;點按一下"左移鍵",變為十位顯示最亮,而個、百、千位顯示較暗,說明可對十位進行輸入。按下"加法鍵"或"減法鍵",即可輸入十位數的值;……這樣可完成4位數的輸入。完成輸入後,再按一下"模式設定鍵",程序即退出設定狀態,進入工作運行。用這種輸入方法,不僅輸入4位數用4個鍵即可,再多位(5位至24位)的輸入也用這4個鍵就夠了。

大家瞭解了這種新穎的按鍵輸入方式後,一定很感興趣,也想掌握設計方法。為了便於大家理解,這裡結合筆者設計的一款"節能時控器",詳細進行講解。"節能時控器"用於定時控制大功率電器工作,因現採用分時計費方法,可起到節約開支的作用,對工業生產成效顯著。

圖3為"節能時控器"硬件構成原理圖。"節能時控器"共有4個輸入按鍵:set--模式設定鍵,left--左移鍵,up—加法鍵,on/off--定時1、2啟動/關閉鍵。單片機IC1(AT89C2051)只有15條I/O線,由於受I/O線數量限制,因此P1口中的P1.0~P1.3既作為驅動4位LED數碼管的數據輸出一部分,同時也用作按鍵的輸入。無疑,這種方式大大節約了硬件的I/O線,但也給編程者提出了更高的技術要求。限於篇幅,我們只對要詳解的按鍵輸入程序進行分析,其它部分只略作介紹。如讀者需"節能時控器"詳細的源程序,可發E-mail:[email protected]與作者聯繫。

單片機按鍵輸入設計方法詳解

圖3

圖4為主程序狀態流程圖。可見主程序只負責進行走時或調整時間的運算及顯示,而判斷按鍵輸入則放在T1定時中斷(10mS)服務子程序中。T0作為走時的基準被設置為100mS定時中斷。這種設計的優點是大大簡化了主程序設計,並且CPU會定時關心鍵盤,只要定時中斷時間足夠短(如為幾十mS),就不會漏掉每一次的按鍵輸入。


N

Y

Y


圖4

下面為判斷按鍵輸入的T1定時中斷服務子程序,序號為解釋方便而加。

/*10mS定時中斷服務子函數*/

序號1:void zd1(void) interrupt 3

2:{

3:uchar i,j;i=P1;j=P3;

4:TH1=-(5000/256);

5:TL1=-(5000%256);

6:if(m==1)n++;

7:if(n>=30){n=0;m=0;}

8:P3_7=0;

9:P1=0xff;

10:if(P1!=0xff)

11:{

12:if(n==0)m=1;

13:{if(n==1)

14:{

15:if(P1_0==0){set++;left=0;}

16:if(set>=4)set=0;

17:if(set==1)flag=0x55;

18:if(P1_1==0)left++;

19:if(left>=4)left=0;

20:if(P1_2==0){up++;

21:switch(left)

22:{

23:case 0:{if(up>=10)up=0;}break;

24:case 1:{if(up>=6)up=0;}break;

25:case 2:{if(up>=10)up=0;}break;

26:case 3:{if(up>=3)up=0;}break;

27:default:break;

28:}

29:}

30:if(P1_2==0){

31:switch(set)

32:{case 0:break;

33:case 1:x[left]=up;break;

34:case 2:{y[left]=up;if(P1_3==0)o_f1=!o_f1;}break;

35:case 3:{z[left]=up;if(P1_3==0)o_f2=!o_f2;}break;

36:default:break;

37:}}

38:else {

39:switch(set)

40:{case 0:break;

41:case 1:up=x[left];break;

42:case 2:{up=y[left];if(P1_3==0)o_f1=!o_f1;}break;

43:case 3:{up=z[left];if(P1_3==0)o_f2=!o_f2;}break;

44:default:break;}

45 :}}

46:}}

47:P1=i;P3=j;

48:}

序號1(程序解釋,以下同):聲明定時1中斷函數。

序號2:定時1中斷函數開始。

序號3:定義i、j為無符號字符型局部變量。將當時的P1口、P3口狀態送i、j暫存。

序號4、5:定時器T1重新載入10mS初值。

序號6:如變量m等於1,則變量n遞增。說明:m、n為整個程序開始時定義的無符號字符型全局變量。

序號7:如變量n大於等於30,則m、n清零。

序號8:P3.7置0,準備讀取按鍵輸入。

序號9:P1口置全1,準備讀取按鍵輸入。

序號10:如果P1口不等於全1,說明4個按鍵中有鍵按下。

序號11:進入if(P1!=0xff)語句範圍。

序號12:如果n等於0,進入if(n==0)語句,m置1。

序號13:如果n等於1,進入if(n==1)語句,同時進行下面的具體判斷按鍵語句。作用效果為:開始時m、n均賦0,一旦有鍵按下,第一次中斷產生時m賦1;第二次中斷產生時n遞增。當n等於1時(第二次中斷產生)進入下面的具體判斷按鍵語句。若持續按下鍵,則第三次中斷產生~第三十一次中斷產生時,程序不進入具體的判斷按鍵語句過程(因這時n不等於1)。由於中斷每10mS產生一次,這樣可實現每0.31秒(31x10=0.31秒)進行一次加法或移位的操作,與人眼的視覺特性相吻合。

序號14:進入具體判斷按鍵語句範圍。

序號15:如果P1.0等於0(即電路中的set鍵按下),變量set遞增,變量left清0。說明:set、left是為了判斷模式設定及左移而在整個程序開始時定義的無符號字符型全局變量。

序號16:如果set大於等於4,則set清0。說明:set值只能在0~3間變化,只有4種工作模式(走時及輸出控制模式、走時調整模式、定時1調整模式、定時2調整模式)。

序號17:在set等於1時,向RAM區標誌變量flag寫入55H。說明:flag是在整個程序開始時定義的無符號字符型全局變量,用作判斷RAM區是否受干擾的依據。

序號18:如果P1.1等於0(即電路中的left鍵按下),變量left遞增。

序號19:如果left大於等於4,則left清0。說明:left值只能在0~3間變化,LED數碼管只有4位顯示。

序號20:如果P1.2等於0(即電路中的up鍵按下),進入if(P1_2==0)語句,變量up遞增。說明:up是為了判斷數值增量而在整個程序開始時定義的無符號字符型全局變量。

序號21:隨即進入switch(left)開關語句。

序號22:switch(left)開關語句開始。

序號23:left值為0時,如果up大於等於10,則up清0。隨即退出。說明:電子鐘的個位可在0~9之間調整。

序號24:left值為1時,如果up大於等於6,則up清0。隨即退出。說明:電子鐘的十位可在0~5之間調整。

序號25:left值為2時,如果up大於等於10,則up清0。隨即退出。說明:電子鐘的百位可在0~9之間調整。

序號26:left值為3時,如果up大於等於3,則up清0。隨即退出。說明:電子鐘的千位可在0~2之間調整。

序號27:若left為其它值,也退出。

序號28:switch(left)開關語句結束。

序號29:if(P1_2==0)語句結束。

序號30:如果P1.2等於0(即電路中的up鍵按下時),進入if(P1_2==0)語句,同時進入switch(set)開關語句。

序號31:switch(set)開關語句開始。

序號32:set值為0時,退出。

序號33:set值為1時,將此時up值送入X數組的第left位。隨即退出。說明:X數組是顯示走時緩存區。

序號34:set值為2時,將此時up值送入Y數組的第left位。若此時P1.3等於0(即電路中的on/off鍵按下),則定時1啟停標誌位o_f1取反(啟動/關閉)。隨即退出。說明:Y數組是定時1記憶緩存區。o_f1是為了判斷定時1啟動/關閉而在整個程序開始時定義的位標誌。

序號35:set值為3時,將此時up值送入Z數組的第left位。若此時P1.3等於0(即電路中的on/off鍵按下),則定時2啟停標誌位o_f2取反(啟動/關閉)。隨即退出。說明:Z數組是定時2記憶緩存區。o_f2是為了判斷定時2啟動/關閉而在整個程序開始時定義的位標誌。

序號36:若set為其它值,也退出。

序號37:switch(set)開關語句結束。if(P1_2==0)語句結束。

序號38:else語句開始。

序號39:又進入switch(set)開關語句。說明:上一個switch(set)開關語句是將按鍵產生的up值送入X、Y、Z數組存放,現在這個switch(set)開關語句是調出X、Y、Z數組內容至變量up,以便在原來的基礎上遞增。例如:原來的X[0]值為5,則在調整時個位LED數碼管顯示就從5開始往上調,而不會產生從0或其它值開始上調的情況,適合人的一般直覺。

序號40:set值為0時,退出。

序號41:set值為1時,將此時X數組的第left位值送入變量up。隨即退出。

序號42:set值為2時,將此時Y數組的第left位值送入變量up。若此時P1.3等於0(即電路中的on/off鍵按下),則定時1啟停標誌位o_f1取反(啟動/關閉)。隨即退出。

序號43:set值為3時,將此時Z數組的第left位值送入變量up。若此時P1.3等於0(即電路中的on/off鍵按下),則定時2啟停標誌位o_f2取反(啟動/關閉)。隨即退出。

序號44:若set為其它值,也退出。

序號45:switch(set)開關語句結束。else語句結束。

序號46:if(n==0)語句結束。if(P1!=0xff)語句結束。

序號47:本次定時中斷快結束時,將暫存於i,j的當時P1口、P3口狀態還原。

序號48:定時1中斷函數結束。

上面為按鍵輸入程序設計的詳細解釋,按鍵輸入時需將當時狀態實時顯示出來,我們將顯示走時、顯示調整走時、顯示調整定時1、顯示調整定時2做成四個子程序,分別由set為0、1、2、3時散轉後的"顯示走時並判斷定時1、2到否程序"、"顯示調整走時程序"、"顯示調整定時1程序"、"顯示調整定時2程序"進行調用。為達到需輸入的某位顯示最亮(穩定顯示),而其它三位顯示較暗(有閃爍感)的視覺效顯,讓三位需顯示較暗的數碼管每位點亮3mS,而顯示最亮的那位數碼管點亮36mS即可。


單片機按鍵輸入設計方法詳解


分享到:


相關文章: