IO 的使用–按鍵
本文主要涉及8051單片機的按鍵的使用,包括獨立按鍵與矩陣按鍵。
其中包括實例分析:
- 獨立按鍵 K1 控制 D1 指示燈亮滅
- 通過數碼管顯示矩陣按鍵 S1-S16 按下后鍵值 0-F
文章目錄
- IO 的使用--按鍵
- 一、按鍵消抖
- 二、獨立按鍵
- 獨立按鍵 K1 控制 D1 指示燈亮滅
- 二、 矩陣按鍵
- 通過數碼管顯示矩陣按鍵 S1-S16 按下后鍵值 0-F
按鍵是一種電子開關,使用時輕輕按開關按鈕就可使開關接通,當松開手時, 開關斷開。
在了解按鍵之前,我們需要先了解一下按鍵消抖
一、按鍵消抖
通常的按鍵所用開關為機械彈性開關,當機械觸點斷開、閉合時,電壓信號
如下圖所示:
由于機械點的彈性作用,按鍵開關在閉合時不會馬上穩定的接通,在斷開時也不會一下子斷開,因而在閉合和斷開的瞬間均伴隨著一連串的抖動。抖動時間的長短由按鍵的機械特性決定的,一般為 5ms 到 10ms。
按鍵消抖有兩種方式,一種是硬件消抖
,另一種是軟件消抖
。為了使電路更加簡單,通常采用軟件消抖。
常用的軟件去抖動方法:
1,先設置 IO 口為高電平(由于開發板 IO 都有上拉電阻,所以默認 IO 為高
電平)。
2,讀取 IO 口電平確認是否有按鍵按下。
3,如有 IO 電平為低電平后,延時幾個毫秒
。
4,再讀取該 IO 電平,如果仍然為低電平,說明按鍵按下。
5,執行按鍵控制程序。
二、獨立按鍵
獨立按鍵電路構成是由各個按鍵的一個管腳連接在一起接地,按鍵其他引腳分別接到單片機 IO 口。
獨立按鍵的原理圖如下:
從上圖中可以看出,4 個獨立按鍵的控制管腳連接到 51 單片機的 P3.0-P3.3腳上
。其中 K1 連接在 P3.1 上,K2 連接在 P3.0 上,K3 連接在 P3.2 上,K4 連接在 P3.3 上。4 個按鍵另一端全部連接在 GND
,當按鍵按下后
,對應 IO 口即為低電平
。
獨立按鍵 K1 控制 D1 指示燈亮滅
#include "reg52.h"
typedef unsigned int u16; //對系統默認數據類型進行重定義
typedef unsigned char u8;
//定義獨立按鍵控制腳
sbit KEY1=P3^1;
sbit KEY2=P3^0;
sbit KEY3=P3^2;
sbit KEY4=P3^3;
//定義 LED1 控制腳
sbit LED1=P2^0;
//使用宏定義獨立按鍵按下的鍵值
#define KEY1_PRESS 1
#define KEY2_PRESS 2
#define KEY3_PRESS 3
#define KEY4_PRESS 4
#define KEY_UNPRESS 0void delay_10us(u16 ten_us)
{
while(ten_us--);
}u8 key_scan(u8 mode)
{static u8 key=1;if(mode)key=1;//連續掃描按鍵if(key==1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0))//任意按鍵按下{delay_10us(1000);//消抖key=0;if(KEY1==0)return KEY1_PRESS;else if(KEY2==0)return KEY2_PRESS;else if(KEY3==0)return KEY3_PRESS;else if(KEY4==0)return KEY4_PRESS;}else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1) //無按鍵按下{key=1;}return KEY_UNPRESS;
}
void main()
{
u8 key=0;
while(1)
{key=key_scan(0);if(key==KEY1_PRESS)//檢測按鍵 K1 是否按下LED1=!LED1;//LED1 狀態翻轉
}
}
key_scan 函數
帶一個形參mode
,該參數用來設定是否連續掃描按鍵
,如果mode為 0
,只能操作一次按鍵
,只有當按鍵松開后才能觸發下次的掃描,這樣做的好處是可以防止按下一次出現多次觸發
的情況。如果mode 為 1
,函數是支持連續掃描的,即使按鍵未松開,在函數內部有 if(mode==1)這條判斷語句,因此 key 始終是等于 1 的,所以可以連續掃描按鍵,當按下某個按鍵,會一直返回這 個按鍵的鍵值,這樣做的好處是可以很方便實現連按操作.
二、 矩陣按鍵
無論是獨立鍵盤還是矩陣鍵盤,單片機檢測其是否被按下的依據都是一樣的,也就是檢測與該鍵對應的 I/O 口是否為低電平
。獨立鍵盤有一端固定為低電平,此種方式編程比較簡單。 而矩陣鍵盤兩端都與單片機 I/O 口相連,因此在檢測時需編程通過單片機 I/O 口送出低電平。檢測方法有多種,最常用的是行列掃描
和線翻轉法
。
行列掃描法檢測時,先送一列為低電平
,其余幾列全為高電平(此時我們確定了列數),然后立即輪流檢測一次各行
是否有低電平,若檢測到某一行為低電平(這時我們又確定了行數),則我們便可確認當前被按下的鍵是哪一行哪一列的,用同樣方法輪流送各列一次低電平,再輪流檢測一次各行是否變為低電平,這樣即可檢測完所有的按鍵,當有鍵被按下時便可判斷出按下的鍵是哪一個鍵。當然我們也可以將行線置低電平,掃描列是否有低電平。從而達到整個鍵盤的檢測。
線翻轉法,就是使所有行線為低電平時
,檢測所有列線是否有低電平,如果有,就記錄列線值;然后再翻轉,使所有列線都為低電平,檢測所有行線的值,由于有按鍵按下,行線的值也會有變化,記錄行線的值。從而就可以檢測到全部按鍵。
4*4 矩陣按鍵引出的 8 根控制線直接連接到 51 單片機的P1 口上。電路中的 P17 連接矩陣鍵盤的第 1 行,P13 連接矩陣鍵盤第 1 列
通過數碼管顯示矩陣按鍵 S1-S16 按下后鍵值 0-F
#include "reg52.h"
typedef unsigned int u16; //對系統默認數據類型進行重定義
typedef unsigned char u8;
#define KEY_MATRIX_PORT P1 //使用宏定義矩陣按鍵控制口
#define SMG_A_DP_PORT P0 //使用宏定義數碼管段碼口
//共陰極數碼管顯示 0~F 的段碼數據
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};void delay_10us(u16 ten_us)
{while(ten_us--);
}
//行列式掃描方式
u8 key_matrix_ranks_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;case 0xb7: key_value=5;break;case 0xd7: key_value=9;break;case 0xe7: key_value=13;break;}}while(KEY_MATRIX_PORT!=0xf7);//等待按鍵松開KEY_MATRIX_PORT=0xfb;//給第二列賦值 0,其余全為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;//給第三列賦值 0,其余全為 1if(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;//給第四列賦值 0,其余全為 1if(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;
}//線翻轉式掃描方式
u8 key_matrix_flip_scan(void)
{
static u8 key_value=0;
KEY_MATRIX_PORT=0x0f;//給所有行賦值 0,列全為 1
if(KEY_MATRIX_PORT!=0x0f)//判斷按鍵是否按下
{delay_10us(1000);//消抖if(KEY_MATRIX_PORT!=0x0f)
{
//測試列
KEY_MATRIX_PORT=0x0f;
switch(KEY_MATRIX_PORT)//保存行為 0,按鍵按下后的列值
{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;
switch(KEY_MATRIX_PORT)//保存列為 0,按鍵按下后的鍵值
{case 0x70: key_value=key_value;break;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);//等待按鍵松開}}elsekey_value=0;return key_value;
}void main()
{
u8 key=0;
while(1)
{
key=key_matrix_ranks_scan();
if(key!=0)
SMG_A_DP_PORT=gsmg_code[key-1];//得到的按鍵值減 1 換算成數組下標
對應 0-F 段碼
}
}