15. 矩阵键盘
15.1. 矩阵键盘介绍
•在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式
•采用逐行或逐列的“扫描”,就可以读出任何位置按键的状态
15.2. 扫描的概念:
•数码管扫描(输出扫描)原理:显示第1位→显示第2位→显示第3位→……,然后快速循环这个过程,最终实现所有数码管同时显示的效果
•矩阵键盘扫描(输入扫描)
原理:读取第1行(列)→读取第2行(列) →读取第3行(列) → ……,然后快速循环这个过程,最终实现所有按键同时检测的效果
•以上两种扫描方式的共性:节省I/O口
15.3. 开发板采用逐列扫描代替逐行扫描的原因是P15口连接蜂鸣器会导致如果用逐行扫描,蜂鸣器会有规律的响,所以用逐列扫描;
15.4. 单片机IO口特性弱上拉,强下拉
15.5. 矩阵键盘程序模块实操;
建立矩阵键盘程序文件夹 6-1 矩阵键盘
将之前项目钟的LCD1602.c与LCD1602.h;以及delay_xms.c 与delay_xms.h ;拷贝到项目目录中,并在Keil项目目录中导入;
Keil中转到template类别:
右键点击空白区域选择configure templates
点击左边的图标新建模板,右边的x是对选中的模板进行删除
新建一个#include名称的模板,在下面的text中输入如下代码,以便于后续新建51程序的编程;
在main.c程序中测试模板如下:
15.6. 程序中之前定义的函数无法转到相应的函数的定义,根据作者说明和尝试,需要关闭Keil程序,然后重新打开生效:
- 关闭Keil并重新打开后如图可以转到 LCD_Init()函数定义:
- 关闭Keil并重新打开后如图可以转到 LCD_Init()函数定义:
15.7. 编程的理念是边做边测试,以及早发现问题并解决相应的问题。
15.8. MATRIXKEY.c 有返回值的矩阵键盘模块程序样例;
#include <REGX52.h>
#include "delay_xms.h"
/**
* @brief 矩阵键盘读取按键码程序
* @param 无
* @retval KeyNumber按下按键的键码值
如果按键按下不放,程序会停留在此函数,松手瞬间,返回按键键码值,
没有按键按下时,返回0;
*/
unsigned char MatrixKey()
{
unsigned char KeyNumber=0;//初始化KeyNumber为0;
P1=0xff;//P1先全部置于1;
P1_3=0; //再将P13口置于0;以下为S1,S5,S9,S13的检测
if(P1_7==0){delay_xms(20);while(P1_7==0);delay_xms(20);KeyNumber=1;}
if(P1_6==0){delay_xms(20);while(P1_6==0);delay_xms(20);KeyNumber=5;}
if(P1_5==0){delay_xms(20);while(P1_5==0);delay_xms(20);KeyNumber=9;}
if(P1_4==0){delay_xms(20);while(P1_4==0);delay_xms(20);KeyNumber=13;}
P1=0xff;//P1先全部置于1;
P1_2=0; //再将P12口置于0;以下为S2,S6,S10,S14的检测
if(P1_7==0){delay_xms(20);while(P1_7==0);delay_xms(20);KeyNumber=2;}
if(P1_6==0){delay_xms(20);while(P1_6==0);delay_xms(20);KeyNumber=6;}
if(P1_5==0){delay_xms(20);while(P1_5==0);delay_xms(20);KeyNumber=10;}
if(P1_4==0){delay_xms(20);while(P1_4==0);delay_xms(20);KeyNumber=14;}
P1=0xff;//P1先全部置于1;
P1_1=0; //再将P11口置于0;以下为S3,S7,S11,S15的检测
if(P1_7==0){delay_xms(20);while(P1_7==0);delay_xms(20);KeyNumber=3;}
if(P1_6==0){delay_xms(20);while(P1_6==0);delay_xms(20);KeyNumber=7;}
if(P1_5==0){delay_xms(20);while(P1_5==0);delay_xms(20);KeyNumber=11;}
if(P1_4==0){delay_xms(20);while(P1_4==0);delay_xms(20);KeyNumber=15;}
P1=0xff;//P1先全部置于1;
P1_0=0; //再将P11口置于0;以下为S4,S8,S12,S16的检测
if(P1_7==0){delay_xms(20);while(P1_7==0);delay_xms(20);KeyNumber=4;}
if(P1_6==0){delay_xms(20);while(P1_6==0);delay_xms(20);KeyNumber=8;}
if(P1_5==0){delay_xms(20);while(P1_5==0);delay_xms(20);KeyNumber=12;}
if(P1_4==0){delay_xms(20);while(P1_4==0);delay_xms(20);KeyNumber=16;}
return KeyNumber;
}
- 15.9. 矩阵键盘MatrixKey.h文件代码:
#ifndef _MATRIXKEY_H_
#define _MATRIXKEY_H_
unsigned char MatrixKey();
#endif
- 15.10. 矩阵键盘按任意数字LCD1602显示相应的数字的测试程序
#include <REGX52.h>
#include "LCD1602.h"
#include "delay_xms.h"
#include "MatrixKey.h"
unsigned char KeyNum; //定义KeyNum接一下MatrixKey返回值
void main()
{
LCD_Init(); //LCD1602初始化
LCD_ShowString(1,1,"Input Password:");
while(1)
{
KeyNum=MatrixKey();//KeyNum接返回的MatrixKey返回值
if(KeyNum) //如果KeyNum不为0,即为真1,如果不加此if判断
//则按键按下的时候瞬间跳一个S*的值然后归0000
//进入到下一个循环中!!
{
LCD_ShowNum(2,1,KeyNum,4);
}
}
}
Proteus测试结果如下:
15.11. 模块化编程规范注释-模板:
/**
* @brief |
* @param
* @retval
*/
16. 矩阵键盘密码锁
- 16.1. 直接拷贝上一节的工程目录,更改目录名称成为新的工程“ 6-2 矩阵键盘密码锁”
#include <REGX52.h>
#include "LCD1602.h"
#include "delay_xms.h"
#include "MatrixKey.h"
unsigned char KeyNum,countnum; //定义KeyNum接一下MatrixKey返回值
unsigned int psw;
void main()
{
LCD_Init(); //LCD1602初始化
LCD_ShowString(1,1,"Password:");
while(1)
{
KeyNum=MatrixKey();//KeyNum接返回的MatrixKey返回值
if(KeyNum) //如果KeyNum不为0,即为真1,如果不加此if判断
//则按键按下的时候瞬间跳一个S*的值然后归0000
//进入到下一个循环中!!
{
if(KeyNum<=10) //如果S1~S10按键按下,输入密码
{
if(countnum<4)
{
psw*=10; //密码左移一位
psw+=KeyNum%10; //获取一位密码,让S10按下的时候为0;
countnum++;
}
LCD_ShowNum(2,1,psw,4);
}
if(KeyNum==11) //S11定义为确认键
{
if(psw==2345) //如果密码等于正确密码2345
{
LCD_ShowString(1,14,"OK "); //显示OK
psw=0; //密码清零
countnum=0; //计次清零
LCD_ShowNum(2,1,psw,4); //清零后继续显示
}
else //如果不等于正确密码
{
LCD_ShowString(1,14,"ERR"); //显示ERR错误
psw=0; //密码清零
countnum=0; //计次清零
LCD_ShowNum(2,1,psw,4); //清零后继续显示
}
}
if(KeyNum==12) //S12 定义为取消键,直接密码和计次清零,重新输入
{
psw=0; //密码清零
countnum=0; //计次清零
LCD_ShowNum(2,1,psw,4); //清零后继续显示
}
}
}
}
16.2. Proteus测试没问题;
16.3. 小结:
程序设计要有结构化的思维;
主要难点在于逻辑表达;
边设计边测试比较好;