第8講自己動手學(xué)習(xí)單片機(jī)系列-鍵盤_第1頁
第8講自己動手學(xué)習(xí)單片機(jī)系列-鍵盤_第2頁
第8講自己動手學(xué)習(xí)單片機(jī)系列-鍵盤_第3頁
第8講自己動手學(xué)習(xí)單片機(jī)系列-鍵盤_第4頁
第8講自己動手學(xué)習(xí)單片機(jī)系列-鍵盤_第5頁
已閱讀5頁,還剩30頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、第8講 輸入-鍵盤主講:王澤華 電話島科技大學(xué)這一章剛做好,為了做出一個不管單鍵還是矩陣鍵盤都能用的狀態(tài)機(jī)消抖,費(fèi)了點(diǎn)功夫。同時對第6講的LCD添加了一個顯示單字符的函數(shù)。 2013.1.31本章重點(diǎn)一般鍵盤消抖方法狀態(tài)機(jī)的概念鍵盤狀態(tài)機(jī)鍵盤矩陣材料清單+5V電源最小系統(tǒng)板液晶顯示板小按鍵17個(用作鍵盤),萬能版1塊圓孔插座(2.54)若干,排線若干,焊錫若干,面包板跳線若干。鍵盤連接電路當(dāng)按鍵少,I/O口資源不緊張時,可采用一個按鍵占用一個I/O口的連接方式。如圖,此時只要將該口設(shè)為輸入,內(nèi)部上拉電阻使能(DDRXn,PORTXn)=(0,1)即可。一旦按鍵按下,

2、電平被拉到低電平,按鍵松開的時候,引腳電平為高。所以只需讀寄存器PINXn的電平可判斷按鍵是否按下。掃描端口引腳電平的函數(shù)中代碼可以這樣寫:unsigned char key_scan()DDRX &= 0 xFE; /PX0輸入PORTX |= 0 x01; /上拉電阻使能if(PINX & 0 x01) /若為真,無鍵閉合 return(0);else/有鍵閉合 return(1);當(dāng)按鍵多,例如16個按鍵,此時采用上述連接方式會占用16個I/O口資源??刹捎镁仃嚪绞?。如圖,這樣只占用8個I/O口。鍵盤掃描方法: 和單鍵掃描一致,有鍵閉合返回非零;無鍵閉合返回0。(1)初步確定有無按鍵:P

3、X0-PX3輸入,上拉電阻使能,這樣這4個腳是高電平(0 x0F);PX4-PX7輸出低電平。讀PX0- PX3口引腳電平,一旦有鍵閉合,引腳電平不再是0 x0F。(2)行掃描法確定哪一個鍵閉合:掃描第1行:PX7-PX4送出0b1110,拉低第一行電平,其它三行電平為高,讀PX3-PX0。若第1行若無鍵閉合,讀出的數(shù)據(jù)為0b1111。有鍵閉合,例如第1列閉合,讀出的數(shù)據(jù)為0b1110;同樣第2列有鍵閉合,讀出的數(shù)據(jù)為0b1101;若讀出的數(shù)據(jù)為0b1011;表示第三列有鍵閉合;0b0111表示第4列有鍵閉合若要掃描第2行,PX7-PX4送出0b1101,拉低第2行電平;同樣,送出0b1011

4、和0b0111可掃描第3行和第4行。(3)value_row高4位存儲行掃描碼,value_col低4位存儲讀取碼,做運(yùn)算value_key = (value_row & 0 xF0) + (value_col & 0 x0F);在只有單鍵閉合的情況下,value_key的取值與鍵閉合對應(yīng)如圖所示掃描代碼可以這樣寫:unsigned char key_scan()int i;unsigned char value_key, value_row, value_col;value_key = 0 x00;/缺省無鍵閉合key_DDR = 0 xF0;/高四位輸出,低四位輸入。key_PORT =

