Proteus仿真:行列式键盘
生活随笔
收集整理的這篇文章主要介紹了
Proteus仿真:行列式键盘
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
實現目標
使用兩部掃描法,若有鍵按下,返回按下鍵的位置;若無鍵按下,返回0xff。每10ms定時檢測一次按鍵,使用定時器中斷實現定時。
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);//延時單位:ms#define KEY_PORT P1 /*按鍵接在KEY_PORT口*/ uchar key_Value=0xff; /*存放鍵值*/ uchar keyscan(void);/**掃描按鍵函數-2步判別掃描法 **/ void Key_process(void);/*鍵值處理程序*//******** main 函數 *********/ void main (void) { initUart(); /* 初始化串口 */TMOD=0x10; /* 設置定時器1為工作方式1 */ TH1=-10000>>8;TL1=-10000 % 256;/* 定時器1每10000計數脈沖發生1次中斷,12MHz晶振,定時時間10000us */TCON=0x40; /* 內部脈沖計數 */IE=0x88; /*打開定時器中斷*/ key_Value=0xff;do {/* 如果key_Value!=0xff 說明有鍵按下 那么就可以根據此時的key_Value使用key_process函數判斷是哪一個按鍵被按下 并輸出 */if (key_Value!=0xff) Key_process();}while(TRUE); }/******* 定時器/計數器1中斷服務程序 ***/ void timer1int(void) interrupt 3 { /******* 每10ms產生一次中斷 每次中斷進行鍵盤掃描 ***/EA=0;/* 關總中斷 */TR1=0;/*停止計數*/ TH1=-10000>>8;TL1=-10000 % 256;/* 定時器1每10000計數脈沖發生1次中斷,12MHz晶振,定時時間10000us */TR1=1;/*啟動計數*/key_Value= keyscan();EA=1;/* 開總中斷 */ } /*****掃描按鍵函數-2步判別掃描法 *****/ uchar keyscan(void)/**掃描按鍵函數-2步判別掃描法 **/ { uchar readkey, rereadkey; uchar x_temp,y_temp;KEY_PORT=0x0f; /*向P1輸出電平 0000 1111 也就是列為低電平 行為高電平 注:這個得看具體連線*/x_temp= KEY_PORT & 0x0f; /*讀取P1的電平情況 并取后四位 得到所有行的電平情況*/if (x_temp==0x0f) return(0xff); /*如果所有行無按鍵按下,說明都為高電平,此時P1電平情況為 0000 111 退出*//*上一步沒有退出 說明有按鍵按下 那么就該進行列掃描*/KEY_PORT=0xf0; /*P1輸出 所有行為低電平 所有列為高電平*/y_temp= KEY_PORT & 0xf0; /*獲取P1端口所有列的電平情況*/readkey = x_temp | y_temp; /*兩者相或*//*為防止鍵的抖動處理 需要進行第二次判斷 若兩次判斷一樣 則確定鍵按下*/time(10); /*延時10ms后再測按鍵*/KEY_PORT=0x0f;x_temp= KEY_PORT & 0x0f;if (x_temp==0x0f) return(0xff); /*無按鍵,退出*/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){ /*根據中斷源分支*//* 按第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)/*初始化串口波特率,使用定時器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*/ } /*********** 延時單位:ms *******************/ void time(unsigned int ucMs)//延時單位:ms {unsigned char j; while(ucMs>0){for(j=0;j<10;j++) delay_100us();ucMs--;} }筆記
思路:
- 為了判斷具體是哪一個鍵被按下,使用了行列兩次掃描
- 首先 讓所有的列輸出低電平 所有行輸出為高電平 即P1輸出0000 1111 (列接的是高四位 行接的是第四位)
- 然后再識別P1低四位即所有行的電平情況
- 若有一行的按鍵被按下 那么有一行的電平就為0
- 假設P1.2那行有按鍵被按下 那么識別到P1的電平情況就是 0000 1011 即 0b(使用變量x_temp=0b)
- 如果沒有按鍵按下 那么就不需要進行列掃描了
- 上述情況若檢測到行有按鍵按下
- 那么就進行列掃描:讓所有列輸出高電平 行輸出低電平 即 1111 0000
- 然后識別P1高四位的電平情況
- 若其中有一列中的按鍵被按下 假設是P1.6那一列有按鍵被按下
- 那么識別到此時P1=1011 0000 即 b0(使用變量y_temp=b0)
- 然后 x_temp與y_temp相或 得到 bb
- 再取反 得到 0x44(十六進制)
- 然后我們可以理解為 當獲得的key_value=44時 那么就是第三行第三列的按鍵被按下
- 同理 其他的按鍵對應的key_value也可以被求出
那么為什么第一次掃描完后,10ms后還要再進行掃描一次呢?
答:這是因為存在鍵位抖動,因為在按下鍵的那一剎那,有一個不穩定的電平,也就是電位抖動,必須要通過軟件或硬件的方法去消除。這里是通過軟件的方法消除的。如果沒有第二次掃描,那么只按一次鍵,程序會識別出按下了多次鍵。如果10ms后,掃描到還是這個鍵,那么才會確定鍵被按下。防止抖動帶來的bug
本文Proteus仿真圖及源程序獲取見:
運行結果
說明
參考課本:單片機原理與嵌入式系統設計
總結
以上是生活随笔為你收集整理的Proteus仿真:行列式键盘的全部內容,希望文章能夠幫你解決所遇到的問題。