矩阵按键

*觉得有用有帮助的评论下,谢谢~

矩阵按键

原理图

​ 独立按键一个按键就要占用一个IO口,整个单片机也就32个IO口,全部用完也控制不了几个按键,太占用资源,而矩阵按键则在这方面更有优势,可以只用8个IO口就可以控制16个按键。

矩阵按键原理图

使用方法

  • 逐行扫描:我们可以通过高四位轮流输出低电平来对矩阵键盘进行逐行扫描,当低四位接收到的数据不全为1的时候,说明有按键按下,然后通过接收到的数据是哪一位为0来判断是哪一个按键被按下。

P-10~P-17 的电平为0111 1111 ,假如这时 S2 按键被按下,这时 P-10~P-17数据则则为0111 1011

P-10~P-13 的电平轮流为0 ,0111-1011-1101-1110,每变一次就查一遍低四位的电平数据

  • 行列扫描:我们可以通过高四位全部输出高电平,低四位输出低电平。当接收到的数据,高四位不全为高电平时,说明有按键按下,然后通过接收的数据值,判断是哪一行有按键按下,然后再反过来,高四位输出低电平,低四位输出高电平,然后根据接收到的低四位的值判断是那一行有按键按下,这样就能够确定是哪一个按键按下了。

如先把P-10~P-17 设置为1111 0000 进行 测试,假如这时第一行有按键按下,这时JP4 的数据则为1110 0000 ,这时还不知道第一行的哪个按键按下,我们就反过来,设置 JP4 值为0000 1111,如果测得JP4的值为0000 1011,则可知是 第2列 有按键按下,再结合行测试,就可知是 S2 按下。

C语言语句

  • 这里我们要用到 switch 语句,这是一个选择语句
switch(表达式)
			{
				case(常量表达式1): 语句1; break;
				case(常量表达式2): 语句2; break;
				case(常量表达式3): 语句3; break;
				case(常量表达式4): 语句4; break;
				default:break;//默认..可以省略
			}

表达式与哪个常量表达式值相同就执行哪个语句

程序

  • 效果:按下 S1~S16 ,在静态数码管上一一对应显示 1~F
#include <reg52.H>
#include "intrins.h"
typedef unsigned char u8;
#define GPIO_DIG P0  //通用接口输入
#define GPIO_KEY P1	 //按键接口输入

u8 KeyValue;    //定义一个全局变量,用来存放按键的值

u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//共阴

void delay10ms()   //误差 0us
{
    unsigned char a,b,c;
    for(c=1;c>0;c--)
        for(b=38;b>0;b--)
            for(a=130;a>0;a--);
}

								 
void JzKey()   //矩阵按键程序
{
	u8 a=0;
	GPIO_KEY=0xf0;  //矩阵按键低4位低电平,高四位为高电平,测试行
	if(GPIO_KEY!=0xf0)
	{
		delay10ms();					//消抖
		if(GPIO_KEY!=0xf0)		
		{
				switch(GPIO_KEY)
				{
					case(0xe0): KeyValue=0;break;
					case(0xd0): KeyValue=1;break;
					case(0xb0): KeyValue=2;break;
					case(0x70): KeyValue=3;break;
					
				}

				GPIO_KEY=0x0f;//与上相反,测试列			
				switch(GPIO_KEY)
				{
					case(0x0e): KeyValue=KeyValue;break;
					case(0x0d): KeyValue=KeyValue+4;break;
					case(0x0b): KeyValue=KeyValue+8;break;
					case(0x07): KeyValue=KeyValue+12;break;					
				}
				while((a<50)&&(GPIO_KEY!=0x0f))	 //检测按键松手检测
				{
					delay10ms();
					a++;
				}
			
		}
	}
}

void main()
{
	while(1)
	{
		JzKey();
		GPIO_DIG=~smgduan[KeyValue];//数码管显示
	}	
}

扩展

  • 当我做完上面的实验时,突然想起来以前用计算器的时候,每按一下,都会响一声,这样就可以知道你按到没有,因此我就想在这实现每当按键按下时,蜂鸣器就响,松开时,蜂鸣器就停。

定时器中断

  • 为了实现上述功能,我在这里用到了 定时器 ,这里我就直接介绍它的用法

用法

工作模式

  • 一般比较常用的 方式1方式2

要注意的是,用 方式1 时,要手动重装初值!

定时器中断程序

void InitTimer0(void)     //定时器0程序
{
    TMOD = 0x01;         //设置工作方式
    TH0 = 0x0FF;         //设置初值
    TL0 = 0x9C;
    EA = 1;              //中断总开关
    ET0 = 1;             //定时/计数器0中断允许控制
    TR0 = 1;             //定时器开关
	
}
void Timer0Interrupt(void) interrupt 1      //定时器中断程序
{
    TH0 = 0x0FF;           //重装初值
    TL0 = 0x9C;
	  fmq=~fmq;		       //蜂鸣器
}
  • 要实现扩展功能,只需加个定时器中断, 定时器中断 来控制 蜂鸣器 的响与停,先把 定时器0程序 里的定时器开关 TR0=0 ;在按键按下后,在让 TR0=1 ,让定时器开始定时,蜂鸣器就响了,在检测到按键松开后,这时在让 TR0=0 ,停止定时器,这时蜂鸣器就停了。

完美收工~~~~

猜你喜欢

转载自blog.csdn.net/weixin_43616727/article/details/84337895