1.从矩阵键盘原理图可知,矩阵键盘流通方向是图二2.1和2.2的两幅图红线位置,然后总的就是图二的2.3的位置,也就是P17,P16,P15,P14口的经过的按键s1,s5,s9,s11对应的是P13位置,由于按键没有按下,则没有导通,也就是单片机的两个IO口连接,也就是图一,图一蓝色位置为开关,如果IO口里面是VCC的时候,就会跳到VCC的那里,如果是GND则跳到GND的位置,然后另一个IO口则连接起来。
2.单片机IO口默认高电平,所以我们给P17,P16,P15,P14口高电平,P13口低电平,如图三3.1,所以如果按下按键s1的话,就导通,之后会变成图三的3.2。
Matrix.h
#ifndef __MATRIX_H__
#define __MATRIX_H__
unsigned char MatrixKey(void);
#endif
Matrix.c
#include
#include "Delay.h"
unsigned char MatrixKey() //矩阵按键函数
{
unsigned char keynumber=0;
P1=0xFF;
P1_3=0; //扫描第一列
if(P1_7==0){Delay20ms();while(P1_7==0);Delay20ms();keynumber=1;}//按下松开后,keynumber=1,也就是按了k1
if(P1_6==0){Delay20ms();while(P1_6==0);Delay20ms();keynumber=5;}
if(P1_5==0){Delay20ms();while(P1_5==0);Delay20ms();keynumber=9;}
if(P1_4==0){Delay20ms();while(P1_4==0);Delay20ms();keynumber=13;}
P1=0xFF;
P1_2=0; //扫描第二列
if(P1_7==0){Delay20ms();while(P1_7==0);Delay20ms();keynumber=2;}
if(P1_6==0){Delay20ms();while(P1_6==0);Delay20ms();keynumber=6;}
if(P1_5==0){Delay20ms();while(P1_5==0);Delay20ms();keynumber=10;}
if(P1_4==0){Delay20ms();while(P1_4==0);Delay20ms();keynumber=14;}
P1=0xFF;
P1_1=0; //扫描第三列
if(P1_7==0){Delay20ms();while(P1_7==0);Delay20ms();keynumber=3;}
if(P1_6==0){Delay20ms();while(P1_6==0);Delay20ms();keynumber=7;}
if(P1_5==0){Delay20ms();while(P1_5==0);Delay20ms();keynumber=11;}
if(P1_4==0){Delay20ms();while(P1_4==0);Delay20ms();keynumber=15;}
P1=0xFF;
P1_0=0; //扫描第四列
if(P1_7==0){Delay20ms();while(P1_7==0);Delay20ms();keynumber=4;}
if(P1_6==0){Delay20ms();while(P1_6==0);Delay20ms();keynumber=8;}
if(P1_5==0){Delay20ms();while(P1_5==0);Delay20ms();keynumber=12;}
if(P1_4==0){Delay20ms();while(P1_4==0);Delay20ms();keynumber=16;}
return keynumber;
}
Delay.h
#ifndef __DALAY_H__
#define __DALAY_H__
void Delay1ms(void);
void Delay20ms(void);
#endif
Delay.c
#include
#include
void Delay1ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
void Delay20ms() //@11.0592MHz
{
unsigned char i, j;
i = 36;
j = 217;
do
{
while (--j);
} while (--i);
}
LCD1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__
void LCD_Init(void);
void LCD_Showstring(unsigned char line,unsigned char column,unsigned char *string);
void LCD_Shownum(unsigned char line,unsigned char column,unsigned int number,unsigned char length);
#endif
LCD1602.c
#include
#include "Delay.h"
#define LCE_Dataport P0
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
void LCD_WriteCommand(unsigned char Command)//写指令
{
LCD_RS=0;
LCD_RW=0;
LCE_Dataport=Command;
LCD_EN=1;
Delay1ms();
LCD_EN=0;
Delay1ms();
}
void LCD_WriteData(unsigned char Data)//写数据
{
LCD_RS=1;
LCD_RW=0;
LCE_Dataport=Data;
LCD_EN=1;
Delay1ms();
LCD_EN=0;
Delay1ms();
}
void LCD_Init(void)//初始化
{
LCD_WriteCommand(0x38);
LCD_WriteCommand(0x0C);
LCD_WriteCommand(0x06);
LCD_WriteCommand(0x01);
}
void LCD_Setcursor(unsigned char line,unsigned char column)
{
if(line==1)//设置光标位置
{
//第一列是数字1,但是位置是0x00,要把数字1转换0x00,就把数字1-1就0,所以转十六进制就是0x00
LCD_WriteCommand(0x80|(column-1));
}
else
{
//第二行的第一列是从0x40开始,第二列是0x41,相当于0x40+0x01,0x01就是与上面一致
LCD_WriteCommand(0x80|(column-1)+0x40);
}
}
void LCD_Showstring(unsigned char line,unsigned char column,unsigned char *string)//line行,column列,string字符串
{//显示字符串,字符串直接等于指针,不用数组形式等于字符串,在等于指针形式,那传给指针的就是字符串的第一个字符的地址,然后string【i】一直往下就可以知道字符串,数组是连续的,如果baby的b在第一行第一列,那a就会在第一行,第二列。
unsigned char i;
LCD_Setcursor(line,column);
for(i=0;string[i]!='\0';i++)
{
LCD_WriteData(string[i]);//字符串本身就是地址,所以传进来的字符串用指针string来接
}
}
int LCD_Pow(int X,int Y)
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}
void LCD_Shownum(unsigned char line,unsigned char column,unsigned int number,unsigned char length)
{
unsigned char i;
LCD_Setcursor(line,column);
for(i=length;i>0;i--)
{
LCD_WriteData('0'+number/LCD_Pow(10,i-1) %10);
}
}
main.c
#include
#include "LCD1602.h"
#include "Matrix.h"
unsigned char keynum;
void main()
{
LCD_Init();
while(1)
{
keynum=MatrixKey();//定义变量keynum接收MatrixKey();的返回值
LCD_Showstring(1,1,"hello");
//这里必须加if语句,因为不加的话,假如按下按键1,while循环第一次循环,返回1,但是while执行的很快,
//第二次在进入while的时候检测没有按下按键,由于设置keynumber=0,所以会返回0,然后就会显示0,无论怎么按,肉眼无法观察,
//加了if以后,keynumber=0时,无法进入if语句,因为if要真的才能进去,非0即真,0假
if(keynum)
{
LCD_Shownum(2,1,keynum,2);
}
}
}
Matrix.h
#ifndef __MATRIX_H__
#define __MATRIX_H__
unsigned char MatrixKey(void);
#endif
Matrix.c
#include
#include "Delay.h"
unsigned char MatrixKey() //矩阵按键函数
{
unsigned char keynumber=0;
P1=0xFF;
P1_3=0; //扫描第一列
if(P1_7==0){Delay20ms();while(P1_7==0);Delay20ms();keynumber=1;}//按下松开后,keynumber=1,也就是按了k1
if(P1_6==0){Delay20ms();while(P1_6==0);Delay20ms();keynumber=5;}
if(P1_5==0){Delay20ms();while(P1_5==0);Delay20ms();keynumber=9;}
if(P1_4==0){Delay20ms();while(P1_4==0);Delay20ms();keynumber=13;}
P1=0xFF;
P1_2=0; //扫描第二列
if(P1_7==0){Delay20ms();while(P1_7==0);Delay20ms();keynumber=2;}
if(P1_6==0){Delay20ms();while(P1_6==0);Delay20ms();keynumber=6;}
if(P1_5==0){Delay20ms();while(P1_5==0);Delay20ms();keynumber=10;}
if(P1_4==0){Delay20ms();while(P1_4==0);Delay20ms();keynumber=14;}
P1=0xFF;
P1_1=0; //扫描第三列
if(P1_7==0){Delay20ms();while(P1_7==0);Delay20ms();keynumber=3;}
if(P1_6==0){Delay20ms();while(P1_6==0);Delay20ms();keynumber=7;}
if(P1_5==0){Delay20ms();while(P1_5==0);Delay20ms();keynumber=11;}
if(P1_4==0){Delay20ms();while(P1_4==0);Delay20ms();keynumber=15;}
P1=0xFF;
P1_0=0; //扫描第四列
if(P1_7==0){Delay20ms();while(P1_7==0);Delay20ms();keynumber=4;}
if(P1_6==0){Delay20ms();while(P1_6==0);Delay20ms();keynumber=8;}
if(P1_5==0){Delay20ms();while(P1_5==0);Delay20ms();keynumber=12;}
if(P1_4==0){Delay20ms();while(P1_4==0);Delay20ms();keynumber=16;}
return keynumber;
}
Delay.h
#ifndef __DALAY_H__
#define __DALAY_H__
void Delay1ms(void);
void Delay20ms(void);
#endif
Delay.c
#include
#include
void Delay1ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
void Delay20ms() //@11.0592MHz
{
unsigned char i, j;
i = 36;
j = 217;
do
{
while (--j);
} while (--i);
}
LCD1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__
void LCD_Init(void);
void LCD_Showstring(unsigned char line,unsigned char column,unsigned char *string);
void LCD_Shownum(unsigned char line,unsigned char column,unsigned int number,unsigned char length);
#endif
LCD1602.c
#include
#include "Delay.h"
#define LCE_Dataport P0
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
void LCD_WriteCommand(unsigned char Command)//写指令
{
LCD_RS=0;
LCD_RW=0;
LCE_Dataport=Command;
LCD_EN=1;
Delay1ms();
LCD_EN=0;
Delay1ms();
}
void LCD_WriteData(unsigned char Data)//写数据
{
LCD_RS=1;
LCD_RW=0;
LCE_Dataport=Data;
LCD_EN=1;
Delay1ms();
LCD_EN=0;
Delay1ms();
}
void LCD_Init(void)//初始化
{
LCD_WriteCommand(0x38);
LCD_WriteCommand(0x0C);
LCD_WriteCommand(0x06);
LCD_WriteCommand(0x01);
}
void LCD_Setcursor(unsigned char line,unsigned char column)
{
if(line==1)//设置光标位置
{
//第一列是数字1,但是位置是0x00,要把数字1转换0x00,就把数字1-1就0,所以转十六进制就是0x00
LCD_WriteCommand(0x80|(column-1));
}
else
{
//第二行的第一列是从0x40开始,第二列是0x41,相当于0x40+0x01,0x01就是与上面一致
LCD_WriteCommand(0x80|(column-1)+0x40);
}
}
void LCD_Showstring(unsigned char line,unsigned char column,unsigned char *string)//line行,column列,string字符串
{//显示字符串,字符串直接等于指针,不用数组形式等于字符串,在等于指针形式,那传给指针的就是字符串的第一个字符的地址,然后string【i】一直往下就可以知道字符串,数组是连续的,如果baby的b在第一行第一列,那a就会在第一行,第二列。
unsigned char i;
LCD_Setcursor(line,column);
for(i=0;string[i]!='\0';i++)
{
LCD_WriteData(string[i]);//字符串本身就是地址,所以传进来的字符串用指针string来接
}
}
int LCD_Pow(int X,int Y)
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}
void LCD_Shownum(unsigned char line,unsigned char column,unsigned int number,unsigned char length)
{
unsigned char i;
LCD_Setcursor(line,column);
for(i=length;i>0;i--)
{
LCD_WriteData('0'+number/LCD_Pow(10,i-1) %10);
}
}
main.c
#include
#include "LCD1602.h"
#include "Matrix.h"
unsigned char keynum;
unsigned int password,count;
void main()
{
LCD_Init();
while(1)
{
keynum=MatrixKey();//定义变量keynum接收MatrixKey();的返回值
LCD_Showstring(1,1,"password:");
//这里必须加if语句,因为不加的话,假如按下按键1,while循环第一次循环,返回1,但是while执行的很快,
//第二次在进入while的时候检测没有按下按键,由于设置keynumber=0,所以会返回0,然后就会显示0,无论怎么按,肉眼无法观察,
//加了if以后,keynumber=0时,无法进入if语句,因为if要真的才能进去,非0即真,0假
if(keynum)
{
if(keynum<=10) //如果s1-s10按键按下,代表输入密码
{
if(count<4) //输入次数小于4
{
password*=10; //密码从右边开始输入完一位就向左移一位就会大10倍,所以这里是向左移一位
password+=keynum%10; //s1-s9取余就是1—9,s10取余就是0,所以s1-s9对应数字9,s10对应0,
}
count++; //记录按下按键次数
LCD_Shownum(2,1,password,4);//显示密码四位
}
if(keynum==11) //确认键
{
if(password==0x7B) //正确密码0123,0开头的密码会被表示成八进制,而不是十进制的0123,所以我们写密码,写十六进制就可以了
{
LCD_Showstring(1,14,"OK "); //输入成功,这里的ok后面需要加一个空格,因为输入错误以后的r会留下
password=0; //密码清0
count=0; //按键次数清0
LCD_Shownum(2,1,password,4);//显示密码四位
}
else //错误密码
{
LCD_Showstring(1,14,"ERR"); //输入失败
password=0; //密码清0
count=0; //按键次数清0
LCD_Shownum(2,1,password,4);//显示密码四位
}
}
if(keynum==12) //取消键
{
password=0; //密码清0
count=0; //按键次数清0
LCD_Shownum(2,1,password,4);//显示密码四位
LCD_Showstring(1,14," ");//四个空格来取消掉之前写的err和ok
}
if(keynum==13) //密码退位键
{
password/=10;
count--;
LCD_Shownum(2,1,password,4);//显示密码四位
}
}
}
}