-
文章仅为本人学习记录,如有引用部分会另加说明引用出处
矩阵键盘检测原理:(独立键盘的原理在代码注释中很详细)
线反法的原理为:首先使P1口的高四位输出高电平,P1口低四位输出低电平,这时键盘的行线被拉高,列线被拉低。如果有按键按下,则某一条行线将被拉低,此时读取P1口高四位,读取到的将不再全为高电平,说明有按键按下。(在判断是否有按键按下这一点上,线反法与逐行逐列扫描法是一致的)根据读取到0值的I/O口所连接的行线,就可以判断出按下的按键位于哪一行。接下来使P1口的高四位输出低电平,P1口低四位输出高电平(即与上次输出的电平相反,因此称为线反法)。如果有按键按下,此时读取P1口低四位,读取到的将不再全为高电平,根据读取到0值的I/O口所连接的列线,就可以判断出按下的按键位于哪一列。综合按键所在的行线与列线,即可唯一确定按键所在位置,进而获取按键的键值。
————————————————
版权声明:本文为CSDN博主「星水天河」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44509533/article/details/107823449
代码部分
#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
sbit LED_LE=P2^0; //LED锁存器控制端
sbit Duan=P2^3; //数码管段选锁存端
sbit Wei=P2^4; //数码管位选锁存端
sbit D1=P1^0; //灯组
sbit key1=P3^4; //独立键盘P3^4
uchar code s[]={ //数码管段选0~9(高电平有效)
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
uchar code ss[]={ //数码管段选0~9带小数点(高电平有效)
0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};
uchar code w[]={ //数码管位选值
0x00,0x01,0x02,0x04,0x08,0x10,0x20};
uint num=0;
uchar temp;
int fl=0;//按键标志位
void delay(uint z)//延时函数
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void UP_Duan(uint i)//更新段选
{
Duan=1;
P0=s[i];
Duan=0;
}
void main()
{
//初始化位选和段选
Wei=1;
P0=~w[1];
Wei=0;
Duan=1;
P0=0;
Duan=0;
P3=0xff;//初始化P3口的值
while(1)
{
//独立键盘(延时消抖)
/*if(key1==0)
{
delay(10);//消抖(软件延时跳过按下的抖动时间)
if(key1==0)
{
D1=0;//按下按键时灯亮
num++;
if(num==10)
num=0;
}
while(!key1);//消抖(检测按键是否松开)
delay(10);//消抖(软件延时跳过松开的抖动时间)
while(!key1);//消抖(再次检测按键是否松开)
}
else
D1=1;
Duan=1;//无论按键是否按下都更新数码管
P0=s[num];
Duan=0;*/
/*//独立键盘(标志位消抖)
if(key1==0&&fl==0)//按键按下,先置标志位f1为1,且点亮灯
{
fl=1;
D1=0;
}
if(key1==1&&fl==1)//按键松开,灯灭且更新num的值
{
fl=0;
D1=1;
num++;
if(num==10)
num=0;
}
Duan=1;//无论按键是否按下都更新数码管
P0=s[num];
Duan=0;*/
//矩阵键盘
//检测第一行
P3=0xfe;//低位赋值
temp=P3;//读取变化
temp=temp&0xf0;//只取高位的变化
while(temp!=0xf0)//检查是否有键按下
{
delay(5);
temp=P3;//重新读取
temp=temp&0xf0;
while(temp!=0xf0)//确认是否有键按下
{
temp=P3;//实时读取按下哪个键,否则无法检测该行其他按键被按下
switch(temp)
{
case 0xee:num=0;
break;
case 0xde:num=1;
break;
case 0xbe:num=2;
break;
case 0x7e:num=3;
break;
}
while(temp!=0xf0)//检查是否松开按键,不检查无法出这个循环导致其他行的按键按下无法被检测到
{
temp=P3;//一直更新P3口的值,检查是否松开按键
temp=temp&0xf0;
}
UP_Duan(num);//更新段选
}
}
//检测第二行
P3=0xfd;
temp=P3;
temp=temp&0xf0;
while(temp!=0xf0)//检查是否有键按下
{
delay(5);
temp=P3;
temp=temp&0xf0;
while(temp!=0xf0)//重新读取,确认是否有键按下
{
temp=P3;
switch(temp)
{
case 0xed:num=4;
break;
case 0xdd:num=5;
break;
case 0xbd:num=6;
break;
case 0x7d:num=7;
break;
}
while(temp!=0xf0)
{
temp=P3;//一直更新P3口的值,检查是否松开按键
temp=temp&0xf0;
}
UP_Duan(num);
}
}
//检测第三行
P3=0xfb;
temp=P3;
temp=temp&0xf0;
while(temp!=0xf0)//检查是否有键按下
{
delay(5);
temp=P3;
temp=temp&0xf0;
while(temp!=0xf0)//重新读取,确认是否有键按下
{
temp=P3;
switch(temp)
{
case 0xeb:num=8;
break;
case 0xdb:num=9;
break;
case 0xbb:num=10;
break;
case 0x7b:num=11;
break;
}
while(temp!=0xf0)
{
temp=P3;//一直更新P3口的值,检查是否松开按键
temp=temp&0xf0;
}
UP_Duan(num);
}
}
//检测第四行
P3=0xf7;
temp=P3;
temp=temp&0xf0;
while(temp!=0xf0)//检查是否有键按下
{
delay(5);
temp=P3;
temp=temp&0xf0;
while(temp!=0xf0)//重新读取,确认是否有键按下
{
temp=P3;
switch(temp)
{
case 0xe7:num=12;
break;
case 0xd7:num=13;
break;
case 0xb7:num=14;
break;
case 0x77:num=15;
break;
}
while(temp!=0xf0)
{
temp=P3;//一直更新P3口的值,检查是否松开按键
temp=temp&0xf0;
}
UP_Duan(num);
}
}
}
}
仿真部分
矩阵键盘原理图:
对应工程原理图见:(96条消息) 单片机——C51实验含Proteus仿真(锁存器,流水灯,继电器,数码管静态显示,蜂鸣器)_暴躁海葵的博客-CSDN博客