5、0 x0F;/高四位輸出低電平,低四位上拉電阻能_NOP();value_col = key_PIN & 0 x0F;/讀列if(value_col != 0 x0F)/有按鍵閉合value_row = 0 xEF;for(i=0;i4;i+)/掃描第i行key_PORT = value_row & 0 xF0;/第i行電平拉低_NOP();value_col = key_PIN & 0 x0F; if(value_col) != 0 x0F)/第一行各列有鍵按下 switch(value_col)case 0b00001110:/第一列按鍵case 0b00001101:/第二列按鍵case

6、 0b00001011:/第三列按鍵case 0b00000111:/第四列按鍵 value_key = (value_row & 0 xF0) + value_col); break;default value_key = 0; break; value_row = 1; /移位,掃描其余各行 return(value_key);鍵盤電路的焊接u本章現(xiàn)在1只獨(dú)立按鍵實(shí)現(xiàn)所有程序,然后由淺如深的拓展到鍵盤矩陣。所用到的鍵盤焊接如圖,左面是焊接正面圖,右面是焊接反面圖。按鍵消抖為什么要消抖為什么要消抖:通常鍵盤所用為機(jī)械彈性開關(guān),在按下和彈起的瞬間伴隨一系列抖動。為確保CPU對一次閉合僅做一次處

7、理,必須對鍵盤的抖動進(jìn)行消抖處理。一般來說,前沿和后沿抖動時間大約在5-10ms。一般鍵盤消抖的思路一般鍵盤消抖的思路:一旦檢測到有鍵按下時,延時10ms,跳過前沿抖動,再次檢測,仍然檢測到該鍵按下,則認(rèn)為是有效按鍵;檢測到該鍵釋放后,延時10ms,再檢測,該鍵仍在釋放狀態(tài);則認(rèn)為完成了一次完整的按鍵。假定鍵盤掃描程序?yàn)閗ey_scan(),有鍵按下返回鍵值;無鍵按下返回0。定義一個鍵盤消息結(jié)構(gòu)struct sMsg_Keyint value ;/有鍵,存儲鍵值int state;/存儲當(dāng)前鍵狀態(tài),按/下為1彈起為0;struct sMsg_Key msg_key;int keyDelay_D

8、ither(const int key_value)/key_value為key_scan() 返回值int tmp;if(key_value)/key_value!=0,有鍵按下執(zhí)行以下程序; 前沿消抖_delay_ms(10);/延時10ms去掉抖動前沿if(key_value = key_scan()/若兩次按鍵相等 msg_key.value = key_value;/返回鍵值msg_key.state = 1;/標(biāo)記鍵盤在按下狀態(tài)return(0);else if(msg_key.state = 1) /鍵沒有釋放,檢測到釋放;后沿消抖_delay_ms(10);/延時10ms去掉抖

9、動后沿tmp = msg_key.value;PA0接一只小按鍵到地;PB0接LED發(fā)光二極管。按下按鍵松手后LED兩0.2s,其它時間熄滅。來檢驗(yàn)以上鍵盤處理程序是否能用。#define F_CPU 8000000UL#include#include/定義鍵盤使用的端口PA0#define key_DDR DDRA#define key_PORT PORTA#define key_PIN PINA#define _NOP() _asm_ _volatile_(nop:)struct sMsg_Keyint value ;/有鍵,存儲鍵值int state;/存儲當(dāng)前鍵狀態(tài),按下為1彈起為0;

10、struct sMsg_Key msg_key;int key_scan()key_DDR = 0 x00;key_PORT |= 0 xFF;/ PA0輸入內(nèi)部上拉,PA0腳高電平,一旦按鍵按下,PA變?yōu)榈碗娖絖NOP();if(key_PIN & 0 x01) = 0)/有鍵按下return(1);/返回PA0端口值else /無鍵按下return(0);msg_key.state = 0;/標(biāo)記按鍵釋放msg_key.value =0;/按鍵值清零return(tmp);/返回鍵值else /一直無鍵按下msg_key.state = 0;/標(biāo)記按鍵釋放msg_key.value =0;

