矩阵按键
原理图
独立按键一个按键就要占用一个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
,停止定时器,这时蜂鸣器就停了。