一、矩阵键盘的工作原理
(1)矩阵键盘概述
- 矩阵键盘是单片机外部设备中所使用的排布类似于矩阵的键盘组。(内部实际走线为矩阵,外形一般表现为矩阵)
(2)组成结构
- 在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式。在矩阵式键盘中,每条水平线和垂直线在交叉处不直接连通,而是通过一个按键加以连接。
- 这样,一个端口(如P1口)就可以构成4*4=16个按键,比直接将端口线用于键盘多出了一杯,而且线数越多,区别越明显,比如再多加一条线就可以构成20键的键盘,而直接用端口线则只能多出一键(9键)。由此可见,在需要的键数比较多时,采用矩阵法来做键盘是合理的
- 内部实际走线为矩阵,外形一般表现为矩阵
(3)识别方法
- 当按键没有按下时,所有的输入端都是高电平,代表无按键按下。行线输出是低电平,一旦有键按下,则输入线就会被拉低,这样,通过读入输入线的状态就可得知是否有键按下了;
"行扫描法"
- 又成逐行(列)扫描查询法,是一种最常用的按键识别方法:依次将行线置为低电平。在确定某根线位置为低电平后,再逐行检测各列线的电平状态。若某列为低,则该列线与置为低电平的行线交叉处的按键就是闭合的按键。
"高低电平翻转法"
- 首先让P口高四位为1,低四位为0,若有按键按下,则高思维中会有一个1翻转为0,低四位不会变,此时即可确定备案下的键的行的位置。然后让P口高四位为0,低四位为1,若有按键按下,则低四位中会有一个1翻转为01,高四位不会变,此时即可确定被按下的键的列位置。最后将上述两者进行或运算即可确定被按下的键的位置。
二、矩阵键盘电路原理图
- 示例:假设只想编写一列,可以将P44输出为0(低电平)
三、单片机I/O口快速输入/输出
(1)例程1:以独立键盘程序为基础将]5跳线帽切换为矩阵键盘模式后先写出其中一列矩阵按键的程序。以S7、S6、S5、S4为例。
- 只在原来的KeyScan函数的第一行加上P44 = 0;即可实现在矩阵键盘中使用一列键盘;
cs
//头文件声明区域
#include <STC15F2K60S2.H>
#include<intrins.h>
//变量声明区域
unsigned char S7_Flag = 0,S6_Flag = 0,S5_Flag = 0,S4_Flag = 0;
//函数声明区域
//毫秒级延时函数
void Delay(unsigned int ms);
//按键扫描函数
void KeyScan(void);
//程序主体
void main()
{
P2 = 0XA0;P0 = 0X00;P2 = 0X80;P0 = 0XFF;//初始化程序
while(1)
{
KeyScan();
if(S7_Flag == 1) {S7_Flag = 0; P00 = 0;}
if(S6_Flag == 1) {S6_Flag = 0; P00 = 1;}
if(S5_Flag == 1) {S5_Flag = 0; P06 = 0;}
if(S4_Flag == 1) {S4_Flag = 0; P06 = 1;}
}
}
//毫秒级延时函数
void Delay(unsigned int ms) //@11.0592MHz
{
unsigned char i, j;
while(ms--)
{
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
}
//按键扫描函数
void KeyScan(void)
{
P44 = 0;
if(P30 == 0)
{
Delay(10);
if(P30 == 0)
{
S7_Flag = 1;
while(!P30);
}
}
if(P31 == 0)
{
Delay(10);
if(P31 == 0)
{
S6_Flag = 1;
while(!P31);
}
}
if(P32 == 0)
{
Delay(10);
if(P32 == 0)
{
S5_Flag =1;
while(!P32);
}
}
if(P33 == 0)
{
Delay(10);
if(P33 == 0)
{
S4_Flag = 1;
while(!P33);
}
}
}
(2)例程2:根据例程1可以编写多列矩阵键盘程序。本例以写出第一列、第二列矩阵键盘程序按下S7、56、S5、S4、S11、510、59、S8按键,依次用第一位数码管依次显示1、2、3、4、5、6、7、8数值。
- 假设只写出第一列,将P44置为0时候,按下按键后,只要判断P30 P31 P32 P33谁为0即可;只写第二列,将P42置为0,仍是只要判断P30 P31 P32 P33谁为即可;
- 但是如果现在要同时写两列,应该如何写,思路:因为单片机程序执行的非常快,所以可以先讲P44置为0,然后对第一列进行扫描,如果有按键被按下,即可知道哪个按键被按下;如果没有按键被按下,那么将接下来P44置为1,将P42置为0,再对第二列进行扫描,不停地进行扫描,循环进行,即可知道哪个按键被按下。
cs
//头文件声明区域
#include <STC15F2K60S2.H>
#include<intrins.h>
//变量声明区域
unsigned char S7_Flag = 0,S6_Flag = 0,S5_Flag = 0,S4_Flag = 0,S11_Flag = 0,S10_Flag = 0,S9_Flag = 0,S8_Flag = 0;
unsigned char code SEG[] = {0XF0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
//函数声明区域
//毫秒级延时函数
void Delay(unsigned int ms);
//按键扫描函数
void KeyScan(void);
//程序主体
void main()
{
P2 = 0XA0;P0 = 0X00;P2 = 0X80;P0 = 0XFF;//初始化程序
P2 = 0XC0;P0 = 0X01;P2 = 0XFF;P0 = 0XFF;//打开第一个数码管程序
while(1)
{
KeyScan();
if(S7_Flag == 1) {S7_Flag = 0; P0 = SEG[1];}
if(S6_Flag == 1) {S6_Flag = 0; P0 = SEG[2];}
if(S5_Flag == 1) {S5_Flag = 0; P0 = SEG[3];}
if(S4_Flag == 1) {S4_Flag = 0; P0 = SEG[4];}
if(S11_Flag == 1) {S11_Flag = 0; P0 = SEG[5];}
if(S10_Flag == 1) {S10_Flag = 0; P0 = SEG[6];}
if(S9_Flag == 1) {S9_Flag = 0; P0 = SEG[7];}
if(S8_Flag == 1) {S8_Flag = 0; P0 = SEG[8];}
}
}
//毫秒级延时函数
void Delay(unsigned int ms) //@11.0592MHz
{
unsigned char i, j;
while(ms--)
{
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
}
//按键扫描函数
void KeyScan(void)
{
P44 = 0;P42 = 1;
if(P30 == 0)
{
Delay(10);
if(P30 == 0)
{
S7_Flag = 1;
while(!P30);
}
}
if(P31 == 0)
{
Delay(10);
if(P31 == 0)
{
S6_Flag = 1;
while(!P31);
}
}
if(P32 == 0)
{
Delay(10);
if(P32 == 0)
{
S5_Flag =1;
while(!P32);
}
}
if(P33 == 0)
{
Delay(10);
if(P33 == 0)
{
S4_Flag = 1;
while(!P33);
}
}
P44 = 1;P42 = 0;
if(P30 == 0)
{
Delay(10);
if(P30 == 0)
{
S11_Flag = 1;
while(!P30);
}
}
if(P31 == 0)
{
Delay(10);
if(P31 == 0)
{
S10_Flag = 1;
while(!P31);
}
}
if(P32 == 0)
{
Delay(10);
if(P32 == 0)
{
S9_Flag =1;
while(!P32);
}
}
if(P33 == 0)
{
Delay(10);
if(P33 == 0)
{
S8_Flag = 1;
while(!P33);
}
}
}
(3)例程3:根据例程1可以编写多列矩阵键盘程序。本例以写出第一列、第二列矩阵键盘程序按下57、56、S5、54、S11、S10、59、S8按键,依次用第一位数码管依次显示1、2、3、4、5、6、7、8数值。注:使用一个按键关键词来代替某一个按键被按下。
cs
//头文件声明区域
#include <STC15F2K60S2.H>
#include<intrins.h>
//变量声明区域
unsigned char Key_Flag = 0;
unsigned char code SEG[] = {0XF0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
//函数声明区域
//毫秒级延时函数
void Delay(unsigned int ms);
//按键扫描函数
void KeyScan(void);
//程序主体
void main()
{
P2 = 0XA0;P0 = 0X00;P2 = 0X80;P0 = 0XFF;//初始化程序
P2 = 0XC0;P0 = 0X01;P2 = 0XFF;P0 = 0XFF;//打开第一个数码管程序
while(1)
{
KeyScan();
switch(Key_Flag)
{
case 7:P0 = SEG[1];break;
case 6:P0 = SEG[2];break;
case 5:P0 = SEG[3];break;
case 4:P0 = SEG[4];break;
case 11:P0 = SEG[5];break;
case 10:P0 = SEG[6];break;
case 9:P0 = SEG[7];break;
case 8:P0 = SEG[8];break;
default:break;
}
}
}
//毫秒级延时函数
void Delay(unsigned int ms) //@11.0592MHz
{
unsigned char i, j;
while(ms--)
{
_nop_();
_nop_();
_nop_();
i = 11;
j = 190;
do
{
while (--j);
} while (--i);
}
}
//按键扫描函数
void KeyScan(void)
{
P44 = 0;P42 = 1;
if(P30 == 0)
{
Delay(10);
if(P30 == 0)
{
Key_Flag = 7;
while(!P30);
}
}
if(P31 == 0)
{
Delay(10);
if(P31 == 0)
{
Key_Flag = 6;
while(!P31);
}
}
if(P32 == 0)
{
Delay(10);
if(P32 == 0)
{
Key_Flag = 5;
while(!P32);
}
}
if(P33 == 0)
{
Delay(10);
if(P33 == 0)
{
Key_Flag = 4 ;
while(!P33);
}
}
P44 = 1;P42 = 0;
if(P30 == 0)
{
Delay(10);
if(P30 == 0)
{
Key_Flag = 11;
while(!P30);
}
}
if(P31 == 0)
{
Delay(10);
if(P31 == 0)
{
Key_Flag = 10;
while(!P31);
}
}
if(P32 == 0)
{
Delay(10);
if(P32 == 0)
{
Key_Flag = 9;
while(!P32);
}
}
if(P33 == 0)
{
Delay(10);
if(P33 == 0)
{
Key_Flag = 8;
while(!P33);
}
}
}