郝麗宏 林 凌 李 剛
傳統的鍵盤接口方式,鍵盤編碼控制芯片都要占用單片機兩根以上的I/O口線,且專用鍵盤編碼控制芯片的價格不菲。本文提出了脈寬編碼式按鍵的設計思想,并給出了已經調試通過的一種脈寬編碼式按鍵的具體設計方案。
1.設計思想及幾種典型的硬件電路
脈寬編碼式按鍵的設計靈感源于兩方面:一是單片機具備測量脈沖寬度的能力。具體地說,單片機的定時器/計數器在方式寄存器TMOD的GATE位為1時可測定外部中斷引腳上高電平的持續時間;二是從電路實現角度講,可以方便地產生具有不同脈沖寬度的脈沖。這兩個方面是實現脈寬編碼式按鍵設計的理論基礎。下面給出幾種實用的產生脈沖的硬件電路:
圖1是采用六施密特觸發反相器74HC14構成的振蕩器,只需要一只電阻和一只電容就可以構成一個最簡單的多諧振蕩器。如果系統中不需要74HC14片上的其它5個反相器,可以采用只有一個施密特觸發反相器的芯片。


圖2 所示為采用運放實現的低成本電路,采用線性積分電路構成多諧振蕩器, 工藝簡單,易于實現。
只要把上述電路中的電阻RK以圖3中所示的電路取代,就可作為脈寬編碼式按鍵的接口電路,脈寬大小取決于電阻值。
圖4所示為采用片內帶振蕩器的14位二進制串行計數器74HC4060實現的脈寬編碼式鍵盤接口電路原理圖。由于采用外接石英晶體振蕩器,所以分頻器的輸出脈寬是十分準確的,不需要任何調試就能夠工作。但由于74HC4060輸出端口有限,因而該電路適合于需要按鍵數量較少的場合,當然,只要在編程上稍下功夫,采用軟按鍵技術(即將菜單和按鍵組合在一起的用戶界面技術)就可以實現多個按鍵的功能。


需要說明的是:與單片機的時鐘電路相似,也可以不用內部振蕩器,而在11腳接入外部時鐘,10腳懸空。這時可以把74HC4060換成74HC4020或者74HC4040,如圖5為采用外部時鐘由74HC4040實現的脈寬編碼式鍵盤接口電路。
為了進一步降低成本,并提高測量脈寬的精度和穩定性,可以將單片機的系統時鐘分頻后提供給脈寬編碼式鍵盤接口電路作輸入脈沖,還可以采用外部時鐘振蕩器同時作為單片機的系統時鐘和脈寬編碼式鍵盤接口電路的時鐘源。需要注意的是,單片機能夠測量的最高頻率不能超過其系統時鐘的十二分之一。所以后者(采用外部時鐘振蕩器同時作為單片機的系統時鐘和脈寬編碼式鍵盤接口電路的時鐘源)在實際使用時只能放棄幾個按鍵不用,如圖5中的K1~K4。
2.程序設計
根據脈寬編碼式按鍵的設計思想,各脈寬編碼式按鍵接口電路圖中的引出端(TO)要與單片機INT0/INT1引腳相連。在保證單片機可分辨各按鍵脈寬的情況下,其它工作就留給程序設計了。
基于模塊化編程思想,按鍵程序應當獨立于程序中其它功能模塊,負責查詢按鍵狀態(有效按下、已釋放或未按下)并根據按鍵特征對按鍵編碼(賦予不同按鍵不同的鍵值),以便于主程序區分各個按鍵而轉入相應鍵處理子程序中。下面以用51單片機定時器T0測INT0腳輸入脈沖寬度為例,介紹具體的編程思路。
首先,主程序中要先進行初始化:設置定時器/計數器T0工作在16位定時器模式,打開選通門以使INT0引腳電平和TR0一起參與對T0/T1的控制,設置外部中斷INT0為邊沿觸發方式等等,具體程序見本刊網站。
然后編制外部中斷服務程序。下降沿觸發中斷,進入中斷服務程序后:(1)保護現場;(2)關閉定時器和外部中斷以免低電平時間太短時未出中斷又繼續計數或者再次觸發中斷;(3)然后讀取定時器時間。由于T0在GATE=1時是啟動定時器有效(TR0=1)并且INT0引腳為高電平時才工作,所以中斷觸發時定時器時間(TH0、TL0)恰好就是之前INT0腳脈沖的寬度;(4)根據TH0、TL0判斷出哪個按鍵被按下,賦鍵值;(5)把定時器TH0、TL0清零;(5)判斷此時INT0引腳是不是低電平,是則啟動定時器、使能中斷,不是則等待。這樣做是為了避免出現因為此時INT0引腳已經是高電平而一旦啟動了定時器(TR0=1)它就開始計時以至于下次中斷得到的定時器時間(TH0、TL0)不真實;(6)恢復現場,中斷返回。