11、/按鍵值清零return(0);/上一頁的鍵盤處理int key_process(int)粘貼到此處int main(void)int key_value, key_release;/led使用PB0,端口輸出DDRB |= 0 x01;while(1)key_value = key_scan();/掃描key_release = keyDelay_Dither(key_value);/鍵盤延時消抖if(key_release)/鍵釋放PORTB |= 0 x01;/點(diǎn)亮LED,200ms_delay_ms(200);else/其它時間,LED熄滅PORTB &= 0 xFE;return(0

12、);狀態(tài)機(jī)(FSM)狀態(tài)機(jī)研究的起因:狀態(tài)機(jī)最早應(yīng)用于時序邏輯電路的設(shè)計(jì)中,在時鐘信號的控制下接收事件輸入,進(jìn)行狀態(tài)遷移,并執(zhí)行相應(yīng)操作?,F(xiàn)在這一思想被借鑒到程序設(shè)計(jì)中。傳統(tǒng)應(yīng)用程序的控制流程基本是順序的,遵循事先設(shè)定的邏輯,從頭到尾地執(zhí)行。很少有事件能改變標(biāo)準(zhǔn)執(zhí)行流程。 缺點(diǎn)不足以應(yīng)對相對復(fù)雜的控制;另一類應(yīng)用程序由外部事件(可能發(fā)生也可能不發(fā)生)來驅(qū)動,事件在應(yīng)用程序之外生成,無法由應(yīng)用程序或程序員來控制。具體需要執(zhí)行的代碼取決于接收到的事件,或者它相對于其他事件的抵達(dá)時間。所以,控制流程既不能是順序的,也不能是事先設(shè)定好的,因?yàn)樗蕾囉谕獠渴录?。狀態(tài)機(jī)是對具有邏輯順序和時序規(guī)律的事件的

13、一種描述方法。狀態(tài)機(jī)三要素:輸入(事件);狀態(tài);輸出(執(zhí)行操作)理解狀態(tài)機(jī)舉例:狀態(tài)機(jī)分類:按狀態(tài)個數(shù),有限狀態(tài)機(jī):狀態(tài)數(shù)有限個無限狀態(tài)機(jī):狀態(tài)數(shù)無限個。輸出是否與輸入有關(guān)moore狀態(tài)機(jī):輸出僅與當(dāng)前狀態(tài)有關(guān),與輸入無關(guān)melay狀態(tài)機(jī):輸出不僅與當(dāng)前狀態(tài)有關(guān),還與輸入有關(guān)狀態(tài)機(jī)實(shí)現(xiàn)按鍵消抖n主要實(shí)現(xiàn)兩個功能n按鍵消抖n鍵盤釋放時返回按鍵值n按鍵狀態(tài)機(jī)三要素n輸入:通常作為狀態(tài)機(jī)函數(shù)的輸入?yún)?shù)。此處該輸入?yún)?shù)每隔20ms的鍵盤掃描key_scan()。n狀態(tài):無鍵按下狀態(tài);有鍵按下狀態(tài);有效按鍵狀態(tài);鍵釋放狀態(tài)n輸出:通常作為函數(shù)的返回值。除鍵釋放狀態(tài)返回鍵值外(第二個功能),其它的各個狀態(tài)

14、返回0。狀態(tài)圖:不考慮長按鍵狀態(tài)和連續(xù)按鍵狀態(tài)#define State_NoKey0/無鍵按下狀態(tài)#define State_KeyPress1/有鍵按下狀態(tài)#define State_ValidKey2/有效按鍵狀態(tài)#define State_KeyRelease3/鍵盤釋放狀態(tài)int State_Key = State_NoKey;/鍵狀態(tài),初始為無鍵按下狀態(tài) char Fsm_KeyDither(char event_trig) static char f_key_release;static char key_value;switch(State_Key)case State_NoK

