前言
上一篇我们学习了模块化编程的思想,并且还使用了LCD1602显示屏的功能,这一篇我们学习矩阵键盘模块,并利用矩阵键盘和LCD1602显示屏完成密码锁的项目。
6-1 矩阵键盘
这一小节,我们学习用LCD1602显示屏显示我们矩阵键盘的键码值。
扫描的概念
我们的显示器都是矩阵连接扫描的。
按行扫描的时候,先检测P17-P14的中哪个为0,就是哪行的按键被按下,然后再检测P13-P10,即可判断这一行中哪个按键被按下。
- 但是不推荐逐行扫描,因为按行扫描P15会时高时低,而P15连接到步进电机,右边连接BZ,经过驱动器驱动会增加输出电流能力,连接到蜂鸣器上,这个开发板上BZ以一定频率高低变换时蜂鸣器会响。
按列扫描同理,先检测P13-P10,确定列,再检测P17-P14,即可确定哪列的哪个按键被按下。
这里还提到了单片机的I/O口是一种弱上拉强下拉的工作模式,这也是为什么LED和按键都是低电平(0)有效。(具体可以参考手册)
完整演示
由于上一篇我们已经引入模块化编程的思想,往后我们都采用模块化编程。
Delay和LCD1602的.c和.h文件我们已经写过,直接放进6-1这一节的工程文件。
我们先写几行代码测试下LCD1602能否使用。
#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
void main()
{
LCD_Init();
LCD_ShowString(1,1,"Star");
while(1)
{
}
}
正常使用√。
添加矩阵按键的模块化程序,编写Matrixkey.c和Matrixkey.h文件
.h文件的编写有固定的套路,我们可以编写好固定模板来方便我们编写代码。
Matrixkey.c代码
#include <REGX52.H>
#include "Delay.h"
/**
* @brief 矩阵键盘读取按键键码
* @param 无
* @retval KeyNumber 按下按键的键码值
如果按键按下不放,程序会停留在此函数,松手的一瞬间返回按键键码,没有按键按下时返回零
*/
unsigned char Matrixkey() //按列扫描
{
unsigned char KeyNumber=0;//局部变量引用必须赋初始值
P1=0xFF;
P1_3=0;//扫描第一列
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;} //S1的检测
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;} //S5的检测
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;} //S9的检测
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;} //S13的检测
P1=0xFF;
P1_2=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;} //S2的检测
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;} //S6的检测
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;} //S10的检测
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;} //S14的检测
P1=0xFF;
P1_1=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;} //S3的检测
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;} //S7的检测
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;} //S11的检测
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;} //S15的检测
P1=0xFF;
P1_0=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;} //S4的检测
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;} //S8的检测
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;} //S12的检测
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;} //S16的检测
return KeyNumber;
}
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;}
- 在扫描第一列时,如果P1_7==0,那么此时是判断开关1的状态
- 由于是机械按键,加入延时函数消除抖动,然后判断是否松手;如果松手,继续消除抖动
- 返回值KeyNumber
Matrixkey.h代码
#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__
unsigned char Matrixkey();
#endif
主函数代码
#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "MatrixKey.h"
/**
* @brief 矩阵键盘读取按键键码
* @param 无
* @retval KeyNumber 按下按键的键码值
如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键键码,没有按键按下返回0.
*/
unsigned char KeyNum;
void main()
{
LCD_Init();
LCD_ShowString(1,1,"MatrixKey:");
while(1)
{
KeyNum=MatrixKey();
if(KeyNum)//if (KeyNum==0)
{
LCD_ShowNum(2,1,KeyNum,2);
}
}
}
没加if(KeyNum)的时候,我们始终显示的是00,因为我们的代码运行速度很快,按下按键后其实显示数字了,但是很快又进入了新循环,所以一直显示初始的00。
6-2 矩阵键盘密码锁
这一小节,我们学习制作一个电子密码锁。
- 直接复制6-1的工程文件
- 首先定义按键的作用,S1-S9定义为数字的1-9,S10定义为0,S11为确认键,S12为取消键,S13-S16按键不用。
#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "MatrixKey.h"
/**
* @brief 矩阵键盘读取按键键码
* @param 无
* @retval KeyNumber 按下按键的键码值
如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键键码,没有按键按下返回0.
*/
unsigned char KeyNum;
unsigned int Password,Count;
void main()
{
LCD_Init();
LCD_ShowString(1,1,"Password:");
while(1)
{
KeyNum=MatrixKey();
if(KeyNum)
{
if(KeyNum<=10) //如果s1-s10按键按下,输入密码
{
if(Count<4) //输入次数小于4
{
Password*=10; //密码左移1位
Password+=KeyNum%10; //获取1位密码
Count++; //计次加一
LCD_ShowString(1,14," ");
}
LCD_ShowNum(2,1,Password,4); //更新显示
}
if(KeyNum==11) //如果s11按键按下,确认密码
{
if(Password==2468) //如果密码等于正确密码,显示ok
{
LCD_ShowString(1,14,"ok ");
P2=0xFE;//1111 1110
Delay(500);
P2=0xFD;//1111 1101
Delay(500);
P2=0xFB;//1111 1011
Delay(500);
P2=0xF7;//1111 0111
Delay(500);
P2=0xEF;//1110 1111
Delay(500);
P2=0xDF;//1101 1111
Delay(500);
P2=0xBF;//1011 1111
Delay(500);
P2=0x7F;//0111 1111
Delay(500);
Password=0; //密码清零
Count=0; //计次清零
LCD_ShowNum(2,1,Password,4); //更新显示
}
else
{
LCD_ShowString(1,14,"ERR");//显示错误
Password=0; //密码清零
Count=0; //计次清零
LCD_ShowNum(2,1,Password,4); //更新显示
}
}
if(KeyNum==12) //如果s12按键按下,取消
{
Password=0; //密码清零
Count=0; //计次清零
LCD_ShowNum(2,1,Password,4); //更新显示
}
}
}
}