本节实现的功能是:通过开发板上的矩阵键盘控制静态数码管显示对应的键值0-F。
独立键盘与单片机连接时,每一个按键都需要单片机的一个I/O口。若某单片机系统需要较多按键,如果用独立按键便会占用过多的I/O口资源。
当用到多个按键时,为了减少I/O口引脚,引入了矩阵按键。比如4*4矩阵键盘。
对于4*4矩阵键盘,开发板上通常将16个按键排成4行4列。第一行将每个按键的一端连接在一起构成行线,第一列将每个按键的另一端连接在一起构成列线,这样便一共有4行4列共8根线。将这8根线连接到单片机的8个I/O口上,通过程序扫描键盘可以检测16个键。
无论是独立键盘还是矩阵键盘,单片机检测其是否被按下的依据都是一样的,即检测与该键对应的I/O口是否为低电平。独立键盘有一端固定为低电平而矩阵键盘两端都与单片机I/O口相连,在检测时需编程通过单片机I/O口送出低电平。检测方法最常用的是行列扫描和线翻转法。
矩阵按键也需要按键消抖。
实现功能:通过开发板上的矩阵键盘控制静态数码管显示对应的键值0-F。用到的硬件资源有:
从上图可以看出,4*4矩阵按键引出的8根控制管脚直接连接到51单片机的P1口上。
要想51单片机能够检测按键是否按下,必须通过单片机管脚来控制矩阵按键。
代码实现如下:
/*
实现功能:使用独立按键控制指示灯的亮灭
[2023-12-06] zoya
*/
#include "reg52.h"
typedef unsigned char u8;
typedef unsigned int u16;
#define GPIO_DIG P0 // 动态数码管
#define GPIO_KEY P1 // 矩阵按键
u8 keyVal; // 记录按键位置
u8 code smg[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71, 0x00}; // 共阴极数码管
// 延时函数,i=1延时10us
void delay(u16 i)
{
while(i--);
}
// 检测矩阵按键的哪个键按下,线翻转法检测哪个按键被按下
void KeyDown()
{
char a = 0;
GPIO_KEY = 0x0f; // 所有行线全部为低电平
if(0x0f != GPIO_KEY) // 检测是否有键被按下,如果有键被按下,GPIO_KEY不会为0x0f
{
delay(1000); // 延时10ms进行消抖
if(0x0f != GPIO_KEY) // 再次判断是否有键被按下
{
// 测试列
GPIO_KEY = 0x0f;
// 检测列是否有低电平
switch(GPIO_KEY)
{
case 0x07: keyVal = 0; break; // 第一列的某行被按下,假设是第一行
case 0x0b: keyVal = 1; break; // 第二列的某行被按下,假设是第一行
case 0x0d: keyVal = 2; break; // 第三列的某行被按下,假设是第一行
case 0x0e: keyVal = 3; break; // 第四列的某行被按下,假设是第一行
}
// 测试行
GPIO_KEY = 0xf0;
switch(GPIO_KEY)
{
case 0x70: keyVal = keyVal + 0; break; // 第一行的某列被按下
case 0xb0: keyVal = keyVal + 4; break; // 第二行的某列被按下
case 0xd0: keyVal = keyVal + 8; break; // 第三行的某列被按下
case 0xe0: keyVal = keyVal + 12; break; // 第四行的某列被按下
}
}
while((a <50) && (GPIO_KEY != 0xF0)) // 检测按键松手检测
{
delay(100);
a++;
}
}
}
void main()
{
while(1)
{
KeyDown();
GPIO_DIG = smg[keyVal];
}
}
仿真结果: