在CT107D单片机综合训练平台上,首先将J5处的跳帽接到1~2引脚,使按键S4~S19按键组成4X4的矩阵键盘。在扫描按键的过程中,发现有按键触发信号后(不做去抖动),待按键松开后,在数码管的第一位显示相应的数字:从左至右,从上倒下,依次显示0~F。
训练重点 :
1、矩阵键盘的扫描方式与程序设计思路。2、键码的识别与基本处理。
首先Kiel5中头文件没有设置P4接口,需要我们自己声明一下
矩阵键盘的扫描也是逐行,然后再逐列
#include <REGX52.H>
unsigned char code SMG_duanma[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xbf,0x7f};
sfr P4 = 0xC0;
sbit R1=P3^0;
sbit R2=P3^1;
sbit R3=P3^2;
sbit R4=P3^3;
sbit C1=P4^4;
sbit C2=P4^2;
sbit C3=P3^5;
sbit C4=P3^4;
//选择实现的锁存器通道
void SelectHC573(unsigned char channel)
{
switch(channel)
{
case 4 :
P2 = (P2 & 0x1f) | 0x80;
break;
case 5 :
P2 = (P2 & 0x1f) | 0xa0;
break;
case 6 :
P2 = (P2 & 0x1f) | 0xc0; //控制数码管的位码
break;
case 7 :
P2 = (P2 & 0x1f) | 0xe0; //控制数码管的段码
break;
}
}
//实现上述通道的选择
void Display_SMG(unsigned char value)
{
SelectHC573(6);
P0=0x01;
SelectHC573(7);
P0=value;
}
按键的扫描以及功能的实现
unsigned char key_num = 0; //定义一个变量用来显示数字
void ScanfKeysMulti()
{
R1=0;
R2=R3=R4=1;
C1=C2=C3=C4=1;
if(C1==0)
{
while(C1==0);
key_num=0;
Display_SMG(SMG_duanma[key_num]);
}
else if(C2==0)
{
while(C2==0);
key_num=1;
Display_SMG(SMG_duanma[key_num]);
}
else if(C3==0)
{
while(C3==0);
key_num=2;
Display_SMG(SMG_duanma[key_num]);
}
else if(C4==0)
{
while(C4==0);
key_num=3;
Display_SMG(SMG_duanma[key_num]);
}
R2=0;
R1=R3=R4=1;
C1=C2=C3=C4=1;
if(C1==0)
{
while(C1==0);
key_num=4;
Display_SMG(SMG_duanma[key_num]);
}
else if(C2==0)
{
while(C2==0);
key_num=5;
Display_SMG(SMG_duanma[key_num]);
}
else if(C3==0)
{
while(C3==0);
key_num=6;
Display_SMG(SMG_duanma[key_num]);
}
else if(C4==0)
{
while(C4==0);
key_num=7;
Display_SMG(SMG_duanma[key_num]);
}
R3=0;
R2=R1=R4=1;
C1=C2=C3=C4=1;
if(C1==0)
{
while(C1==0);
key_num=8;
Display_SMG(SMG_duanma[key_num]);
}
else if(C2==0)
{
while(C2==0);
key_num=9;
Display_SMG(SMG_duanma[key_num]);
}
else if(C3==0)
{
while(C3==0);
key_num=10;
Display_SMG(SMG_duanma[key_num]);
}
else if(C4==0)
{
while(C4==0);
key_num=11;
Display_SMG(SMG_duanma[key_num]);
}
R4=0;
R2=R3=R1=1;
C1=C2=C3=C4=1;
if(C1==0)
{
while(C1==0);
key_num=12;
Display_SMG(SMG_duanma[key_num]);
}
else if(C2==0)
{
while(C2==0);
key_num=13;
Display_SMG(SMG_duanma[key_num]);
}
else if(C3==0)
{
while(C3==0);
key_num=14;
Display_SMG(SMG_duanma[key_num]);
}
else if(C4==0)
{
while(C4==0);
key_num=15;
Display_SMG(SMG_duanma[key_num]);
}
R1=0;
R2=R3=R4=1;
C1=C2=C3=C4=1;
if(C1==0)
{
while(C1==0);
key_num=0;
Display_SMG(SMG_duanma[key_num]);
}
else if(C2==0)
{
while(C2==0);
key_num=1;
Display_SMG(SMG_duanma[key_num]);
}
else if(C3==0)
{
while(C3==0);
key_num=2;
Display_SMG(SMG_duanma[key_num]);
}
else if(C4==0)
{
while(C4==0);
key_num=3;
Display_SMG(SMG_duanma[key_num]);
}
}
void main()
{
while(1)
{
ScanfKeysMulti();
}
}
总结:
一、功能简介
本程序基于 51 单片机(STC89C52),实现了 4×4 矩阵键盘扫描,并使用 数码管 显示按键值。按下键盘上的某个按键后,相应的数码管显示对应的键值。
二、硬件连接
- 矩阵键盘(4×4) 采用 P3 及 P4 端口 连接:
- 行(R1~R4):P3.0、P3.1、P3.2、P3.3
- 列(C1~C4):P4.4、P4.2、P3.5、P3.4
- 数码管 通过 P0 端口 输出数据,HC573 锁存器 选择数据端口。
三、程序解析
1. 数码管显示部分
unsigned char code SMG_duanma[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xbf,0x7f};
这是 共阴极数码管段码表,用于显示 0~F
(共 16 个字符)。
2. 矩阵键盘扫描
矩阵键盘由 4 行 4 列组成,共 16 个按键。使用 行扫描法:
- 行(R1-R4)逐行置低,列(C1-C4)读取状态。
- 检测到按键按下(低电平),等待松开(防抖)。
- 更新
key_num
,调用Display_SMG()
显示对应的数字。
void ScanfKeysMulti() { R1=0; R2=R3=R4=1; C1=C2=C3=C4=1; if(C1==0) { while(C1==0); key_num=0; Display_SMG(SMG_duanma[key_num]); } else if(C2==0) { while(C2==0); key_num=1; Display_SMG(SMG_duanma[key_num]); } else if(C3==0) { while(C3==0); key_num=2; Display_SMG(SMG_duanma[key_num]); } else if(C4==0) { while(C4==0); key_num=3; Display_SMG(SMG_duanma[key_num]); } R2=0; R1=R3=R4=1; if(C1==0) { while(C1==0); key_num=4; Display_SMG(SMG_duanma[key_num]); } else if(C2==0) { while(C2==0); key_num=5; Display_SMG(SMG_duanma[key_num]); } else if(C3==0) { while(C3==0); key_num=6; Display_SMG(SMG_duanma[key_num]); } else if(C4==0) { while(C4==0); key_num=7; Display_SMG(SMG_duanma[key_num]); } // 继续扫描 R3、R4 ... }
- 每次置低一行(R1~R4),检查 C1~C4 列 是否有低电平。
- 若某列为低电平,说明对应按键被按下,读取按键值。
while(Cx==0);
等待按键松开,防止按键抖动。
3. 主函数
void main() { while(1) { ScanfKeysMulti(); // 不断扫描矩阵键盘 } }
主函数通过 循环扫描键盘,并 实时更新数码管显示。
四、程序优化建议
-
优化按键去抖:
- 目前是
while(Cx==0);
等待松开,建议增加 延时去抖。
void Delay(unsigned int t) { while(t--); } // 简单延时 if(C1==0) { Delay(1000); while(C1==0); key_num=0; Display_SMG(SMG_duanma[key_num]); }
- 目前是
-
结构优化
ScanfKeysMulti()
可使用 循环遍历,减少重复代码:
void ScanfKeysMulti() { unsigned char row, col; for(row=0; row<4; row++) { R1 = R2 = R3 = R4 = 1; // 先全部置高 if(row == 0) R1 = 0; else if(row == 1) R2 = 0; else if(row == 2) R3 = 0; else if(row == 3) R4 = 0; if(C1==0) col = 0; else if(C2==0) col = 1; else if(C3==0) col = 2; else if(C4==0) col = 3; else continue; while(C1==0 || C2==0 || C3==0 || C4==0); // 等待松开 key_num = row * 4 + col; Display_SMG(SMG_duanma[key_num]); } }
优点:
- 减少重复代码,提高可读性和可维护性。
- 更易扩展到更大矩阵键盘(如 5×5、6×6)。
五、总结
- 行扫描法检测矩阵键盘,逐行拉低,读取列值。
- 数码管通过 HC573 锁存器进行显示控制。
- 优化代码结构,减少冗余,提高可读性。
- 可添加延时去抖,提高稳定性。