1、键盘分类
键盘分编码键盘和非编码键盘,键盘上闭合键的识别由专用的硬件编码器实现,并产生键编码或键值的称为编码键盘,如计算机键盘。
而靠软件编程来识别的称为非编码键盘;
在单片机组成的各种系统中,用的最多的是非编码键盘。也有用到编码键盘的。
非编码键盘又分为:独立键盘和行列式(又称为矩阵式)键盘。
此图为矩阵键盘
此图为独立键盘
在单片机内部P1,P2,P3口各I/O口线片内均有固定的上拉电阻,当这3个准双向I/O口作为输入口使用时,向该口先写“1” 才能读取这个I/O的状态,P3.4 =1,如果这个I/O口没有3态就是没有3态关系这个I/O就跟连接的元器件是一个线与的关系,所以按键按下去就是低电平。如果有3态的I/O口就是跟连接的器件是一个线或的关系,高阻态并非是高电平还是低电平,而是高阻状态,如果外接高它就是高,接低它就是低电平。
实例:先写个程序检测下吧
note:说明下这个程序就是每按下按键让一个数码管变一下,从0--9 然后再按变成0循环
#include
#define uchar unsigned char
sbit d1= P1^0; //这个脚接的是发光二极管。
sbit key1= P3^4 ;//接的一个按键
sbit dula = P2^6;// 段啦 控制数码管
sbit wela = P^7;// 位啦 控制数码管
uchar num;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,
0x76,0x79,0x38,0x3f,0};//编码表 数组 code 是在ROM区
void main(){
wela =1;
P0= Oxfe;
wela=0; //位选就打开一个数码管的
P3 = 0XFF; //把P3都给写1
while(1){ //轮循的方式
if(0==key1){
d1= 0; //点亮灯
num ++;//每按一次按键让num++
if (10==num)
num=0; //一个数码管就只能显示9
}else{
d1 = 1; //熄灭灯
}
dula =1;
P0 = table[num];
dula =0;
}
以上程序存在问题:按下按键时候数码管显示的不是1 2.....9 0 1... 原因是:你按下的大概低电平持续了20毫秒,20毫秒此程序执行了多少次了,所以数码管显示的不是1 可能是5 可能是8 9 。所以必须做一个松手检测。
#include
#define uchar unsigned char
sbit d1= P1^0; //这个脚接的是发光二极管。
sbit key1= P3^4 ;//接的一个按键
sbit dula = P2^6;// 段啦 控制数码管
sbit wela = P^7;// 位啦 控制数码管
uchar num;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,
0x76,0x79,0x38,0x3f,0};//编码表 数组 code 是在ROM区
void main(){
wela =1;
P0= Oxfe;
wela=0; //位选就打开一个数码管的
P3 = 0XFF; //把P3都给写1
while(1){ //轮循的方式
if(0==key1){
d1= 0; //点亮灯
num ++;//每按一次按键让num++
if (10==num)
num=0; //一个数码管就只能显示9
while (!key1) //松手检测 只要你按键按下去是0 取反 一直等待 否则跳出去到下面
}else{
d1 = 1; //熄灭灯
}
dula =1;
P0 = table[num];
dula =0;
}
以上程序虽然得到改善,但是存在按一下会加得不是1现象,当然几率不大,但确实存在。
按键在闭合和断开时,触点会存在抖动现象
从这个图看按下和松开有毛刺 这个是硬件消抖动不要理解
我们解决的是按下去的毛刺去掉:延时函数 10毫秒 也就是说我们第一次按下去的时候我们延时个10毫秒,实际上毛刺抖动为5毫秒左右,我们给10毫秒更稳定。程序如下:
#include
#define uchar unsigned char
sbit d1= P1^0; //这个脚接的是发光二极管。
sbit key1= P3^4 ;//接的一个按键
sbit dula = P2^6;// 段啦 控制数码管
sbit wela = P^7;// 位啦 控制数码管
uchar num;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,
0x76,0x79,0x38,0x3f,0};//编码表 数组 code 是在ROM区
//此为延时 测试值为1毫秒级
void delay(uint z)
{
uint t1,y;
for(t1=z;t1>0;t1--)
for(y=110;y>0;y--);
}
void main(){
wela =1;
P0= Oxfe;
wela=0; //位选就打开一个数码管的
P3 = 0XFF; //把P3都给写1
while(1){ //轮循的方式
if(0==key1){
delay(10);//延时10毫秒
if (0==key1){ //再确认下确实按下去了多了delay 和if 判断
d1= 0; //点亮灯
num ++;//每按一次按键让num++
if (10==num)
num=0; //一个数码管就只能显示9
}
while (!key1) //松手检测 只要你按键按下去是0 取反 一直等待 否则跳出去到下面
}else{
d1 = 1; //熄灭灯
}
dula =1;
P0 = table[num];
dula =0;
}
经过以上的更改是改善了问题但是还是会存在抖动现象,原因是我们只是在按下去消除抖动,没有在松手消除抖动,但是实际的项目中一般我们都是按下去的时候做消除抖动,如果想要达到更好的效果可以在松手也做消除抖动。程序简单修改如下:
#include
#define uchar unsigned char
sbit d1= P1^0; //这个脚接的是发光二极管。
sbit key1= P3^4 ;//接的一个按键
sbit dula = P2^6;// 段啦 控制数码管
sbit wela = P^7;// 位啦 控制数码管
uchar num;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,
0x76,0x79,0x38,0x3f,0};//编码表 数组 code 是在ROM区
//此为延时 测试值为1毫秒级
void delay(uint z)
{
uint t1,y;
for(t1=z;t1>0;t1--)
for(y=110;y>0;y--);
}
void main(){
wela =1;
P0= Oxfe;
wela=0; //位选就打开一个数码管的
P3 = 0XFF; //把P3都给写1
while(1){ //轮循的方式
if(0==key1){
delay(10);//延时10毫秒
if (0==key1){ //再确认下确实按下去了多了delay 和if 判断
d1= 0; //点亮灯
num ++;//每按一次按键让num++
if (10==num)
num=0; //一个数码管就只能显示9
}
while (!key1) //松手检测 只要你按键按下去是0 取反 一直等待 否则跳出去到下面
dely(10); //松手消除抖动 就是延时
while(!key1);// 再确认下 然后执行下面语句
}else{
d1 = 1; //熄灭灯
}
dula =1;
P0 = table[num];
dula =0;
}
以上程序是独立键盘的应用中确实存在的一些问题和本人的一些简单的解决问题的思路。当然延时也可以改成5毫秒尽量的不要让MCU过多的等待。一般的项目中都不会采用延时来去抖动,可以用定时器来去除抖动。特别在一些嵌入式系统中常用定时器去抖动,因为嵌入式设备的硬件资源太宝贵了哦。希望大牛们给个定时器的去除抖动程序。!!!!