基于51单片机的矩阵键盘_Matrixkey---线反转法

1.矩阵键盘简介

矩阵键盘使用的方法与独立按键类似,但是比独立按键节省I/O,同时使用方法变得相对复杂了,首先展示硬件连接。
基于51单片机的矩阵键盘_Matrixkey---线反转法_第1张图片
上图所示就是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 
#include "keyboard.h"
#include "delay.h"
//按键按下返回键值(1-16)没有按下返回0
unsigned char Matrixkey_Scan(void)
{
	unsigned char temp,row,col,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 
#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 

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

#include 
#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.仿真图

基于51单片机的矩阵键盘_Matrixkey---线反转法_第2张图片

你可能感兴趣的:(单片机,单片机)