矩阵按键实验
矩陣按鍵簡介
? ? ? ??以 4*4 矩陣鍵盤為例。 16 個按鍵被排成 4 行 4 列,第一行將每個按鍵的一端連接在一起構成行線,第一列將每個按鍵的另一端連接在一起構成列線,這樣便一共有 4 行 4 列共 8 根線,如圖所示:
? ? ? ??將這 8 根線連接到單片機的 8 個 I/O 口上,通過程序掃描鍵盤就可檢測 16 個鍵。用這種方法也可實現 3 行 3 列 9 個鍵、 5 行 5 列 25 個鍵、 6 行 6 列 36 個鍵甚至更多。
? ? ? ??無論是獨立鍵盤還是矩陣鍵盤,單片機檢測其是否被按下的依據都一樣,即檢測與該鍵對應的 I/O 口是否為低電平。獨立鍵盤有一端固定為低電平,此種方式編程比較簡單。 而矩陣鍵盤兩端都與單片機 I/O 口相連,因此在檢測時需編程通過單片機 I/O 口送出低電平。檢測方法有多種,最常用的是行列掃描和線翻轉法。
? ? ? ??行列掃描法,檢測時,先送一列為低電平,其余幾列全為高電平(確定列數),然后立即輪流檢測一次各行是否有低電平,若檢測到某一行為低電平(確定行數),則便可確認當前被按下的鍵是哪一行哪一列 的,用同樣方法輪流送各列一次低電平,再輪流檢測一次各行是否變為低電平, 這樣即可檢測完所有的按鍵,當有鍵被按下時便可判斷出按下的鍵是哪一個鍵。 當然,也可以將行線置低電平,掃描列是否有低電平,從而達到整個鍵盤的檢測。
? ? ? ??線翻轉法,就是使所有行線為低電平時,檢測所有列線是否有低電平,如果有,就記錄列線值;然后再翻轉,使所有列線都為低電平,檢測所有行線的值, 由于有按鍵按下,行線的值也會有變化,記錄行線的值。從而就可以檢測到全部按鍵。
? ? ? ? 同時,矩陣鍵盤也少不了按鍵消抖的環節,此處采用行列掃描法來檢測哪個按鍵按下。
硬件部分
? ? ? ? 使用到硬件資源如下:
? ? ? ? 靜態數碼管模塊電路在靜態數碼管實驗中有介紹,此處不多做贅述。矩陣按鍵模塊電路如下圖所示:
? ? ? ? 由圖可知,該模塊電路獨立,4*4 矩陣按鍵引出的 8 根控制管腳并未直接連接到 51 單片機的 IO 上,而是連接到 JP3 端子上。電路中的 ARRAY_H1 表示矩陣鍵盤第 1 行,ARRAY_L1 表示矩陣鍵盤第 1 列。
源代碼
? ? ? ? 核心代碼為 key_matrix_ranks_scan 函數和 key_matrix_flip_scan 函數,前者是使用行列式掃描方式實現,而后者是使用線翻轉式掃描方式實現, 實現功能一致,二者可選其一。
行列式
? ? ? ? 行列式掃描原理比較簡單,與獨立式按鍵操作類似,即給每一列賦值 0,此時的矩陣按鍵就被分割成獨立按鍵,然后再判斷每一列中的按鍵按下情況,并返回對應的鍵值。如此循環 4 組,就可將 4 列 4 行按鍵按下鍵值全部得到。
? ? ? ?源代碼如下所示:
#include "reg52.h"typedef unsigned int u16;//使用關鍵字 typedef 對系統默認數據類型 unsigned int 重新命名 typedef unsigned char u8;#define KEY_MATRIX_PORT P1 //使用宏定義矩陣按鍵控制口 #define SMG_A_DP_PORT P0 //使用宏定義數碼管段碼口/*共陰極數碼管顯示0~F的段碼數據*/ u8 gysmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};void delay_10us(u16 ten_us)//延時函數,ten_us=1 時,大約延時 10us {while(ten_us--); }u8 KEY_MATRIX_RANK_SCAN(void) {u8 key_value=0;//定義一個返回給主函數,代表按下按鍵的數 /*判斷第一列*/KEY_MATRIX_PORT=0xf7; //給第一列賦值0,其余列全為1if(KEY_MATRIX_PORT!=0xf7) //判斷第一列按鍵是否按下{delay_10us(1000); //消抖switch(KEY_MATRIX_PORT)//判斷是哪一行按鍵按下,并返回按鍵對應的鍵值{case 0x77:key_value=1;break; //返回第一個按鍵,即:1case 0xb7:key_value=5;break; //返回第二個按鍵,即:2case 0xd7:key_value=9;break;case 0xe7:key_value=13;break;}}while(KEY_MATRIX_PORT!=0xf7);//等待按鍵松開/*判斷第二列*/KEY_MATRIX_PORT=0xfb;if(KEY_MATRIX_PORT!=0xfb){delay_10us(1000);switch(KEY_MATRIX_PORT){case 0x7b:key_value=2;break;case 0xbb:key_value=6;break;case 0xdb:key_value=10;break;case 0xeb:key_value=14;break;}}while(KEY_MATRIX_PORT!=0xfb);//等待按鍵松開/*判斷第三列*/KEY_MATRIX_PORT=0xfd;if(KEY_MATRIX_PORT!=0xfd){delay_10us(1000);switch(KEY_MATRIX_PORT){case 0x7d:key_value=3;break;case 0xbd:key_value=7;break;case 0xdd:key_value=11;break;case 0xed:key_value=15;break;}}while(KEY_MATRIX_PORT!=0xfd);//等待按鍵松開/*判斷第四列*/KEY_MATRIX_PORT=0xfe;if(KEY_MATRIX_PORT!=0xfe){delay_10us(1000);switch(KEY_MATRIX_PORT){case 0x7e:key_value=4;break;case 0xbe:key_value=8;break;case 0xde:key_value=12;break;case 0xee:key_value=16;break;}}while(KEY_MATRIX_PORT!=0xfe);//等待按鍵松開return key_value; }void main(void) //主函數 { u8 key=0;//定義一個變量來接收KEY_MATRIX_RANK_SCAN()函數的返回值 while(1) //行列式掃描函數在無限循環中持續掃描{key=KEY_MATRIX_RANK_SCAN();//函數調用,并返回按下按鍵所對應的數if(key!=0) //有按鍵按下SMG_A_DP_PORT=~gysmg_code[key-1];//減1,是因為數組元素下標是從0開始的} }?線翻轉式
? ? ? ? 線翻轉式掃描可以先確定行,后確定列,可以先確定列,再確定行,方法是一樣的。難以理解的朋友可以腦中先確定一個按鍵按下(比如第2行,第3列的鍵值為7的按鍵)帶入程序中理解,程序有詳細的注釋。
#include "reg52.h"typedef unsigned int u16;//使用關鍵字 typedef 對系統默認數據類型 unsigned int 重新命名 typedef unsigned char u8;#define KEY_MATRIX_PORT P1 //使用宏定義矩陣按鍵控制口 #define SMG_A_DP_PORT P0 //使用宏定義數碼管段碼口/*共陰極數碼管顯示0~F的段碼數據*/ u8 gysmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};void delay_10us(u16 ten_us)//延時函數,ten_us=1 時,大約延時 10us {while(ten_us--); }u8 KEY_MATRIX_FLIP_SCAN(void) {static u8 key_value=0; //定義一個返回主函數,代表第幾個按鍵的值KEY_MATRIX_PORT=0x0f; //給所有行賦值0,列全為1if(KEY_MATRIX_PORT!=0x0f) //判斷按鍵是否按下,若按下,則KEY_MATRIX_PORT不等于0x0f{delay_10us(1000); //消抖if(KEY_MATRIX_PORT!=0x0f) //若KEY_MATRIX_PORT!=0x0f,則確定按鍵已按下,且消抖了,開始測試按鍵的行列{/*測試列*/KEY_MATRIX_PORT=0x0f; //再次設置所有行賦值0,列全為1switch(KEY_MATRIX_PORT) //通過匹配case的值,確定按下的按鍵在那一列{case 0x07:key_value=1;break; //在第一列case 0x0b:key_value=2;break; //在第二列case 0x0d:key_value=3;break; //在第三列case 0x0e:key_value=4;break; //在第四列}/*測試行*/KEY_MATRIX_PORT=0xf0; //設置所有行賦值1,列全為0switch(KEY_MATRIX_PORT) //匹配case的值,確定按下的按鍵在那一行{case 0x70:key_value=key_value;break; //在第一行,并返回行列所對應的鍵值(即16個按鍵中的第幾個)case 0xb0:key_value=key_value+4;break; //在第二行,并返回行列所對應的鍵值case 0xd0:key_value=key_value+8;break; //在第三行,并返回行列所對應的鍵值case 0xe0:key_value=key_value+12;break; //在第四行,并返回行列所對應的鍵值}while(KEY_MATRIX_PORT!=0xf0);//等待按鍵松開,松開之前KEY_MATRIX_PORT不等于0xf0,會一直在while中循環}}else //按鍵沒有按下key_value=0;return key_value; }void main(void) //主函數 { u8 key=0;//定義一個變量來接收KEY_MATRIX_RANK_SCAN()函數的返回值 while(1) //行列式掃描函數在無限循環中持續掃描{key=KEY_MATRIX_FLIP_SCAN();//函數調用,并返回按下按鍵所對應的數if(key!=0) //判斷是否有按鍵按下SMG_A_DP_PORT=~gysmg_code[key-1];//減1,是因為數組元素下標是從0開始的} }? 現象
?
?? ? ? ? ?按下矩陣按鍵模塊中相應按鍵,靜態數碼管顯示按鍵所對應的0~F值。所圖所示:
? ? ? ? ?
總結
- 上一篇: MeshBaker插件 使用套路
- 下一篇: 分享一个超好看回忆相册(代码自取)