飞道的博客

8051单片机实战分析(以STC89C52RC为例) | 08 - 矩阵按键驱动

432人阅读  评论(0)

前面我们学习了《8051单片机实战分析(以STC89C52RC为例) | 07 - 独立按键驱动》,但是在单片机系统中,若使用按键较多时如电子密码锁、电话机键盘等一般都至少有12到16个按键,通常采用矩阵式按键,即矩阵键盘。

1 矩阵键盘

矩阵键盘又称行列键盘,它是用四条I/O线作为行线,四条I/O线作为列线组成的键盘。在行线和列线的每个交叉点上设置一个按键。这样键盘上按键的个数就为4*4个。这种行列式键盘结构能有效地提高单片机系统中I/O口的利用率。

最常见的键盘布局如图所示。一般由16个按键组成,在单片机中正好可以用一个P1实现16个按键功能,这也是在单片机系统中最常用的形式。

4*4矩阵键盘的电路如图所示:

工作原理:

当无按键闭合时,P10~P13P14~P17之间开路。当有键闭合时,与闭合键相连的两条I/O口线之间短路。

判断有无按键按下的方法是:

① 设置列线P10~P13为输入状态,从行线P14~P17输出低电平,读入列线数据,若某一列线为低电平,则该列线上有键闭合。

② 行线轮流输出低电平,从列线P10~P13读入数据,若有某一列为低电平,则对应行线上有键按下。

③ 综合 ① 与 ② 的结果,就可确定按键编号。但是键闭合一次只能进行一次键功能操作,因此须等到按键释放后,再进行键功能操作,否则按一次键,有可能会连续多次进行同样的键操作。

接下来我们实现一个通过按下矩阵键盘上的按键,然后在数码管上显示对应的数字!

按键对应的数码管显示数字定义如下:

S1-S4:0-3
S5-S8:4-7
S9-S12:8-B
S13-S16:C-F

2 原理图

① 矩阵键盘:

② 上拉电阻:

③ MCU原理图:

3 程序

#include "reg52.h"			 //此文件中定义了单片机的一些特殊功能寄存器

typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;

#define GPIO_DIG P0
#define GPIO_KEY P1

sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

u8 KeyValue;	//用来存放读取到的键值

u8 code LedChar[]={
   
	0x3F,  //"0"
    0x06,  //"1"
    0x5B,  //"2"
    0x4F,  //"3"
    0x66,  //"4"
    0x6D,  //"5"
    0x7D,  //"6"
    0x07,  //"7"
    0x7F,  //"8"
    0x6F,  //"9"
    0x77,  //"A"
    0x7C,  //"B"
    0x39,  //"C"
    0x5E,  //"D"
    0x79,  //"E"
    0x71,  //"F"
    0xff, //全亮
    0x00  //熄灭
};

/*******************************************************************************
* 函 数 名         : delay
* 函数功能		   : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
   
	while(i--);	
}

/*******************************************************************************
* 函 数 名         : KeyDown
* 函数功能		   : 检测有按键按下并读取键值
* 输    入         : 无
* 输    出         : 无
*******************************************************************************/
void KeyDown(void)
{
   
        char timeout=0;
        GPIO_KEY=0x0f;    
        //0x0f转化为为二进制为0000 1111,即矩阵按键的八个管脚,高位为低电平(0),低位为高电平(1)
        if(GPIO_KEY!=0x0f)//读取按键是否按下
        {
   
                delay(1000);//延时10ms进行消抖
                if(GPIO_KEY!=0x0f)//再次检测键盘是否按下
                {
          
                        /*对列进行测试(高位低电平,低位高电平)*/
                        GPIO_KEY=0x0f;
                        switch(GPIO_KEY)
                        {
   
                                case(0x07): KeyValue=0;break; //对应管脚高低电平0000 0111,第0列
                                case(0x0b): KeyValue=1;break; //对应管脚高低电平0000 1011,第1列
                                case(0x0d): KeyValue=2;break; //对应管脚高低电平0000 1101,第2列
                                case(0x0e): KeyValue=3;break; //对应管脚高低电平0000 1110,第3列
                        }
                        /*对行进行测试(低位高电平,高位低电平)*/
                        GPIO_KEY=0xf0;
                        switch(GPIO_KEY)
                        {
           /*上一行对应的列号加上相应有规律的字号就等于按键号,可由原理图查看*/
                                case(0x70): KeyValue=KeyValue;break; //对应管脚高低电平0111 0000,第0行
                                case(0xb0): KeyValue=KeyValue+4;break; //对应管脚高低电平1011 0000,第1行
                                case(0xd0): KeyValue=KeyValue+8;break; //对应管脚高低电平1101 0000,第2行
                                case(0xe0): KeyValue=KeyValue+12;break; //对应管脚高低电平1110 0000,第0行
                        }
                        
                }
        }
        while((timeout<50)&&(GPIO_KEY!=0xf0)) //当按键按下的时间超过了50ms或者按键松开了就退出while循环
        {
   
                delay(100);
                timeout++;
        }
}

/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{
   	
	LSA=0; //给一个数码管提供位选
	LSB=0;
	LSC=0;
	while(1)
	{
   	
		KeyDown();		   //按键判断函数
		GPIO_DIG=LedChar[KeyValue];	  //显示键值
	}		
}

简要分析:

① 程序定义一个全局变量KeyValue,用于存放存放读取到的键值。使用宏定义用GPIO_DIG表示P0端口,用GPIO_KEY表示P1端口。

main函数中首先初始化数码管的位选,关于数码管部分,在《8051单片机实战分析(以STC89C52RC为例) | 05 - 静态数码管驱动》这篇博文中已有介绍,这里不再赘述。然后进入while(1)大循环,执行按键判断函数KeyDown()与显示键值GPIO_DIG=LedChar[KeyValue];

③ 在按键判断函数KeyDown()中,首先对矩阵键盘的列进行测试,再按键消抖后判断那一列被按下,接着切换高四位与低四位的电平状态,进一步判断哪一行被按下,之后刷新键值。最后是通过while((timeout<50)&&(GPIO_KEY!=0xf0))进行松手检测,变量timeout的作用是给个50ms的倒计时,不然如果按键一直不松开会一直处于死循环了,这会导致单片机就无法执行其他任务。


转载:https://blog.csdn.net/Neutionwei/article/details/117455613
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场