一. 键盘检测
键盘分为编码键盘和非编码键盘。
编码键盘 :键盘上闭合键的识别由专用的硬件编码器实现,并产生键编码号或者键值,如计算机键盘。
非编码键盘:靠软件编程来识别。
在单片机组成的各种系统中,用的较多的是非编码键盘。编码键盘又分为独立键盘和行列式键盘(矩阵式键盘)。
1. 独立键盘
单片机系统中常见的几种按键:弹性按键,贴片按键,自锁按键
编写单片机的键盘检测程序时,一般在检测按下时加入去抖延时,检测松手时就不用加了。
案例1:用数码管的前两位显示一个十进制数,变化范围为00-59,开始时显示00,每按下S2键1次,数值加1;每按下S3键1次,数值减1;每按下S4键1次数值归零;按下S5键1次,利用定时器功能使数值开始自动每秒加1,再次按下S5键,数值停止自动加1,保持显示原数。
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit key1 = P3^4;
sbit key2 = P3^5;
sbit key3 = P3^6;
sbit key4 = P3^7;
sbit dula = P2^6; //U1锁存器的锁存端
sbit wela = P2^7; //U2锁存器的锁存端
uchar code table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delayms(uint);
uchar numt0, num;
/***数码管显示函数***/
void display(uchar numdis)
{
uchar shi,ge;
shi = numdis/10;
he = numdis%10;
dula = 1;
P0 = table[shi]; //送十位段选数据
dula = 0;
P0 = 0xff;/*送位选数据前关闭所有显示,
防止打开位选锁存时原来段选数据通过位选锁存器造成混乱*/
wela = 1;
P0 = 0xfe; //送位选数据
wela = 0;
delayms(5);
dula = 1;
P0 = table[ge]; //送个位段选数据
dula = 0;
P0 = 0xff;
wela = 1;
P0 = 0xfd;
wela = 0;
delayms(5);
}
/***延时函数***/
void delayms(uint xms)
{
uint i ,j;
for(i= xms; i>0 ; i--)
{
for(j =110;i>0;j--);
}
}
/***初始化函数***/
void init()
{
TMOD = 0x01; //设置定时器0为工作方式1
TH0 = (65536-45872)/256; //装初值50ms一次中断
TL0 = (65536-45872)%256;
EA = 1; //开总中断
ET0 = 1; //开定时器0中断
}
/***键盘扫描函数***/
void keyscan()
{
if(0 == key1)
{
delayms(10);
if(0 == key1)
{
num++;
if(60 == num)
{
num = 0
}
while(!key1); //等待按键释放
}
}
if(0 == key2)
{
delayms(10);
if(0 == key2)
{
if(0 == num)
{
num = 60
}
num--;
while(!key2);
}
}
if(0 == key3)
{
delayms(10);
if(0 == key3)
{
num = 0;
while(!key3);
}
}
if(0 == key4)
{
delayms(10);
if(0 == key4)
{
while(!key4);
TR0 = ~TR0; //启动或者停止定时器0
}
}
}
void main()
{
init();
while(1)
{
keyscan();
display(num);
}
}
/***定时器中断函数***/
void T0_time() interrupt 1
{
TH0 = (65536-45872)/256; //重装初值
TL0 = (65536-45872)%256;
numt0++;
if(20 == numt0)
{
numt0 = 0;
num++;
if(60 == num)
{
num = 0;
}
}
}
2. 矩阵键盘
独立键盘有一端固定为低电平,单片机写程序检测时比较方便。而矩阵键盘两端都与单片机I/O口相连,因此在检测时需人为通过单片机I/O口送出低电平。
检测时,先送一列为低电平,其余几列全为高电平(此时我们确定了列数),然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电平(这时我们又确定了行数),则我们可以确定当前被按下的键是哪一行哪一列的。用同样的方法轮流送各列一次低电平,再轮流检测一次各行是否变为低电平,这样即可检测完所有的按键,当有按键被按下时便可判断出按下的键是哪一个键。
案例2:实验板上电时,数码管不显示,顺序按下矩阵键盘后,在数码管上依次显示0-F,6个数码管同时静态显示即可。
其中,矩阵键盘的4行分别与单片机的P3.0-P3.3相连,4列分别与P3.4-P3.7相连。
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit dula = P2^6; //U1锁存器的锁存端
sbit wela = P2^7; //U2锁存器的锁存端
uchar code table[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,
0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
/***延时函数***/
void delayms(uint xms)
{
uint i ,j;
for(i= xms; i>0 ; i--)
{
for(j =110;i>0;j--);
}
}
/***数码管显示函数***/
void display(uchar num)
{
P0 = table[num]; //显示函数只送段选数据
dula = 1;
dula = 0;
}
/***矩阵键盘扫描函数***/
void matrixkeyscan()
{
uchar temp,key;
//第一行
P3 = 0xfe;
temp = P3;
temp = temp & 0xf0; //用于判断temp高4位是否有0
if(0xf0 != temp) /*temp的高4位数据实际上就是矩阵键盘的
4个列线,若temp不等于0xf0,说明有键被按下*/
{
delayms(10); //延时去抖
temp = P3;
temp = temp & 0xf0;
if(0xf0 != temp)
{
temp =P3;
switch(temp)
{
case 0xee:
key = 0;
break;
case 0xde:
key = 1;
break;
case 0xbe:
key =2;
break;
case 0x7e:
key = 3;
break;
}
while(temp!=0xf0) //等待按键释放
{
temp = P3;
temp = temp & 0xf0;
}
display(key); //显示
}
}
//第2行
P3 = 0xfd;
temp = P3;
temp = temp & 0xf0;
if(0xf0 != temp)
{
delayms(10);
temp = P3;
temp = temp & 0xf0;
if(0xf0 != temp)
{
temp =P3;
switch(temp)
{
case 0xed:
key = 4;
break;
case 0xdd:
key = 5;
break;
case 0xbd:
key =6;
break;
case 0x7d:
key = 7;
break;
}
while(temp!=0xf0) //等待按键释放
{
temp = P3;
temp = temp & 0xf0;
}
display(key); //显示
}
}
//第3行
P3 = 0xfb;
temp = P3;
temp = temp & 0xf0;
if(0xf0 != temp)
{
delayms(10);
temp = P3;
temp = temp & 0xf0;
if(0xf0 != temp)
{
temp =P3;
switch(temp)
{
case 0xeb:
key = 8;
break;
case 0xdb:
key = 9;
break;
case 0xbb:
key = 10;
break;
case 0x7b:
key = 11;
break;
}
while(temp!=0xf0) //等待按键释放
{
temp = P3;
temp = temp & 0xf0;
}
display(key); //显示
}
}
//第4行
P3 = 0xf7;
temp = P3;
temp = temp & 0xf0;
if(0xf0 != temp)
{
delayms(10);
temp = P3;
temp = temp & 0xf0;
if(0xf0 != temp)
{
temp =P3;
switch(temp)
{
case 0xe7:
key = 12;
break;
case 0xd7:
key = 13;
break;
case 0xb7:
key =14;
break;
case 0x77:
key = 15;
break;
}
while(temp!=0xf0) //等待按键释放
{
temp = P3;
temp = temp & 0xf0;
}
display(key); //显示
}
}
}
void main()
{
P0 = 0; //关闭所有数码管段选
dula = 1;
dula = 0;
P0 = 0xc0; //位选中所有数码管
wela = 1;
wela = 0;
while(1)
{
matrixkeyscan(); //不停调用键盘扫描程序
}
}