?? keyboard.txt
字號(hào):
#ifndef _KEY_H_ //防止重復(fù)引用該文檔,如果沒有定義過符號(hào) _KEY_H_,則編譯下面語句
#define _KEY_H_ //只要引用過一次,即 #include <key.h>,則定義符號(hào) _KEY_H_
unsigned char keyHit( void ); //如果按鍵,則返回非0,否則返回0
unsigned char keyGet( void ); //讀取按鍵值,如果沒有按鍵則等待到按鍵為止
void keyPut( unsigned char ucKeyVal ); //保存按鍵值ucKeyVal到按鍵緩沖隊(duì)列末
void keyBack( unsigned char ucKeyVal ); //退回鍵值ucKeyVal到按鍵緩沖隊(duì)列首
#endif
定義函數(shù)體文檔 KEY.C,如下:
#include “key.h”
#define KeyBufSize 16 //定義按鍵緩沖隊(duì)列字節(jié)數(shù)
unsigned char KeyBuf[ KeyBufSize ]; //定義一個(gè)無符號(hào)字符數(shù)組作為按鍵緩沖隊(duì)列。該隊(duì)列為先進(jìn)
//先出,循環(huán)存取,下標(biāo)從0到 KeyBufSize-1
unsigned char KeyBufWp=0; //作為數(shù)組下標(biāo)變量,記錄存入位置
unsigned char KeyBufRp=0; //作為數(shù)組下標(biāo)變量,記錄讀出位置
//如果存入位置與讀出位置相同,則表明隊(duì)列中無按鍵數(shù)據(jù)
unsigned char keyHit( void )
{ if( KeyBufWp == KeyBufRp ) return( 0 ); else return( 1 ); }
unsigned char keyGet( void )
{ unsigned char retVal; //暫存讀出鍵值
while( keyHit()==0 ); //等待按鍵,因?yàn)楹瘮?shù)keyHit()的返回值為 0 表示無按鍵
retVal = KeyBuf[ KeyBufRp ]; //從數(shù)組中讀出鍵值
if( ++KeyBufRp >= KeyBufSize ) KeyBufRp=0; //讀位置加1,超出隊(duì)列則循環(huán)回初始位置
return( retVal );
}
void keyPut( unsigned char ucKeyVal )
{ KeyBuf[ KeyBufWp ] = ucKeyVal; //鍵值存入數(shù)組
if( ++KeyBufWp >= KeyBufSize ) KeyBufWp=0; //存入位置加1,超出隊(duì)列則循環(huán)回初始位置
}
/*****************************************************************************************
由于某種原因,讀出的按鍵,沒有用,但其它任務(wù)要用該按鍵,但傳送又不方便。此時(shí)可以退回按鍵隊(duì)列。就如取錯(cuò)了信件,有必要退回一樣
******************************************************************************************/
void keyBack( unsigned char ucKeyVal )
{
/*
如果KeyBufRp=0; 減1后則為FFH,大于KeyBufSize,即從數(shù)組頭退回到數(shù)組尾。或者由于干擾使得KeyBufRp超出隊(duì)列位置,也要調(diào)整回到正常位置,
*/
if( --KeyBufRp >= KeyBufSize ) KeyBufRp=KeyBufSize-1;
KeyBuf[ KeyBufRp ] = ucKeyVal; //回存鍵值
}
下面漸進(jìn)講解鍵盤物理層的驅(qū)動(dòng)。
電路共同點(diǎn):P2端口接一共陰數(shù)碼管,共陰極接GND,P2.0接a段、P2.1接b段、…、P2.7接h段。
軟件共同點(diǎn):code unsigned char Seg7Code[10] 是七段數(shù)碼管共陰編碼表。
Code unsigned char Seg7Code[16]=
// 0 1 2 3 4 5 6 7 8 9 A b C d E F
{0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};
例一:P1.0接一按鍵到GND,鍵編號(hào)為‘6’,顯示按鍵。
#include <at89x52.h>
#include “KEY.H”
void main( void )
{ P1_0 = 1; //作為輸入引腳,必須先輸出高電平
while( 1 ) //永遠(yuǎn)為真,即死循環(huán)
{ if( P1_0 == 0 ) //如果按鍵,則為低電平
{ keyPut( 6 ); //保存按鍵編號(hào)值為按鍵隊(duì)列
while( P1_0 == 0 ); //如果一直按著鍵,則不停地執(zhí)行該循環(huán),實(shí)際是等待松鍵
}
if( keyHit() != 0 ) //如果隊(duì)列中有按鍵
P2=Seg7Code[ keyGet() ]; //從隊(duì)列中取出按鍵值,并顯示在數(shù)碼管上
}
}
例二:在例一中考慮按鍵20ms抖動(dòng)問題。
#include <at89x52.h>
#include “KEY.H”
void main( void )
{ P1_0 = 1; //作為輸入引腳,必須先輸出高電平
while( 1 ) //永遠(yuǎn)為真,即死循環(huán)
{ if( P1_0 == 0 ) //如果按鍵,則為低電平
{ delay20ms(); //延時(shí)20ms,跳過接下抖動(dòng)
keyPut( 6 ); //保存按鍵編號(hào)值為按鍵隊(duì)列
while( P1_0 == 0 ); //如果一直按著鍵,則不停地執(zhí)行該循環(huán),實(shí)際是等待松鍵
delay20ms(); //延時(shí)20ms,跳過松開抖動(dòng)
}
if( keyHit() != 0 ) //如果隊(duì)列中有按鍵
P2=Seg7Code[ keyGet() ]; //從隊(duì)列中取出按鍵值,并顯示在數(shù)碼管上
}
}
例三:在例二中考慮干擾問題。即小于20ms的負(fù)脈沖干擾。
#include <at89x52.h>
#include “KEY.H”
void main( void )
{ P1_0 = 1; //作為輸入引腳,必須先輸出高電平
while( 1 ) //永遠(yuǎn)為真,即死循環(huán)
{ if( P1_0 == 0 ) //如果按鍵,則為低電平
{ delay20ms(); //延時(shí)20ms,跳過接下抖動(dòng)
if( P1_0 == 1 ) continue; //假按鍵
keyPut( 6 ); //保存按鍵編號(hào)值為按鍵隊(duì)列
while( P1_0 == 0 ); //如果一直按著鍵,則不停地執(zhí)行該循環(huán),實(shí)際是等待松鍵
delay20ms(); //延時(shí)20ms,跳過松開抖動(dòng)
}
if( keyHit() != 0 ) //如果隊(duì)列中有按鍵
P2=Seg7Code[ keyGet() ]; //從隊(duì)列中取出按鍵值,并顯示在數(shù)碼管上
}
}
例四:狀態(tài)圖編程法。通過20ms周期中斷,掃描按鍵。
/****************************************************************************************
采用晶體為12KHz時(shí),指令周期為1ms(即主頻為1KHz),這樣T0工作在定時(shí)器方式2,8位自動(dòng)重載。計(jì)數(shù)值為20,即可產(chǎn)生20ms的周期性中斷,在中斷服務(wù)程序中實(shí)現(xiàn)按鍵掃描
*****************************************************************************************/
#include <at89x52.h>
#include “KEY.H”
void main( void )
{
TMOD = (TMOD & 0xf0 ) | 0x02; //不改變T1的工作方式,T0為定時(shí)器方式2
TH0 = -20; //計(jì)數(shù)周期為20個(gè)主頻脈,即20ms
TL0=TH0; //先軟加載一次計(jì)數(shù)值
TR0=1; //允許T0開始計(jì)數(shù)
ET0=1; //允許T0計(jì)數(shù)溢出時(shí)產(chǎn)生中斷請(qǐng)求
EA=1; //允許CPU響應(yīng)中斷請(qǐng)求
while( 1 ) //永遠(yuǎn)為真,即死循環(huán)
{
if( keyHit() != 0 ) //如果隊(duì)列中有按鍵
P2=Seg7Code[ keyGet() ]; //從隊(duì)列中取出按鍵值,并顯示在數(shù)碼管上
}
}
void timer0int( void ) interrupt 1 //20ms;T0的中斷號(hào)為1
{ static unsigned char sts=0;
P1_0 = 1; //作為輸入引腳,必須先輸出高電平
switch( sts )
{
case 0: if( P1_0==0 ) sts=1; break; //按鍵則轉(zhuǎn)入狀態(tài)1
case 1:
if( P1_0==1 ) sts=0; //假按錯(cuò),或干擾,回狀態(tài)0
else{ sts=2; keyPut( 6 ); } //確實(shí)按鍵,鍵值入隊(duì)列,并轉(zhuǎn)狀態(tài)2
break;
case 2: if( P1_0==1 ) sts=3; break; //如果松鍵,則轉(zhuǎn)狀態(tài)3
case 3:
if( P1_0==0 ) sts=2; //假松鍵,回狀態(tài)2
else sts=0; //真松鍵,回狀態(tài)0,等待下一次按鍵過程
}
}
例五:狀態(tài)圖編程法。
/****************************************************************************************
如果采用晶體為12MHz時(shí),指令周期為1us(即主頻為1MHz),要產(chǎn)生20ms左右的計(jì)時(shí),則計(jì)數(shù)值達(dá)到20000,T0工作必須為定時(shí)器方式1,16位非自動(dòng)重載,即可產(chǎn)生20ms的周期性中斷,在中斷服務(wù)程序中實(shí)現(xiàn)按鍵掃描
*****************************************************************************************/
#include <at89x52.h>
#include “KEY.H”
void main( void )
{
TMOD = (TMOD & 0xf0 ) | 0x01; //不改變T1的工作方式,T0為定時(shí)器方式1
TL0 = -20000; //計(jì)數(shù)周期為20000個(gè)主頻脈,自動(dòng)取低8位
TH0 = (-20000)>>8; //右移8位,實(shí)際上是取高8位
TR0=1; //允許T0開始計(jì)數(shù)
ET0=1; //允許T0計(jì)數(shù)溢出時(shí)產(chǎn)生中斷請(qǐng)求
EA=1; //允許CPU響應(yīng)中斷請(qǐng)求
while( 1 ) //永遠(yuǎn)為真,即死循環(huán)
{
if( keyHit() != 0 ) //如果隊(duì)列中有按鍵
P2=Seg7Code[ keyGet() ]; //從隊(duì)列中取出按鍵值,并顯示在數(shù)碼管上
}
}
void timer0int( void ) interrupt 1 //20ms;T0的中斷號(hào)為1
{ static unsigned char sts=0;
TL0 = -20000; //方式1為軟件重載
TH0 = (-20000)>>8; //右移8位,實(shí)際上是取高8位
P1_0 = 1; //作為輸入引腳,必須先輸出高電平
switch( sts )
{
case 0: if( P1_0==0 ) sts=1; break; //按鍵則轉(zhuǎn)入狀態(tài)1
case 1:
if( P1_0==1 ) sts=0; //假按錯(cuò),或干擾,回狀態(tài)0
else{ sts=2; keyPut( 6 ); } //確實(shí)按鍵,鍵值入隊(duì)列,并轉(zhuǎn)狀態(tài)2
break;
case 2: if( P1_0==1 ) sts=3; break; //如果松鍵,則轉(zhuǎn)狀態(tài)3
case 3:
if( P1_0==0 ) sts=2; //假松鍵,回狀態(tài)2
else sts=0; //真松鍵,回狀態(tài)0,等待下一次按鍵過程
}
}
例六:4X4按鍵。
/****************************************************************************************
由P1端口的高4位和低4位構(gòu)成4X4的矩陣鍵盤,本程序只認(rèn)為單鍵操作為合法,同時(shí)按多鍵時(shí)無效。
這樣下面的X,Y的合法值為0x7, 0xb, 0xd, 0xe, 0xf,通過表keyCode影射變換可得按鍵值
*****************************************************************************************/
#include <at89x52.h>
#include “KEY.H”
unsigned char keyScan( void ) //返回0表示無按鍵,或無效按鍵,其它值為按鍵編碼值
{ code unsigned char keyCode[16]=
/0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF
{ 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 3, 4, 0 };
unsigned char x, y, retVal;
P1=0x0f; //低四位輸入,高四位輸出0
x=P1&0x0f; //P1輸入后,清高四位,作為X值
P1=0xf0; //高四位輸入,低四位輸出0
y=(P1 >> 4) & 0x0f; //P1輸入后移位到低四位,并清高四位,作為Y值
retVal = keyCode[x]*4 + keyCode[y]; //根據(jù)本公式倒算按鍵編碼
if( retVal==0 ) return(0); else return( retVal-4 );
}
//比如按鍵‘1’,得X=0x7,Y=0x7,算得retVal= 5,所以返回函數(shù)值1。
//雙如按鍵‘7’,得X=0xb,Y=0xd,算得retVal=11,所以返回函數(shù)值7。
void main( void )
{
TMOD = (TMOD & 0xf0 ) | 0x01; //不改變T1的工作方式,T0為定時(shí)器方式1
TL0 = -20000; //計(jì)數(shù)周期為20000個(gè)主頻脈,自動(dòng)取低8位
TH0 = (-20000)>>8; //右移8位,實(shí)際上是取高8位
TR0=1; //允許T0開始計(jì)數(shù)
ET0=1; //允許T0計(jì)數(shù)溢出時(shí)產(chǎn)生中斷請(qǐng)求
EA=1; //允許CPU響應(yīng)中斷請(qǐng)求
while( 1 ) //永遠(yuǎn)為真,即死循環(huán)
{
if( keyHit() != 0 ) //如果隊(duì)列中有按鍵
P2=Seg7Code[ keyGet() ]; //從隊(duì)列中取出按鍵值,并顯示在數(shù)碼管上
}
}
void timer0int( void ) interrupt 1 //20ms;T0的中斷號(hào)為1
{ static unsigned char sts=0;
TL0 = -20000; //方式1為軟件重載
TH0 = (-20000)>>8; //右移8位,實(shí)際上是取高8位
P1_0 = 1; //作為輸入引腳,必須先輸出高電平
switch( sts )
{
case 0: if( keyScan()!=0 ) sts=1; break; //按鍵則轉(zhuǎn)入狀態(tài)1
case 1:
if( keyScan()==0 ) sts=0; //假按錯(cuò),或干擾,回狀態(tài)0
else{ sts=2; keyPut( keyScan() ); } //確實(shí)按鍵,鍵值入隊(duì)列,并轉(zhuǎn)狀態(tài)2
break;
case 2: if(keyScan()==0 ) sts=3; break; //如果松鍵,則轉(zhuǎn)狀態(tài)3
case 3:
if( keyScan()!=0 ) sts=2; //假松鍵,回狀態(tài)2
else sts=0; //真松鍵,回狀態(tài)0,等待下一次按鍵過程
}
}
第六節(jié):低頻頻率計(jì)
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -