51单片机学习记录07
矩阵键盘
在键盘中按键较多时,将按键排列为矩阵形式,以减少I/O口的占用
采用逐行或逐列的“扫描”,就可以读出任何位置按键的状态
- 原理图
- P17 ~ 14控制行;P13 ~ 10控制列
- P1端是接到单片机上,单片机上电的时候所有I/O口默认都是高电平,如果按键没有按下,I/O口保持高电平;如果按下按键,I/O口变成低电平,因为接地了。所以按键给0时按下。
- 单片机“弱上拉,强下拉”。输出1,驱动能力很弱;输出0,驱动能力比较强。
矩阵键盘应用
显示键码值在LCD上
利用模块化编程、Templates自定义函数框架放置驱动代码,将重心放在主函数的逻辑代码上
- 导入Delay、LCD1602头文件
- 按键扫描——创建MatrixKey.h及.c文件
MatrixKey.h
#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__
unsigned char MatrixKey();
#endif
- P17 ~ 14控制行;P13 ~ 10控制列,
- P1全部置高电平,对于列(P13 ~ 10)其中一列给0即扫描该列
- 延迟消抖、检测松手,在同一列的基础上,扫描每一行
- 判断当扫描到其中一行(P17~14)等于0时,表示按下,返回按键值
MatrixKey.c
#include <REGX52.H>
#include "Delay.h"
unsigned char MatrixKey() //扫描按键(先列后行)
{
unsigned char KeyNumber=0; //初始化
P1=0xFF; //P1全部置高电平
P1_3=0; //第一列
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;}
P1=0xFF; //P1全部置高电平
P1_2=0; //第二列
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;}
P1=0xFF; //P1全部置高电平
P1_1=0; //第三列
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;}
P1=0xFF; //P1全部置高电平
P1_0=0; //第四列
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;}
return KeyNumber;//用返回值代替按键值
}
main.c
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"
unsigned char KeyNum;
void main()
{
LCD_Init();
LCD_ShowString(1,1,"MatrixKey:");
while(1)
{
KeyNum=MatrixKey();
if(KeyNum) //判断“当按键值不为零”为真时
{
LCD_ShowNum(2,1,KeyNum,2); //在LCD第二行第一列开始显示长度为2的按键值
}
}
}
矩阵密码锁
- 大框架的两个if语句都是在**判断按键按下if(KeyNum)**的条件下进行的
- 输入密码:乘十数字左移,取余获得一位数
- 确认密码:判断完毕后,计数与密码都要清零
- 取消密码:全部取消or按位取消(注意计次变化)
计次是防止输入数字超出正确密码位数
main.c
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"
unsigned char KeyNum;
unsigned int Password,Count; //全局变量默认初始值为0
void main()
{
LCD_Init();
LCD_ShowString(1,1,"Password:");
while(1)
{
KeyNum=MatrixKey();
if(KeyNum) //按键按下
{
if(KeyNum<=10) //S1~S10按键按下,输入密码
{
if(Count<4) //按下次数
{
Password*=10; //Password初始值默认为0,左移一位
Password+=KeyNum%10; //获取一位密码
Count++; //计次
}
LCD_ShowNum(2,1,Password,4); //更新显示
}
if(KeyNum==11) //如果S11按键按下,确认
{
if(Password==5678) //输入正确
{
LCD_ShowString(1,11,"OK "); //显示OK
Password=0; //密码清零
Count=0; //计次清零
LCD_ShowNum(2,1,Password,4);
}
else //输入错误
{
LCD_ShowString(1,11,"ERR"); //显示OK
Password=0; //密码清零
Count=0; //计次清零
LCD_ShowNum(2,1,Password,4);
}
}
if(KeyNum==12) //如果S12按键按下,取消
{
Password=0; //密码清零
Count=0; //计次清零
LCD_ShowNum(2,1,Password,4);
}
if(KeyNum==13) //如果S13按键按下,按位取消
{
if(Count>0)
{
Password/=10; //右移一位
Count--; //取消一次计数
LCD_ShowNum(2,1,Password,4);
}
}
}
}
}