一、基本知識
1. 按鍵分類與輸入原理
按鍵按照結構原理科分為兩類枢劝,一類是觸點式開關按鍵井联,如機械式開關、導電橡膠式開關燈您旁;另一類是無觸點式開關按鍵烙常,如電氣式按鍵,磁感應按鍵等鹤盒。前者造價低蚕脏,后者壽命長。目前侦锯,微機系統(tǒng)中最常見的是觸點式開關按鍵驼鞭。
在單片機應用系統(tǒng)中,除了復位按鍵有專門的復位電路及專一的復位功能外率触,其他按鍵都是以開關狀態(tài)來設置控制功能或輸入數(shù)據(jù)的终议。當所設置的功能鍵或數(shù)字鍵按下時,計算機應用系統(tǒng)應完成該按鍵所設定的功能葱蝗,鍵信息輸入時與軟件結構密切相關的過程穴张。
對于一組鍵或一個鍵盤,總有一個接口電路與CPU相連两曼。CPU可以采用查詢或中斷方式了解有無將按鍵輸入皂甘,并檢查是哪一個按鍵按下,將該鍵號送入累加器悼凑,然后通過跳轉指令轉入執(zhí)行該鍵的功能程序偿枕,執(zhí)行完成后再返回主程序。
2. 按鍵結構與特點
微機鍵盤通常使用機械觸點式按鍵開關户辫,其主要功能式把機械上的通斷轉換為電氣上的邏輯關系渐夸。也就是說,它能提供標準的TTL邏輯電平渔欢,以便于通用數(shù)字系統(tǒng)的邏輯電平相容墓塌。機械式按鍵再按下或釋放時,由于機械彈性作用的影響奥额,通常伴隨有一定的時間觸點機械抖動苫幢,然后其觸點才穩(wěn)定下來。
其抖動過程如圖1所示垫挨,抖動時間的長短與開關的機械特性有關韩肝,一般為5-10ms。在觸點抖動期間檢測按鍵的通與斷九榔,可能導致判斷出錯哀峻,即按鍵一次按下或釋放錯誤的被認為是多次操作涡相,這種情況是不允許出現(xiàn)的。為了克服按鍵觸點機械抖動所致的檢測誤判谜诫,必須采取消抖措施漾峡。按鍵較少時,可采用硬件消抖喻旷;按鍵較多式生逸,采用軟件消抖。
3. 獨立按鍵與矩陣鍵盤
(1)獨立按鍵
單片機控制系統(tǒng)中且预,如果只需要幾個功能鍵槽袄,此時,可采用獨立式按鍵結構锋谐。
獨立按鍵式直接用I/O口線構成的單個按鍵電路遍尺,其特點式每個按鍵單獨占用一根I/O口線,每個按鍵的工作不會影響其他I/O口線的狀態(tài)涮拗。獨立按鍵的典型應用如圖所示乾戏。獨立式按鍵電路配置靈活,軟件結構簡單三热,但每個按鍵必須占用一個I/O口線鼓择,因此,在按鍵較多時就漾,I/O口線浪費較大呐能,不宜采用。獨立按鍵如圖2所示抑堡。
獨立按鍵的軟件常采用查詢式結構摆出。先逐位查詢與I/O口線的輸入狀態(tài),如某一根I/O口線輸入為低電平首妖,則可確認該I/O口線所對應的按鍵已按下偎漫,然后,再轉向該鍵的功能處理程序有缆。
(2) 關于上拉電阻
單片機按鍵一般通過配備上拉電阻來實現(xiàn)輸入端高低電平的切換骑丸。
4條輸入線接到單片機的IO口上,當按鍵K1按下時妒貌,+5V通過電阻R1然后再通過按鍵K1最終進入GND形成一條通路,那么這條線路的全部電壓都加到了R1這個電阻上铸豁,KeyIn1這個引腳就是個低電平灌曙。當松開按鍵后,線路斷開节芥,就不會有電流通過在刺,那么KeyIn1和+5V就應該是等電位逆害,是一個高電平。我們就可以通過KeyIn1這個IO口的高低電平來判斷是否有按鍵按下蚣驼。
三魄幕、獨立按鍵實例編程
1.說明
以普中科技51單片機開發(fā)板為例
圖4為獨立按鍵電路圖 8個按鍵分別對應JP5的八個引腳,所有按鍵統(tǒng)一接地颖杏,按鍵之間互不影響纯陨,JP5中包含上拉電阻。當按鍵松開時留储,對應引腳輸入1翼抠;當按鍵按下時,對應引腳輸入0获讳。
圖5為流水燈電路圖 8個LED燈接地共陰阴颖,當引腳輸出1時,LED燈亮丐膝;當引腳輸出0時量愧,LED燈滅。
2.代碼實現(xiàn)
(1) 無消抖的8個引腳控制8個LED燈
#include <reg51.h>
#define Key P0 //P0接獨立按鍵電路引腳
#define Led P2 //P2接LED流水燈電路引腳
int main()
{
unsigned char i;
P2=0x00; //初始化流水燈全滅
while(1)
{
//動態(tài)掃描八個按鍵
for(i=0;i<8;i++)
{
if( 0 == (Key&(1<<i)) ) Led|=1<<i; //按鍵按下
else Led&=~(1<<i); //按鍵彈起
}
}
return 0;
}
(2) 通過按鍵控制單個數(shù)碼管計數(shù)并作消抖處理
具體要求:
- 數(shù)碼管初始化為0帅矗,按下按鍵增加對應的數(shù)偎肃,例如按下Key1則增加1,按下Key2則增加2
- Key8用于清零
- 超出9時损晤,要做越界處理
- 消抖
- 按鍵抬起檢測 按一次只加一次
//printNum.h頭文件
#define Led P2 //P2口控制單個數(shù)碼管
#define state 1 //此處是共陽數(shù)碼管 所以置1
void printNum(int i)
{
//0123456789AbCDEF
unsigned char num[16]={0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};
if(state==1) Led=num[i]; //Common yang
else Led=~num[i]; //Common yin
}
void delay_ms(unsigned int i)
{
unsigned int temp=i*100;
while(temp--) ;
}
#include <reg51.h>
#include "printNum.h"
#define Key P0
int main()
{
unsigned char i;
unsigned char count=0;
while(1)
{
printNum(count);
for(i=0;i<7;i++) //動態(tài)檢測8個按鍵
{
if( 0==(Key&(1<<i)) ) //判斷按鍵是否按下
{
delay_ms(150); //消抖
if( 0==(Key&(1<<i)) )
count+=i+1; //累加上對應的數(shù)
if(count>9) count%=10; //防止越界
printNum(count); //實時更新數(shù)字
while( !(Key&(1<<i)) ) ; //按鍵抬起檢測
}
}
if( 0 == (Key&(1<<7))) count=0; //最后一個鍵用于清零
}
}
(3)通過按鍵控制多個數(shù)碼管計數(shù)
具體要求:
- 功能:數(shù)碼管初始化為0软棺,按下按鍵增加對應的數(shù),例如按下Key1則增加1尤勋,按下Key2則增加2……但是按下Key8需清零
- 使用38譯碼器對COM口進行控制 節(jié)省I/O口
- P1的三個引腳控制38譯碼器喘落,其他引腳上的值不允許被改動
- P2控制數(shù)碼管段碼端的給值
- P0控制檢測按鍵的輸入
- 按鍵要消抖 抬起要檢測 邊界要檢測
#define Led P2
#define state 0
void printNum(int i)
{
//0123456789AbCDEF
unsigned char num[16]={0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};
if(state==1) Led=num[i]; //Common yang
else Led=~num[i]; //Common yin
}
void delay_ms(unsigned int i)
{
unsigned int temp=i*100;
while(temp--) ;
}
#include <reg51.h>
#include "printNum.h"
#define Key P0
#define LED_PLACE P1
unsigned char screenNum[8]={0,0,0,0,0,0,0,0};
int main()
{
unsigned char i;
unsigned char j;
unsigned long count=0;
unsigned long temp=0;
while(1)
{
LED_PLACE &= 0xf8; //Clear PLACE.0-2
if(count>99999999) count=0; //deal with the range
temp=count;
for(i=0;i<8;i++) //transfer long to arr
{
screenNum[7-i]=temp%10;
temp/=10;
}
for(i=0;i<8;i++) //give nums to screen
{
printNum(screenNum[i]);
j=100;
while(j--) ;
Led = 0x0; //remove the double image
LED_PLACE+=1; //control the place
}
for(i=0;i<7;i++) //scan the press keys
{
if( 0==(Key&(1<<i)) )
{
delay_ms(150);
if( 0==(Key&(1<<i)) )
count+=i+1;
while( !(Key&(1<<i)) ) ;
}
}
if( 0 == (Key&(1<<7))) count=0; //key8 to clear all
}
}
不足:按下按鍵時,數(shù)碼管全部熄滅最冰,這是由于掉進按鍵檢測的死循環(huán)中瘦棋,無法掃描動態(tài)數(shù)碼管。改進方法暖哨,等待學習中斷和定時器赌朋。
更新:
(3) 通過中斷來控制按鈕增加數(shù)碼管顯示
連線方式:
- P2接J12控制動態(tài)數(shù)碼管段碼端
- P1.0-2接J6-三八譯碼器 控制動態(tài)數(shù)碼管COM端
- P3.2接JP5-K1 INT0控制按鍵1
#define Led P2
#define state 0
void printNum(int i)
{
//0123456789AbCDEF
unsigned char num[16]={0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e};
if(state==1) Led=num[i]; //Common yang
else Led=~num[i]; //Common yin
}
void delay_ms(unsigned int i)
{
unsigned int temp=i*100;
while(temp--) ;
}
#include <reg51.h>
#include "printNum.h"
#define LED_PLACE P1
unsigned char screenNum[8]={0,0,0,0,0,0,0,0};
unsigned long count=0;
void exint0() interrupt 0 // P3.2
{
count++;
}
void initDevice()
{
IT0=1;
EX0=1;
EA=1;
}
int main()
{
unsigned char i;
unsigned char j;
unsigned long temp=0;
initDevice();
while(1)
{
LED_PLACE &= 0xf8; //Clear PLACE.0-2
if(count>99999999) count=0; //deal with the range of dital
temp=count;
for(i=0;i<8;i++) //transfer long to arr
{
screenNum[7-i]=temp%10;
temp/=10;
}
for(i=0;i<8;i++) //give nums to screen
{
printNum(screenNum[i]);
j=100;
while(j--) ;
Led = 0x0; //remove the double image
LED_PLACE+=1; //control the place
}
}
}
參考資料:
http://www.51hei.com/bbs/dpj-19896-1.html ——單片機論壇
http://blog.csdn.net/fanyuqa/article/details/48036529 ——CSDN fanyuqa博客