单片机外设矩阵键盘之行列扫描识别原理与示例
1.概述
这篇文章介绍单片机通过行列扫描的方式识别矩阵键盘的按键,通过程序执行相应的操作。
2.行列扫描识别原理
2.1.独立按键识别原理
为什么需要矩阵按键
独立按键操作简单,当数量较多时候会占用单片机的IO口,限制了按键的数量,无法满足需要更多按键的场景,因此矩阵键盘就应用而生了,他的按键数量多占用的IO口却很少。
为什么介绍独立按键
为什么不直接介绍矩阵按键而是先介绍独立按键工作原理那,这是因为矩阵键盘是独立按键数量的升级,矩阵键盘工作原理并没有改变,还是独立按键的工作原理。
一个独立按键工作原理
- 当我们将按键接到单片机上,通过按键控制LED灯的亮灭。
- -他的工作原理是将按键的一端接到单片机IO口,另一端接到GND端
- 当按下按键,连接按键的IO口和GND导通,高电平变为低电平。
- 当检测到IO口为低电平,就让LED灯点亮。
- 松开按键IO口恢复高电平,就让LED灯灭。
多个独立按键工作原理
当我们掌握了一个独立按键控制LED灯的原理后,就可以将多个独立按键用一根导线并联并接到GND,按键另一端接到单片机的每个IO口,形成一列独立按键。
- 定义每个接到单片机IO口上的按键名称
- 当某个按键按下去的时候,对应的IO口引脚就会与GND导通,高电平变为低电平
- 检测低电平的引脚对应的按键,然后通过程序逻辑作出对应操作。
2.2.独立按键升级矩阵按键
当一列独立按键不够用的时候,可以增加多列。但是单片机的IO口是有限的,因此不能介入更多的按键。这个时候就可以采用矩阵接线方式,连接多列独立按键形成行和列的矩阵键盘。
行列扫描工作原理
例如下图中是一个4X4矩阵键盘,KEYIN1~KEYIN4
为行,KEYOUT1~KEYOUT4
为列。
- 第一列行扫描:如果我们将第一列接到GND,
KEYIN1~KEYIN4
行接到单片机的4个IO口上那么就是上面的多个独立按键组成一列独立按键场景,当按下某个按键时就会扫描第一列的1~4行按键的高低电平。 - 第二列行扫描:将第二列接到GND,
KEYIN1~KEYIN4
行接到单片机的4个IO口上,当按下某个按键时就会扫描第二列的1~4行按键的高低电平。 - 第三列行扫描:将第三列接到GND,
KEYIN1~KEYIN4
行接到单片机的4个IO口上,当按下某个按键时就会扫描第三列的1~4行按键的高低电平。 - 第四列行扫描:将第三列接到GND,
KEYIN1~KEYIN4
行接到单片机的4个IO口上,当按下某个按键时就会扫描第四列的1~4行按键的高低电平。
行列扫描软件实现原理
了解了矩阵键盘的行列扫描工作原理后,就可以用程序实现行列扫描识别按键。
- 第一列行扫描:将第一列
KEYOUT1
接到单片机引脚并设置为低电平,就可以模拟硬件电路接到GND,KEYIN1~KEYIN4
行接到单片机的4个IO口上设置为高电平,当按下1号按键
那么第一行就与第一列接通,第一行的高电平就变为低电平,这个时候就能识别出按下了1号按键
。 - 第二列行扫描:将第二列
KEYOUT2
接到单片机引脚并设置为低电平,KEYIN1~KEYIN4
行接到单片机的4个IO口上设置为高电平,当按下5号按键
那么第一行就与第二列接通,第一行的高电平就变为低电平,这个时候就能识别出按下了5号按键
。 - 第三列行扫描:将第三列
KEYOUT3
接到单片机引脚并设置为低电平,KEYIN1~KEYIN4
行接到单片机的4个IO口上设置为高电平,当按下9号按键
那么第一行就与第三列接通,第一行的高电平就变为低电平,这个时候就能识别出按下了9号按键
。 - 第四列行扫描:将第四列
KEYOUT4
接到单片机引脚并设置为低电平,KEYIN1~KEYIN4
行接到单片机的4个IO口上设置为高电平,当按下C号按键
那么第一行就与第四列接通,第一行的高电平就变为低电平,这个时候就能识别出按下了C号按键
。
3.行列扫描实例
根据矩阵键盘的行列扫描原理用程序来实现识别按键,并作出对应的操作。
/*
程序名:行列扫描操作矩阵键盘
编写人:bruce
编写时间:2023年12月
硬件支持:STC12C2052AD系列
接口说明:
修改日志:
NO.1-
*/
#include <STC12C2052AD.H> //STC12Cx052或STC12Cx052AD系列单片机头文件
// 定义LED灯
sbit LED = P3^7;
// 定义行扫描按键
sbit KEYIN1 = P1^0;
sbit KEYIN2 = P1^1;
sbit KEYIN3 = P1^2;
sbit KEYIN4 = P1^3;
//定义列扫描按键
sbit KEYOUT1 = P1^4;
sbit KEYOUT2 = P1^5;
sbit KEYOUT3 = P1^6;
sbit KEYOUT4 = P1^7;
/*
函数名:毫秒级CPU延时函数
调 用:DELAY_MS (?);
参 数:1~65535(参数不可为0)
返回值:无
结 果:占用CPU方式延时与参数数值相同的毫秒时间
备 注:应用于1T单片机时i<600,应用于12T单片机时i<125
*/
void DELAY_MS (unsigned int a){
unsigned int i;
while( a-- != 0){
for(i = 0; i < 600; i++);
}
}
/*
作用:行列扫描方式识别矩阵键盘按键
参数:返回识别到的按键
返回:
*/
unsigned char keyScan(){
unsigned char keyNum;
/*
扫描第一列行上面的按键
*/
KEYIN1,KEYIN2,KEYIN3,KEYIN4 = 1;
KEYOUT2,KEYOUT3,KEYOUT4 = 1;
// 第一列设置为低电平
KEYOUT1 = 0;
if(!KEYIN1 || !KEYIN2 || !KEYIN3 || !KEYIN4 ){
DELAY_MS(20);
if(!KEYIN1 || !KEYIN2 || !KEYIN3 || !KEYIN4){
if(!KEYIN1){
keyNum = 1;
}
if(!KEYIN2){
keyNum = 2;
}
if(!KEYIN3){
keyNum = 3;
}
if(!KEYIN4){
keyNum = 4;
}
}
//等待按键松开
while(!KEYIN1 || !KEYIN2 || !KEYIN3 || !KEYIN4);
}
/*
扫描第二列行上面的按键
*/
KEYIN1,KEYIN2,KEYIN3,KEYIN4 = 1;
KEYOUT1,KEYOUT3,KEYOUT4 = 1;
// 第二列设置为低电平
KEYOUT2 = 0;
if(!KEYIN1 || !KEYIN2 || !KEYIN3 || !KEYIN4 ){
DELAY_MS(20);
if(!KEYIN1 || !KEYIN2 || !KEYIN3 || !KEYIN4){
if(!KEYIN1){
keyNum = 5;
}
if(!KEYIN2){
keyNum = 6;
}
if(!KEYIN3){
keyNum = 7;
}
if(!KEYIN4){
keyNum = 8;
}
}
//等待按键松开
while(!KEYIN1 || !KEYIN2 || !KEYIN3 || !KEYIN4);
}
/*
扫描第三列行上面的按键
*/
KEYIN1,KEYIN2,KEYIN3,KEYIN4 = 1;
KEYOUT1,KEYOUT2,KEYOUT4 = 1;
// 第三列设置为低电平
KEYOUT3 = 0;
if(!KEYIN1 || !KEYIN2 || !KEYIN3 || !KEYIN4 ){
DELAY_MS(20);
if(!KEYIN1 || !KEYIN2 || !KEYIN3 || !KEYIN4){
if(!KEYIN1){
keyNum = 9;
}
if(!KEYIN2){
keyNum = 10;
}
if(!KEYIN3){
keyNum = 11;
}
if(!KEYIN4){
keyNum = 12;
}
}
//等待按键松开
while(!KEYIN1 || !KEYIN2 || !KEYIN3 || !KEYIN4);
}
/*
扫描第四列行上面的按键
*/
KEYIN1,KEYIN2,KEYIN3,KEYIN4 = 1;
KEYOUT1,KEYOUT2,KEYOUT3 = 1;
// 第四列设置为低电平
KEYOUT4 = 0;
if(!KEYIN1 || !KEYIN2 || !KEYIN3 || !KEYIN4 ){
DELAY_MS(20);
if(!KEYIN1 || !KEYIN2 || !KEYIN3 || !KEYIN4){
if(!KEYIN1){
keyNum = 13;
}
if(!KEYIN2){
keyNum = 14;
}
if(!KEYIN3){
keyNum = 15;
}
if(!KEYIN4){
keyNum = 16;
}
}
//等待按键松开
while(!KEYIN1 || !KEYIN2 || !KEYIN3 || !KEYIN4);
}
return keyNum;
}
void main(){
while(1){
switch(keyScan()){
case 1:
LED = 0;
break;
case 2:
LED = 1;
break;
default:
LED =1;
}
}
}