0引言
参考郭天祥老师的矩阵键盘讲解视频,前几天看了郭老师的视频学习到了一些有用的知识,因此写篇博客记录一些知识与程序,作为储备。
1按键原理
按键的工作原理就是按下按键则闭合端口,松开按键则断开端口,这里讲的是按键抖动原理。(上图取自郭老师的ppt)
1.1硬件消抖
当按键未按下时,输出为1;当键按下时,输出为0。使按键因弹性抖动而产生瞬时断开(抖动跳开B),只要按键不返回原始状态A,双稳态电路的状态不改变,输出保持为0,不会产生抖动的波形,因为当B端口输入0以后,RS锁存器将保持上一个状态。
也就是说,即使B点的电压波形是抖动的,但经双稳态电路之后,其输出为正规的矩形波。
1.2软件消抖
软件消抖主要使用增加延时函数和增加标志位两种方法
1.2.1延时函数
通过if或者while语句进行检测按键是否按下,若按下则进入相关语句,通过延时5ms进行消抖,再次检测是否按下按键,若确实按下则进行相应操作,最后使用whlie语句来判断按键是否松开。
void delay(unint z)
{
unint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);//延时1ms
}
if(key1==0)
{
delay(5);//消除抖动
if(key1==0)
{
//具体操作
}
while(!key1);//松手判断
delay(5);//松手消抖
while(!key1);
}
1.2.2标志位消抖
这是通过设定一个标志位来代替延时函数的方法,当判断按键按下进入if语句后对标志位进行赋值,而后通过标志位与key状态同时判断。
void key_config()
{
//按下输入状态为0,按键外接上拉电阻
//赋初值flag=0
if(key0==0&&flag==0)
{
flag=1;//改变标志位
}
if(flag==1&&key0==1)
{
//具体操作
flag=0;//重置标志位相当于松手检测
}
}
2按键键盘原理
上图是按键键盘的原理图,同样参考郭老师的PPT,采用了行扫描,大致的原理即将P1口赋4次初值,而后进行四次扫描P1的高四位若有相应位被拉低,则得到某行某列按键被按下。
3实际例子
按下16个矩阵键盘依次在数码管上显示1到f。如按下第一个显示1,第二个显示2…
由于这个例子较简单,直接上代码,将键盘扫描的实现封装到一个函数中。
#include "reg52.h"
#define unchar unsigned char
#define unint unsigned int
sbit dula=P2^6;//段选信号
sbit wela=P2^7;//位选信号
unchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,0,
0x36,0x79,0x38,0x3f,0};//1到F数组 code将数组中的数据放程序存储器中
unchar num=17,temp,num1;
unchar keyscan();//封装好的按键键盘函数
void display(unchar num11);
void init();
void delay(unint z)
{
unint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);//1ms
}
int main()
{
init();
while(1)
{
display(keyscan());
}
}
unchar keyscan()
{
P3=0xfe;
temp=P3;
while(temp!=0xfe)
{
delay(5);
temp=P3;
while(temp!=0xfe)
{
switch(temp)
{
case 0xee:num=1;
break;
case 0xde:num=2;
break;
case 0xbe:num=3;
break;
case 0x7e:num=4;
break;
}
while(temp!=0xfe)
{
temp=P3;
}
}
}
P3=0xfd;
temp=P3;
while(temp!=0xfd)
{
delay(5);
temp=P3;
while(temp!=0xfd)
{
switch(temp)
{
case 0xed:num=5;
break;
case 0xdd:num=6;
break;
case 0xbd:num=7;
break;
case 0x7d:num=8;
break;
}
while(temp!=0xfd)
{
temp=P3;
}
}
}
P3=0xfb;
temp=P3;
while(temp!=0xfb)
{
delay(5);
temp=P3;
while(temp!=0xfb)
{
switch(temp)
{
case 0xeb:num=9;
break;
case 0xdb:num=10;
break;
case 0xbb:num=11;
break;
case 0x7b:num=12;
break;
}
while(temp!=0xfb)
{
temp=P3;
}
}
}
P3=0xf7;
temp=P3;
while(temp!=0xf7)
{
delay(5);
temp=P3;
while(temp!=0xf7)
{
switch(temp)
{
case 0xe7:num=13;
break;
case 0xd7:num=14;
break;
case 0xb7:num=15;
break;
case 0x77:num=16;
break;
}
while(temp!=0xf7)
{
temp=P3;
}
}
}
return num;
}
void display(unchar num11)
{
dula=1;
P0=table[num11-1];
dula=0;
}
//初始化
void init()
{
dula=1;
P0=0;
dula=0;
wela=1;
P0=0xc0;
wela=0;
}
可以看到主要的思想是先将P3口赋值(这里TX-1C开发板的按键键盘与P3口相连),而后将P3口状态输出到temp变量中,通过while语句判断temp的值是否改变,while(真)则进入循环并且一直进行循环直到while(假)跳出循环。若temp值(高四位)改变,说明有按键被按下经过延时与反复检测,确定有某行按键按下,而后使用switch/case语句,进行判断是哪行那列按键按下,不断对比过程中可输出相应按键编号,最后使用while语句进行判断按键是否松开,如果松开则说明一次按键检测结束,将松开按键后的P3口状态再次赋值给temp变量用于跳出while循环,通过函数的封装可以返回一个值,该值即被按下按键的编号。
4感悟
学完按键键盘后主要掌握了switch语句,熟悉了一下相关按键消抖与while语句应用,最后就是记录了函数封装。