步驟4中對按鍵的區別取決于具體電路,如圖1、圖2結合圖3所示的電路輸出的脈寬是等差的,而圖4、5、6是等比的。前者在單片機所直接測量的范圍內可以有較多的按鍵,但脈寬的精度較低,而后者的鍵值有限,少于16位鍵,但脈寬(鍵值)測量精度較高,特別是與單片機采用同一時鐘源時,可以認為沒有誤差。因而這兩類的鍵值處理程序略有不同:雖然都需要允許脈寬有一定的范圍,但前者的程序要復雜一些,去判定是否落在一個給定的誤差范圍內;后者由于誤差較小,而鍵值間距較大,可以簡單地按“位”判斷即可。下面舉例說明這兩種典型情況下的編程:
假定有255個鍵,通過適當的參數設置使K255按下時脈寬等于51單片機的256個指令周期(系統時鐘頻率為12MHz時一個指令周期等于1ms),K254按下時脈寬等于512個指令周期……,K1按下時脈寬等于65280個指令周期,相鄰兩鍵脈寬的差值為256個指令周期。按照上述的設計,脈寬比較時只需比較定時器高位字節即可。由于脈寬最小為256μs,和鍵盤電路的輸出脈沖基本上為50%的占空比,所以,在鍵盤電路的輸出低電平期間完全可以完成鍵值(脈寬)處理程序的執行,因而可以把鍵值(脈寬)處理程序放在中斷服務子程序中執行而不會影響脈寬的測量。鍵值有效時設置標志位KF0=1。假定等比鍵值的鍵盤接口電路有8個按鍵,并使得脈寬最小值為256個指令周期,相鄰分布。等差鍵值(脈寬)及等比鍵值(脈寬)的處理程序見本刊網站。

以上介紹的6個步驟是最基本的操作,還不足以保證按鍵信息的有效性。由于按鍵是利用機械觸點的合、斷作用,因此,鍵的按下與抬起都會有10~20ms的抖動毛刺存在。為了獲取穩定的按鍵信息,必須去除抖動影響,這也是按鍵處理的重要環節。去抖動的方法有硬件、軟件兩種。傳統按鍵接口電路通常用判斷口線電平來確定按鍵被按下與否,所以最常用的去抖動方法是一旦檢測到按鍵可能被按下就先延時10~20ms然后再讀口線狀態確定按下與否以及哪個鍵被按下。類似地,按鍵釋放與否也是在執行完相應鍵功能子程序后讀取口線狀態來確定。
在脈寬編碼式按鍵電路中抖動表現為脈沖寬度的不一致,因而去抖動的方法是在中斷服務程序中判斷此次測得的定時器時間(TH0、TL0)是否與上一次相等,相等則有效,不等則認為是干擾或者原按鍵已經釋放而新的按鍵被按下,更新定時器時間暫存單元。為了提高測量精度,設定計數器N,若連續n次測得的定時器時間(TH0、TL0)都相等,則認為按鍵有效,計數器N清零、賦鍵值、按鍵有效標志置1;若不足n次就發生變化,則認為按鍵無效,清空按鍵有效標志。需要注意的是,要允許一定的測量誤差存在,只要不影響按鍵的識別即可。

3.一個已經調試通過的應用實例
筆者設計了圖6所示的應用實例電路,其中MSC1210是TI公司生產的51兼容的單片機,具有增強型51內核,其ALE信號作為分頻器74HC4060(用4040或者4020除引腳序號不一樣外無區別)的輸入時鐘源信號,出于實際需要只用了5個按鍵。測試程序用單片機C語言編寫,在Keil_C7.01上調試通過,并由MSC1210的串口下載工具下載到單片機里,圖7為其主程序流程圖、圖8為中斷子程序流程圖,在本刊的網站上給出了源程序,供讀者參考。
該程序的執行結果是:按圖6中的K1~K5鍵則輸出小寫字母e~a,按一次鍵輸出一次。如果用戶想把某個按鍵作為連續觸發鍵(即按鍵按下較長時間后才抬起,雖然鍵閉合一次,但CPU卻進行多次鍵輸入處理)使用,只要稍微改變主程序中鍵處理子程序即可。例如:***行{}中加入下列語句:do{fun();}while(KF0==0);則只要按住K1鍵不放就反復執行fun()函數。要做成軟按鍵也只要進行嵌套即可。