15、ey:if(event_trig) /key_scan!=0,轉(zhuǎn)到有鍵按下狀態(tài) State_Key = State_KeyPress;else/key_scan=0,在無鍵狀態(tài)下循環(huán) State_Key = State_NoKey;f_key_release = 0;key_value = 0;break;case State_KeyPress:if(event_trig) /key_scan!=0,轉(zhuǎn)到有效按鍵狀態(tài) State_Key = State_ValidKey;else/key_scan=0,無效按鍵,轉(zhuǎn)無鍵狀態(tài)State_Key = State_NoKey;f_key_releas

16、e = 0;key_value = 0;break;case State_ValidKey:if(event_trig) /key_scan!=0,在狀態(tài)中循環(huán),存儲鍵值 State_Key = State_ValidKey;key_value = event_trig;else/key_scan=0,轉(zhuǎn)鍵釋放狀態(tài)State_Key = State_KeyRelease;f_key_release = 0;break;case State_KeyRelease:if(event_trig) /key_scan!=0,有新的按鍵 State_Key = State_KeyPress;else/k

17、ey_scan=0,轉(zhuǎn)無鍵按下狀態(tài)State_Key = State_NoKey;f_key_release = 1;/一次按鍵完成break;default:/其它未考慮的情況。key_value = 0;f_key_release = 0;break;if(f_key_release)/鍵釋放,返回鍵值 return(key_value);else /否則返回0值 return(0);PA0接一只小按鍵到地;PB0接LED發(fā)光二極管。按下按鍵后LED點(diǎn)亮,再一次按鍵LED熄滅;重復(fù)按鍵,重復(fù)以上步驟。來檢驗(yàn)以上鍵盤處理程序是否能用。#define F_CPU 8000000UL#inclu

18、de#include#include/定義鍵盤使用的端口PA0#define key_DDR DDRA#define key_PORT PORTA#define key_PIN PINA#define _NOP() _asm_ _volatile_(nop:)#define State_NoKey0#define State_KeyPress1#define State_ValidKey2#define State_KeyRelease3int State_Key = State_NoKey;/鍵狀態(tài),初始為無鍵按下狀態(tài) volatile int value_keyscan;/掃描到的鍵值ch

19、ar key_scan()key_DDR &= 0 xfe;key_PORT |= 0 x01;/ PA0輸入,內(nèi)部上拉,這樣PA0引腳高電平/按鍵按下,PA變?yōu)榈碗娖絖NOP();if(key_PIN & 0 x01)/無鍵按下返回0return(0);else /有鍵按下返回1return(1);/前面定義的Fsm_KeyDither鍵盤狀態(tài)機(jī)處理程序粘貼到此處。ISR(TIMER0_OVF_vect) TCNT0 = 256 - F_CPU* 0.015/1024 ;/重載定時器 value_keyscan = key_scan();/鍵盤掃描 int main(void)_delay_

