Proteus仿真:行列式键盘
生活随笔
收集整理的這篇文章主要介紹了
Proteus仿真:行列式键盘
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
實(shí)現(xiàn)目標(biāo)
使用兩部掃描法,若有鍵按下,返回按下鍵的位置;若無(wú)鍵按下,返回0xff。每10ms定時(shí)檢測(cè)一次按鍵,使用定時(shí)器中斷實(shí)現(xiàn)定時(shí)。
Proteus仿真圖
C51代碼
#include <REG52.H> /* special function register declarations */ #include <intrins.h>#define byte unsigned char #define uchar unsigned char #define word unsigned int #define uint unsigned int #define ulong unsigned long #define BYTE unsigned char #define WORD unsigned int#define TRUE 1 #define FALSE 0void initUart(void);/*初始化串口*/ void time(unsigned int ucMs);//延時(shí)單位:ms#define KEY_PORT P1 /*按鍵接在KEY_PORT口*/ uchar key_Value=0xff; /*存放鍵值*/ uchar keyscan(void);/**掃描按鍵函數(shù)-2步判別掃描法 **/ void Key_process(void);/*鍵值處理程序*//******** main 函數(shù) *********/ void main (void) { initUart(); /* 初始化串口 */TMOD=0x10; /* 設(shè)置定時(shí)器1為工作方式1 */ TH1=-10000>>8;TL1=-10000 % 256;/* 定時(shí)器1每10000計(jì)數(shù)脈沖發(fā)生1次中斷,12MHz晶振,定時(shí)時(shí)間10000us */TCON=0x40; /* 內(nèi)部脈沖計(jì)數(shù) */IE=0x88; /*打開定時(shí)器中斷*/ key_Value=0xff;do {/* 如果key_Value!=0xff 說(shuō)明有鍵按下 那么就可以根據(jù)此時(shí)的key_Value使用key_process函數(shù)判斷是哪一個(gè)按鍵被按下 并輸出 */if (key_Value!=0xff) Key_process();}while(TRUE); }/******* 定時(shí)器/計(jì)數(shù)器1中斷服務(wù)程序 ***/ void timer1int(void) interrupt 3 { /******* 每10ms產(chǎn)生一次中斷 每次中斷進(jìn)行鍵盤掃描 ***/EA=0;/* 關(guān)總中斷 */TR1=0;/*停止計(jì)數(shù)*/ TH1=-10000>>8;TL1=-10000 % 256;/* 定時(shí)器1每10000計(jì)數(shù)脈沖發(fā)生1次中斷,12MHz晶振,定時(shí)時(shí)間10000us */TR1=1;/*啟動(dòng)計(jì)數(shù)*/key_Value= keyscan();EA=1;/* 開總中斷 */ } /*****掃描按鍵函數(shù)-2步判別掃描法 *****/ uchar keyscan(void)/**掃描按鍵函數(shù)-2步判別掃描法 **/ { uchar readkey, rereadkey; uchar x_temp,y_temp;KEY_PORT=0x0f; /*向P1輸出電平 0000 1111 也就是列為低電平 行為高電平 注:這個(gè)得看具體連線*/x_temp= KEY_PORT & 0x0f; /*讀取P1的電平情況 并取后四位 得到所有行的電平情況*/if (x_temp==0x0f) return(0xff); /*如果所有行無(wú)按鍵按下,說(shuō)明都為高電平,此時(shí)P1電平情況為 0000 111 退出*//*上一步?jīng)]有退出 說(shuō)明有按鍵按下 那么就該進(jìn)行列掃描*/KEY_PORT=0xf0; /*P1輸出 所有行為低電平 所有列為高電平*/y_temp= KEY_PORT & 0xf0; /*獲取P1端口所有列的電平情況*/readkey = x_temp | y_temp; /*兩者相或*//*為防止鍵的抖動(dòng)處理 需要進(jìn)行第二次判斷 若兩次判斷一樣 則確定鍵按下*/time(10); /*延時(shí)10ms后再測(cè)按鍵*/KEY_PORT=0x0f;x_temp= KEY_PORT & 0x0f;if (x_temp==0x0f) return(0xff); /*無(wú)按鍵,退出*/KEY_PORT=0xf0;y_temp= KEY_PORT & 0xf0;rereadkey= x_temp + y_temp;if (readkey == rereadkey) { /*2次一致*/return(~rereadkey);}return(0xff); } void Key_process(void)/*鍵值處理程序*/ {switch (key_Value){ /*根據(jù)中斷源分支*//* 按第2行鍵 */case 0x11:printf ("Key(R1,C1) is pressed\n");/* 可在此處插入該按鍵的處理程序 */break;case 0x21:printf ("Key(R1,C2) is pressed\n");/* 可在此處插入該按鍵的處理程序 */break;case 0x41:printf ("Key(R1,C3) is pressed\n");/* 可在此處插入該按鍵的處理程序 */break;case 0x81:printf ("Key(R1,C4) is pressed\n");/* 可在此處插入該按鍵的處理程序 */break;/* 按第2行鍵 */case 0x12:printf ("Key(R2,C1) is pressed\n");/* 可在此處插入該按鍵的處理程序 */break;case 0x22:printf ("Key(R2,C2) is pressed\n");/* 可在此處插入該按鍵的處理程序 */break;case 0x42:printf ("Key(R2,C3) is pressed\n");/* 可在此處插入該按鍵的處理程序 */break;case 0x82:printf ("Key(R2,C4) is pressed\n");/* 可在此處插入該按鍵的處理程序 */break;/* 按第3行鍵 */case 0x14:printf ("Key(R3,C1) is pressed\n");/* 可在此處插入該按鍵的處理程序 */break;case 0x24:printf ("Key(R3,C2) is pressed\n");/* 可在此處插入該按鍵的處理程序 */break;case 0x44:printf ("Key(R3,C3) is pressed\n");/* 可在此處插入該按鍵的處理程序 */break;case 0x84:printf ("Key(R3,C4) is pressed\n");/* 可在此處插入該按鍵的處理程序 */break;/* 按第4行鍵 */case 0x18:printf ("Key(R4,C1) is pressed\n");/* 可在此處插入該按鍵的處理程序 */break;case 0x28:printf ("Key(R4,C2) is pressed\n");/* 可在此處插入該按鍵的處理程序 */break;case 0x48:printf ("Key(R4,C3) is pressed\n");/* 可在此處插入該按鍵的處理程序 */break;case 0x88:printf ("Key(R4,C4) is pressed\n");/* 可在此處插入該按鍵的處理程序 */break;default:break;} } /********** 初始化串口波特率 ************/ void initUart(void)/*初始化串口波特率,使用定時(shí)器2*/ { /* Setup the serial port for 9600 baud at 11.0592MHz */SCON = 0x50; //串口工作在方式1RCAP2H=(65536-(3456/96))>>8;RCAP2L=(65536-(3456/96))%256;T2CON=0x34;TI = 1; /* 置位TI*/ } /*********** 延時(shí)單位:ms *******************/ void time(unsigned int ucMs)//延時(shí)單位:ms {unsigned char j; while(ucMs>0){for(j=0;j<10;j++) delay_100us();ucMs--;} }筆記
思路:
- 為了判斷具體是哪一個(gè)鍵被按下,使用了行列兩次掃描
- 首先 讓所有的列輸出低電平 所有行輸出為高電平 即P1輸出0000 1111 (列接的是高四位 行接的是第四位)
- 然后再識(shí)別P1低四位即所有行的電平情況
- 若有一行的按鍵被按下 那么有一行的電平就為0
- 假設(shè)P1.2那行有按鍵被按下 那么識(shí)別到P1的電平情況就是 0000 1011 即 0b(使用變量x_temp=0b)
- 如果沒有按鍵按下 那么就不需要進(jìn)行列掃描了
- 上述情況若檢測(cè)到行有按鍵按下
- 那么就進(jìn)行列掃描:讓所有列輸出高電平 行輸出低電平 即 1111 0000
- 然后識(shí)別P1高四位的電平情況
- 若其中有一列中的按鍵被按下 假設(shè)是P1.6那一列有按鍵被按下
- 那么識(shí)別到此時(shí)P1=1011 0000 即 b0(使用變量y_temp=b0)
- 然后 x_temp與y_temp相或 得到 bb
- 再取反 得到 0x44(十六進(jìn)制)
- 然后我們可以理解為 當(dāng)獲得的key_value=44時(shí) 那么就是第三行第三列的按鍵被按下
- 同理 其他的按鍵對(duì)應(yīng)的key_value也可以被求出
那么為什么第一次掃描完后,10ms后還要再進(jìn)行掃描一次呢?
答:這是因?yàn)榇嬖阪I位抖動(dòng),因?yàn)樵诎聪骆I的那一剎那,有一個(gè)不穩(wěn)定的電平,也就是電位抖動(dòng),必須要通過軟件或硬件的方法去消除。這里是通過軟件的方法消除的。如果沒有第二次掃描,那么只按一次鍵,程序會(huì)識(shí)別出按下了多次鍵。如果10ms后,掃描到還是這個(gè)鍵,那么才會(huì)確定鍵被按下。防止抖動(dòng)帶來(lái)的bug
本文Proteus仿真圖及源程序獲取見:
運(yùn)行結(jié)果
說(shuō)明
參考課本:單片機(jī)原理與嵌入式系統(tǒng)設(shè)計(jì)
總結(jié)
以上是生活随笔為你收集整理的Proteus仿真:行列式键盘的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 对BOM的总结
- 下一篇: nginx配置php 9000,Ngin