今天继续学习晋中C51-A2单片机,以下均是我个人学习笔记,如果由小伙伴一起学习,欢迎指点。
上次我们学习到独立按键,独立按键的好处很多,但是缺点就是占用I/O接口,为了充分的利用I/O接口,就引入了我们今天学习的按钮矩阵。
使用矩阵按钮之前我们要先了解怎么连接之后再继续编写对应的程序。
我们可以看到,四行四列的矩阵按钮是通过P17~P14控制行,P13~P10控制列,这样就实现了用8个IO接口实现了对十六的按钮的控制,相较于独立按钮是不是节省了很多IO接口呢?
检测原理:
行列式检测:和独立按键检测原理一样,先扫描检查行,在扫描检查列,以此来检测出按下的按钮是哪一个
现在我们来仔细分析,我们先看一下,我们要扫描第一列应该怎么做,结合独立按钮的检测来看,我们应该让一个端口为0,一个端口为1这样当按钮按下的时候才能检测到,所以我们先让行的所有先为1,P17~P14就为1111等同于十六进制的0xF,接下来我们处理列,我们要检测第一列,所以就让P13为0,P12~P10为111,P13~P10就为0111等同于十六进制的0x7,当我们按下第一列的按钮的时候,高位的P17~P14其中的某一位就会变成0,必然会使的P17~14不等于1111,所以这个时候我们只需要根据独立按键的原理就可以找到是哪一行的按钮被按下了,到这里的时候 ,我们就已经知道是哪一行哪一列的按钮被按下了。还是不理解的话我们直接上代码。
u8 key_value=0;
//现在检测第一列,让控制第一列的端口为P13为0,其他为1
//P17~P10=1111 0111=0xf7
KEY_MATRIX_PORT=0xf7;
if(KEY_MATRIX_PORT!=0xf7)
{
delay_time(1000);//别忘了避免抖动
if(KEY_MATRIX_PORT!=0xf7)
{
switch(KEY_MATRIX_PORT)
{
case 0x77:key_value= 1;break;//第一行的按钮被按下时,P17~P10=0111 0111=0x77
case 0xb7:key_value= 5;break;//第二行的按钮被按下时,P17~P10=1011 0111=0xb7
case 0xd7:key_value= 9;break;//第三行的按钮被按下时,P17~P10=1101 0111=0xd7
case 0xe7:key_value= 13;break;//第四行的按钮被按下时,P17~P10=1110 0111=0xe7
//到这里我们是不是就知道了具体时哪一行哪一列了
}
}
while(KEY_MATRIX_PORT!=0xf7);//等待松开按钮,再继续执行
}
对第二列,第三列和第四列一样的处理是不是就完成了我们需要的功能,返回值仅供参考
利用这一个检测原理我们来做一个按按钮后用数码管显示对应的十六进制
⭕ ⭕ ⭕ ⭕ 1 2 3 4
⭕ ⭕ ⭕ ⭕ 5 6 7 8
⭕ ⭕ ⭕ ⭕ 9 10 11 12
⭕ ⭕ ⭕ ⭕ 13 14 15 16
代码放这里了,这里简单回顾一下,数码管的采用的共阴极,连接P0引脚,本代码仅对晋中C51-A2板适用。
#include"reg52.h"
#define SMG_A_DP_PORT P0 //使用宏定义数码管段码口
#define KEY_MATRIX_PORT P1 //使用宏定义矩阵按钮段码口
typedef unsigned char u8;
//共阴极数码管显示0~F的段码数据
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//延时函数
void delay_time(int t)
{
while(t--);
}
u8 key_probe_ranks(void)
{
u8 key_value=0;
//现在检测第一列,让控制第一列的端口为P13为0,其他为1
//P17~P10=1111 0111=0xf7
KEY_MATRIX_PORT=0xf7;
if(KEY_MATRIX_PORT!=0xf7)
{
delay_time(1000);//别忘了避免抖动
if(KEY_MATRIX_PORT!=0xf7)
{
switch(KEY_MATRIX_PORT)
{
case 0x77:key_value= 1;break;//第一行的按钮被按下时,P17~P10=0111 0111=0x77
case 0xb7:key_value= 5;break;//第二行的按钮被按下时,P17~P10=1011 0111=0xb7
case 0xd7:key_value= 9;break;//第三行的按钮被按下时,P17~P10=1101 0111=0xd7
case 0xe7:key_value= 13;break;//第四行的按钮被按下时,P17~P10=1110 0111=0xe7
//到这里我们是不是就知道了具体时哪一行哪一列了
}
}
while(KEY_MATRIX_PORT!=0xf7);//等待按钮松开,松开了我们才能继续向下判断
}
KEY_MATRIX_PORT=0xfb;
if(KEY_MATRIX_PORT!=0xfb)
{
delay_time(1000);
if(KEY_MATRIX_PORT!=0xfb)
{
switch(KEY_MATRIX_PORT)
{
case 0x7b:key_value= 2;break;
case 0xbb:key_value= 6;break;
case 0xdb:key_value= 10;break;
case 0xeb:key_value= 14;break;
}
}
while(KEY_MATRIX_PORT!=0xfb);
}
KEY_MATRIX_PORT=0xfd;
if(KEY_MATRIX_PORT!=0xfd)
{
delay_time(1000);
if(KEY_MATRIX_PORT!=0xfd)
{
switch(KEY_MATRIX_PORT)
{
case 0x7d:key_value= 3;break;
case 0xbd:key_value= 7;break;
case 0xdd:key_value= 11;break;
case 0xed:key_value= 15;break;
}
}
while(KEY_MATRIX_PORT!=0xfd);
}
KEY_MATRIX_PORT=0xfe;
if(KEY_MATRIX_PORT!=0xfe)
{
delay_time(1000);
if(KEY_MATRIX_PORT!=0xfe)
{
switch(KEY_MATRIX_PORT)
{
case 0x7e:return 4;break;
case 0xbe:return 8;break;
case 0xde:return 12;break;
case 0xee:return 16;break;
}
}
while(KEY_MATRIX_PORT!=0xfe);
}
return key_value;
}
void main()
{
u8 key=0;
SMG_A_DP_PORT=gsmg_code[0];
while(1)
{
key=key_probe_ranks();
if(key!=0)
SMG_A_DP_PORT=gsmg_code[key-1];
}
}
线翻转扫描:
我们先来说一下原理,和行列扫描不一样,线翻转扫描先确定行或者列,在确定另一个,不预先设定结果,直接看代码吧
u8 key_value=0;//按键编号
//先进行扫描,那么P17~P14为1111=0xf,P13~P10=0000=0x0
KEY_MATRIX_PORT=0xf0;
if(KEY_MATRIX_PORT!=0xf0)//有按钮按下
{
delay_time(1000);//避免抖动
if(KEY_MATRIX_PORT!=0xf0)
{
switch(KEY_MATRIX_PORT)
{
case 0x70:key_value=0;break;//第一行
case 0xb0:key_value=4;break;//第二行
case 0xd0:key_value=8;break;//第三行
case 0xe0:key_value=12;break;//第四行
}
//立马检测列,那么P17~P14为0000=0x0,P13~P10=1111=0xf
KEY_MATRIX_PORT=0x0f;
switch(KEY_MATRIX_PORT)
{
case 0x07:key_value=key_value+1;break;//第一列
case 0x0b:key_value=key_value+2;break;//第二列
case 0x0d:key_value=key_value+3;break;//第三列
case 0x0e:key_value=key_value+4;break;//第四列
}
while(KEY_MATRIX_PORT!=0x0f);
}
}
return key_value;
好了,我们最后放上最后的代码吧
#include"reg52.h"
#define SMG_A_DP_PORT P0 //使用宏定义数码管段码口
#define KEY_MATRIX_PORT P1 //使用宏定义矩阵按钮段码口
typedef unsigned char u8;
//共阴极数码管显示0~F的段码数据
u8 gsmg_code[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//延时函数
void delay_time(int t)
{
while(t--);
}
u8 key_probe_ranks(void)//行列扫描
{
u8 key_value=0;
//现在检测第一列,让控制第一列的端口为P13为0,其他为1
//P17~P10=1111 0111=0xf7
KEY_MATRIX_PORT=0xf7;
if(KEY_MATRIX_PORT!=0xf7)
{
delay_time(1000);//别忘了避免抖动
if(KEY_MATRIX_PORT!=0xf7)
{
switch(KEY_MATRIX_PORT)
{
case 0x77:key_value= 1;break;//第一行的按钮被按下时,P17~P10=0111 0111=0x77
case 0xb7:key_value= 5;break;//第二行的按钮被按下时,P17~P10=1011 0111=0xb7
case 0xd7:key_value= 9;break;//第三行的按钮被按下时,P17~P10=1101 0111=0xd7
case 0xe7:key_value= 13;break;//第四行的按钮被按下时,P17~P10=1110 0111=0xe7
//到这里我们是不是就知道了具体时哪一行哪一列了
}
}
while(KEY_MATRIX_PORT!=0xf7);
}
KEY_MATRIX_PORT=0xfb;
if(KEY_MATRIX_PORT!=0xfb)
{
delay_time(1000);
if(KEY_MATRIX_PORT!=0xfb)
{
switch(KEY_MATRIX_PORT)
{
case 0x7b:key_value= 2;break;
case 0xbb:key_value= 6;break;
case 0xdb:key_value= 10;break;
case 0xeb:key_value= 14;break;
}
}
while(KEY_MATRIX_PORT!=0xfb);
}
KEY_MATRIX_PORT=0xfd;
if(KEY_MATRIX_PORT!=0xfd)
{
delay_time(1000);
if(KEY_MATRIX_PORT!=0xfd)
{
switch(KEY_MATRIX_PORT)
{
case 0x7d:key_value= 3;break;
case 0xbd:key_value= 7;break;
case 0xdd:key_value= 11;break;
case 0xed:key_value= 15;break;
}
}
while(KEY_MATRIX_PORT!=0xfd);
}
KEY_MATRIX_PORT=0xfe;
if(KEY_MATRIX_PORT!=0xfe)
{
delay_time(1000);
if(KEY_MATRIX_PORT!=0xfe)
{
switch(KEY_MATRIX_PORT)
{
case 0x7e:return 4;break;
case 0xbe:return 8;break;
case 0xde:return 12;break;
case 0xee:return 16;break;
}
}
while(KEY_MATRIX_PORT!=0xfe);
}
return key_value;
}
u8 key_probe_line()//线翻转扫描
{
u8 key_value=0;//按键编号
//先进行扫描,那么P17~P14为1111=0xf,P13~P10=0000=0x0
KEY_MATRIX_PORT=0xf0;
if(KEY_MATRIX_PORT!=0xf0)//有按钮按下
{
delay_time(1000);//避免抖动
if(KEY_MATRIX_PORT!=0xf0)
{
switch(KEY_MATRIX_PORT)
{
case 0x70:key_value=0;break;//第一行
case 0xb0:key_value=4;break;//第二行
case 0xd0:key_value=8;break;//第三行
case 0xe0:key_value=12;break;//第四行
}
//立马检测列,那么P17~P14为0000=0x0,P13~P10=1111=0xf
KEY_MATRIX_PORT=0x0f;
switch(KEY_MATRIX_PORT)
{
case 0x07:key_value=key_value+1;break;//第一列
case 0x0b:key_value=key_value+2;break;//第二列
case 0x0d:key_value=key_value+3;break;//第三列
case 0x0e:key_value=key_value+4;break;//第四列
}
while(KEY_MATRIX_PORT!=0x0f);
}
}
return key_value;
}
void main()
{
u8 key=0;
SMG_A_DP_PORT=gsmg_code[0];
while(1)
{
key=key_probe_line();
//key=key_probe_ranks();
if(key!=0)
SMG_A_DP_PORT=gsmg_code[key-1];
}
}