20、ms(500);int key_counter = 0;/設(shè)定定時器中斷DDRB |= 0 x01;/PB0輸出,其它位保持原狀態(tài)TIMSK = 0 x01;/允許TIMER0溢出中斷TCNT0 = 256 - F_CPU * 0.015/1024;/設(shè)定時間TCCR0 = 0 x05;/設(shè)定分頻系數(shù),啟動定時器sei();/開全局中斷while(1)if(Fsm_KeyDither(value_keyscan)key_counter+;if(key_counter % 2)PORTB |= 0 x01;elsePORTB &= 0 xFE;return(0); LCD1602顯示矩陣鍵盤按鍵

21、LCD1602接口PB0-PB7接DB0-DB7PC0(RS),PC1(RW),PC2(E)鍵盤接口PA0,PA1,PA2,PA3連接1-4列PA4,PA5,PA6,PA7連接1-4行實(shí)現(xiàn)功能:在LCD1602顯示所按下的鍵。Key_scan()函數(shù)返回值與鍵對應(yīng)關(guān)系見圖,其中CLR是清屏。分析:鍵盤顯示程序采用液晶部分,接口完全相同,各子程序不需改動;鍵盤掃描見本章,由于矩陣鍵盤的返回值和單鍵盤的返回值意義相同,狀態(tài)機(jī)消抖函數(shù)兩者通用。代碼如下:#define F_CPU 8000000UL#include #include #include #include #include #defin

22、e _NOP() _asm_ _volatile_(nop:)/*/LCD定義/*/ #define clear_scr 0 x01/清屏 #define cursor_return 0 x02/光標(biāo)回左上角 #define data_cur_right 0 x06/數(shù)據(jù)寫入光標(biāo)右移,AC+1 #define disp_on 0 x0C/顯示開 #define disp_off 0 x08/顯示關(guān) #define cursor_right 0 x14/整體顯示,光標(biāo)右移,AC+1 #define disp_line 0 x38/兩行顯示,5*7點(diǎn)陣/LCD控制端口定義#define LCD_C

23、TRL_PORT PORTC#define LCD_CTRL_DDR DDRC/LCD數(shù)據(jù)端口定義#define LCD_PORT PORTB#define LCD_PIN PINB #define LCD_DDR DDRB / LCD控制功能定義 #define RS_0() LCD_CTRL_PORT &= 0 xFE#define RS_1() LCD_CTRL_PORT |= 0 x01#define RW_0() LCD_CTRL_PORT &= 0 xFD#define RW_1() LCD_CTRL_PORT |= 0 x02#define EN_0() LCD_CTRL_POR

24、T &= 0 xFB#define EN_1() LCD_CTRL_PORT |= 0 x04/定義鍵盤口#define key_DDR DDRA#define key_PORT PORTA#define key_PIN PINA/按鍵四狀態(tài)#define State_NoKey0#define State_KeyPress1#define State_ValidKey2#define State_KeyRelease3int State_Key = State_NoKey; /鍵狀態(tài),初始為無鍵按下狀態(tài) volatile unsigned char value_keyscan;/掃描到的鍵值

25、/本章矩陣鍵盤掃描函數(shù)key_scan()放于此處/本章鍵盤狀態(tài)機(jī)函數(shù)放于此處/鍵盤掃描返回值對應(yīng)按鍵函數(shù)unsigned char key_process(unsigned char key_value)unsigned char key_x;switch(key_value)case 0 x11:/檢測到第1行第1列按鍵key_x = 0 x43;/C的Ascii碼,清屏指令 break;case 0 x12:/檢測到第1行第2列按鍵key_x = 0 x31;/1的Ascii碼break;case 0 x14:/檢測到第1行第3列按鍵key_x = 0 x32;/2的Ascii碼brea

26、k;case 0 x18:/檢測到第1行第4列按鍵key_x = 0 x2B;/+的Ascii碼break;case 0 x21:/檢測到第2行第1列按鍵key_x = 0 x33;/3的Ascii碼break;case 0 x22:/檢測到第2行第2列按鍵key_x = 0 x34;/4的Ascii碼break;case 0 x24:/檢測到第2行第3列按鍵key_x = 0 x35;/5的Ascii碼break;case 0 x28:/檢測到第2行第4列按鍵key_x = 0 x2D;/+的Ascii碼break;case 0 x41:/檢測到第3行第1列按鍵key_x = 0 x36;/6的Ascii碼break;case 0 x42:/檢測到第3行第2列按鍵key_x = 0 x37;/7的Ascii碼break;case 0 x44:/檢測到第3行第3列按鍵key_x = 0 x38;/8的Ascii碼break;case 0 x48:/檢測到第3行第4列按鍵key_x = 0 x78;/X的Ascii碼break;case 0 x81:/檢測到第4行第1列按鍵key_x = 0 x39;/9的Ascii碼break;case 0 x82:/檢測到第4行第2列按鍵key_x

溫馨提示

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

最新文檔

評論

0/150

提交評論