1.矩阵键盘简介
矩阵键盘使用的方法与独立按键类似,但是比独立按键节省I/O,同时使用方法变得相对复杂了,首先展示硬件连接。
上图所示就是4X4矩阵键盘的常见接法,按行来看,每个按键的左端接在一起,按列来看,每个按键的右端接在一起,共占用8个I/O,接到51单片机的P1端口。
2.代码解释
对于矩阵键盘,常用的方法有两种,一个是线反转法,另一个是行列扫描法,本文介绍线反转法。首先插入模块化编程编程的内容,新建两个文件命名为keyboard.h与keyboard.c并添加到工程中,然后在h文件中定义一个宏,便于与硬件连接发生改变时而进行代码的修改。编程思路,首先给矩阵键盘的端口Matrixkey_Port赋值0x0F,意为行为1列为0,即0000 1111,对应上图就是P10,P11,P12,P13为1,P14,P15,P16,P17为0,那么此时如果第一行有按键按下,P10这一位的高电平必然被拉低,1 & 0 = 0,P1就会变成0X0E,第二,三,四行亦如此,然后进行反推,当检测到这些值的出现时就可以知道是哪一行有按键按下,记录下行值,row就是行值,再给矩阵键盘的端口Matrixkey_Port赋值0xF0,意为行为0列为1,即1111 0000,对应上图就是P10,P11,P12,P13为0,P14,P15,P16,P17为1,与第一次反推类似,可以得到列值col,在下文的程序中,只要将row,col进行运算就能得到1-16的返回值。row的值是1 2 3 4,col的值是1 2 3 4,而键盘编码如下:
/1 2 3 4/
/5 6 7 8/
/9 10 11 12/
/13 14 15 16/
显然,返回值1-16与行列的关系是(row-1)*4+col。
keyboard.h
#ifndef __KEYBOARD_H__
#define __KEYBOARD_H__
#define Matrixkey_Port P1
unsigned char Matrixkey_Scan(void);
#endif
keyboard.h
#include <reg52.h>
#include "keyboard.h"
#include "delay.h"
//按键按下返回键值(1-16)没有按下返回0
unsigned char Matrixkey_Scan(void)
{
unsigned char temp,row=0,col=0,i=0;
Matrixkey_Port=0x0f;//行为1列为0 0000 1111 ->0x0f
/*第一行若有按键按下 0000 1110 ->0x0e*/
/*第二行若有按键按下 0000 1101 ->0x0d*/
/*第三行若有按键按下 0000 1011 ->0x0b*/
/*第四行若有按键按下 0000 0111 ->0x07*/
Delay_xms(1);
temp=Matrixkey_Port;
if(temp!=0x0f)//说明有按键按下
{
if(temp==0x0e)row=1;
else if(temp==0x0d)row=2;
else if(temp==0x0b)row=3;
else if(temp==0x07)row=4;
Matrixkey_Port=0xf0;//行为0列1 1111 0000->0xf0
temp=Matrixkey_Port;
if(temp!=0xf0)//说明有按键按下
switch(temp)
{
/*第一列若有按键按下 0111 0000 ->0x70*/
/*第二列若有按键按下 1011 0000 ->0xb0*/
/*第三列若有按键按下 1101 0000 ->0xd0*/
/*第四列若有按键按下 1110 0000 ->0xe0*/
case 0xe0:col=1;break;
case 0xd0:col=2;break;
case 0xb0:col=3;break;
case 0x70:col=4;break;
default:break;
}
while(Matrixkey_Port!=0xf0&&i<255)//按键松开与超时判断
{
Delay_xms(1);
i++;
}
}
if(row!=0&&col!=0) return ((row-1)*4+col);
else return 0;
}
3.完整工程
本次工程包含的文件如下:
main.c
#include <reg52.h>
#include "delay.h"
#include "lcd1602.h"
#include "keyboard.h"
#define u8 unsigned char
u8 keynum,a;
void main()
{
LCD1602_Init();
while(1)
{
keynum=Matrixkey_Scan();
if(keynum!=0)
{
LCD1602_Dis_dat(0,0,keynum);
LCD1602_Dis_dat(1,0,a);
a++;
}
}
}
delay.h
#ifndef __DELAY_H__
#define __DELAY_H__
//延时100us
void Delay_100us();
//x=1时,大约延时50us
void Delay_50xus(unsigned int x);
//x=1时,大约延时1ms
void Delay_xms(unsigned int x);
#endif
delay.c
#include "delay.h"
#include <intrins.h>
void Delay_100us()
{
unsigned char i;
_nop_();
i=47;
while(--i);
}
void Delay_50xus(unsigned int x)
{
unsigned int i,j;
for(i=x;i>0;i--)
for(j=19;j>0;j--);
}
void Delay_xms(unsigned int x)
{
unsigned int i,j;
for(i=x;i>0;i--)
for(j=123;j>0;j--);
}
lcd1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__
//LCD1602写命令函数
void LCD1602_W_Cmd(unsigned char cmd);
//LCD1602写数据函数
void LCD1602_W_Dat(unsigned char dat);
//判忙函数,最高位位1即为忙
void LCD1602_BusyCheck();
//LCD1602初始化函数
void LCD1602_Init();
//LCD1602在指定位置显示字符hang:0-1,lie:0-15
void LCD1602_Dis_char(unsigned char hang,unsigned char lie,unsigned char ch);
//LCD1602在指定位置显示两位数据,比如20
void LCD1602_Dis_dat(unsigned char hang,unsigned char lie,unsigned char dat);
//LCD1602在指定位置显示字符串
void LCD1602_Dis_string(unsigned char hang,unsigned char lie,unsigned char *str);
#endif
lcd1602.c文章来源:https://www.toymoban.com/news/detail-508295.html
#include <reg52.h>
#include "lcd1602.h"
#include "delay.h"
#define LCD1602_Port P2
sbit LCD1602_RS=P3^5;
sbit LCD1602_RW=P3^6;
sbit LCD1602_EN=P3^7;
unsigned char LCD1602_Temp;
unsigned char LCD1602[]="LCD1602 Test Ok!";
void LCD1602_BusyCheck()
{
LCD1602_Port=0xff;
LCD1602_RS=0;
LCD1602_RW=1;
while(1)
{
LCD1602_EN=1;
LCD1602_Temp=LCD1602_Port;
LCD1602_EN=0;
if((LCD1602_Temp & 0x80)==0)break;
}
}
void LCD1602_W_Cmd(unsigned char cmd)
{
LCD1602_BusyCheck();
LCD1602_EN=0;
LCD1602_RS=0;
LCD1602_RW=0;
LCD1602_Port=cmd;
LCD1602_EN=1;
Delay_xms(1);
LCD1602_EN=0;
}
void LCD1602_W_Dat(unsigned char dat)
{
LCD1602_BusyCheck();
LCD1602_EN=0;
LCD1602_RS=1;
LCD1602_RW=0;
LCD1602_Port=dat;
LCD1602_EN=1;
Delay_xms(1);
LCD1602_EN=0;
}
void LCD1602_Init()
{
Delay_xms(15); //延时15ms
LCD1602_W_Cmd(0x38); //不检测忙信号
Delay_xms(5); //延时5ms
LCD1602_W_Cmd(0x38); //不检测忙信号
Delay_xms(5); //延时5ms
LCD1602_W_Cmd(0x38); //不检测忙信号
LCD1602_W_Cmd(0x38); //显示模式设置
LCD1602_W_Cmd(0x08); //显示关闭
LCD1602_W_Cmd(0x01); //显示清屏
LCD1602_W_Cmd(0x06); //显示光标移动设置,光标右移
LCD1602_W_Cmd(0x0C); //显示开及光标设置,光标关,闪烁关
}
void LCD1602_Dis_char(unsigned char hang,unsigned char lie,unsigned char ch)
{
if(hang==0){ LCD1602_W_Cmd(0x80+lie);}
if(hang==1){ LCD1602_W_Cmd(0xC0+lie);}
LCD1602_W_Dat(ch);
}
void LCD1602_Dis_dat(unsigned char hang,unsigned char lie,unsigned char dat)
{
unsigned char shi,ge;
shi=dat/10%10+0x30;
ge=dat%10+0x30;
LCD1602_Dis_char(hang,lie,shi);
LCD1602_Dis_char(hang,lie+1,ge);
}
void LCD1602_Dis_string(unsigned char hang,unsigned char lie,unsigned char *str)
{
unsigned char a;
if(hang==0)a=0x80;
if(hang==1)a=0xC0;
a=a+lie; //hang:0-1,lie:0-15
LCD1602_W_Cmd(a);
while(*str!='\0')
{
LCD1602_W_Dat(*str);
str++;
}
}
4.仿真图
5.资料包
基于Peoteus仿真的4X4矩阵键盘文章来源地址https://www.toymoban.com/news/detail-508295.html
到了这里,关于基于51单片机的矩阵键盘(线反转法)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!