❤️ 专栏简介:本专栏记录了从零学习单片机的过程,其中包括51单片机和STM32单片机两部分;建议先学习51单片机,其是STM32等高级单片机的基础;这样再学习STM32时才能融会贯通。
☀️ 专栏适用人群 :适用于想要从零基础开始学习入门单片机,且有一定C语言基础的的童鞋。
🌙专栏目标:实现从零基础入门51单片机和STM32单片机,力求在玩好单片机的同时,能够了解一些计算机的基本概念,了解电路及其元器件的基本理论等。⭐️ 专栏主要内容: 主要学习51单片机的功能、各个模块、单片机的外设、驱动等,最终玩好单片机和单片机的外设,全程手敲代码,实现我们所要实现的功能。
🌴 专栏说明 :如果文章知识点有错误的地方,欢迎大家随时在文章下面评论,我会第一时间改正。让我们一起学习,一起进步。
💑专栏主页:http://t.csdn.cn/HCD8v
本学习过程参考:https://space.bilibili.com/383400717
单片机安装软件、各种资料以及源码的路径:
https://pan.baidu.com/s/1vDTN2o8ffvczzNQGfyjHng
提取码:gdzf
本节主要介绍LCD1602调试工具,用于对调试代码进行输出显示,方便我们对开发过程中代码的调试工作。本文会提供LCD1602的使用方法、驱动代码、以及演示LCD1602调试过程。
文章目录
- 一、矩阵键盘介绍和本节目标
- 1.1 矩阵键盘介绍
- 1.1.1 矩阵键盘概念
- 1.1.2 矩阵键盘原理
- 1.1.2.1扫描过程:
- 1.1.2.2 单片机i/o口弱上拉模式
- 1.2 本节目标
- 二、读取并显示矩阵键盘按键
- 三、矩阵键盘密码锁
一、矩阵键盘介绍和本节目标
1.1 矩阵键盘介绍
1.1.1 矩阵键盘概念
相较于独立按键,矩阵键盘可以减少i/o口的占用。
独立按键是每个按键都占用一个i/o口;而矩阵键盘是利用四行四列达到16个键盘占用8个i/o口的目的;减少了i/o口的占用。有点类似于利用坐标系,用行号和列号来定位具体的键盘。即采用逐行或逐列的“扫描”,就可以独处任何位置按键的状态。
什么是扫描呢?
1.1.2 矩阵键盘原理
矩阵键盘的原理图有下图所示,左边是独立按键的原理图,右边是矩阵键盘的原理图,放在一起比较更容易理解。
1.1.2.1扫描过程:
独立按键是将四个按键公共的一端都接在GND即低电平上,另一端连接在i/o口上;而独立按键呢,是每一行连接到一个公共的i/o上,每一列也连接到一个公共的i/o口上;
我们可以假设,矩阵按键第一行的一端都接在GND上,另一端接四列的i/o口,那么此时就变成和独立按键一模一样,如下图所示:
此时就成了按行扫描的过程,因为一端已经接了GND即低电平,那么此时如果检测到P13=0,说明是S1按下了;如果是P12=0,说明是S2按下了;如果是P11=0,说明是S3按下了;如果是P10=0,说明是S4按下了;此时第一行就扫描结束了,同时也得到了S1-S4 4个按键的状态。
如果想知道为什么公共端设置为0,然后检测另一端是否为0,来判断是否按下按键,请看第1.1.2.2节的介绍。
然后就可以判断第二行了,判断第二行时,将第一行的公共端(也就是P17口)设置为1;第二行的公共端(也就是P16口)设置为0;第三行的公共端(也就是P15)设置为1;第四行的公共端(也就是P14)设置为1;总结一下就是扫描哪一行,哪一行的公共端给0,其他行的公共端给1
;然后判断P13-P10的值,如果P13=0,说明是S5按下了;如果是P12=0,说明是S6按下了;如果是P11=0,说明是S7按下了;如果是P10=0,说明是S8按下了;此时第二行就扫描结束了,同时也得到了S5-S8 4个按键的状态。如下图:
同理,如果扫描第三行时,将第一行的公共端(也就是P17口)设置为1;第二行的公共端(也就是P16口)设置为1;第三行的公共端(也就是P15)设置为0;第四行的公共端(也就是P14)设置为1;总结一下就是扫描哪一行,哪一行的公共端给0,其他行的公共端给1
;然后判断P13-P10的值,如果P13=0,说明是S9按下了;如果是P12=0,说明是S10按下了;如果是P11=0,说明是S11按下了;如果是P10=0,说明是S12按下了;此时第三行就扫描结束了,同时也得到了S9-S11 4个按键的状态。如下图:
第四行同理,这四行全都扫描完一遍后,16个按键的状态也就都得到了。
按列扫描也是同样的道理,即将P13-P12口赋值0和1,然后分别读取P17-P14,从而获得16个按键的状态。
由于按行扫描时,P15口会反复的给0和给1,而P15口又连接着蜂鸣器,所以如果按行扫描,就会导致蜂鸣器一直响,且无法关掉,这是由引脚和外设的冲突引起的,无法避免;所以建议使用按列臊面来获得矩阵键盘的状态。
补充一个知识点,为什么在扫描具体的某一行时,要使其公共端赋值为低电平0,另外的三个行的公共端赋值为高电平1呢?这就涉及到了单片机i/o口的弱上拉模式。
1.1.2.2 单片机i/o口弱上拉模式
i/o口的弱上拉模式又叫准双向口(可以去看51单片机入门教程资料\课件及程序源码\相关资料\STC89C52.pdf
中的第4.1.1节:准双向口输出配置);i/o口即iniput/output,既可以输入又可以输出。那i/o是如何达到输出和输入呢?
举个例子,如果现在有两个i/o口,A口是高电平1,B口是低电平0,将A和B直接连接在一起,有同学说这不就短路了嘛,确实像是短路,但是没有问题;就是因为单片机是弱上拉模式,即单片机的上拉能力是弱的;也就是说高电平的驱动能力是有限的,而低电平0的驱动能力是很强的,也可以称为弱上拉,强下拉
;
更加详细的原理解释,请参考视频(https://www.bilibili.com/video/BV1Mb411e7re?p=15&vd_source=e2638d12685eef84cda913d9d67be0a9)的17分30秒
总结下来一句话,弱上拉强下拉就是1弱0强;也就是当低电平0和高电平1同时出现时,表现的是低电平0
;
所以这里再解释一遍扫描的原理:
当第一行的公共端(P17)接了低电平0,那么S1的另一端(P13)在上电时默认是高电平1,所以当S1按键未按下时,读取P13的状态得到的是高电平1
;当S1按下时,P17和P13连接在了一起,P17是低电平,而P13在连接的一瞬间,由于弱上拉强下拉原理(1弱0强),P13也就瞬间从高电平1变成了低电平0;所以,当检测到P13是0时,也就说明S1按下了(因为S1不按下,P13检测到的值会是1)。
1.2 本节目标
目标1:读取矩阵键盘每次按下的数值,并将该数值显示在LCD1602上;
例如,当按下第一个矩阵按键S1时,LCD1602显示01;当按下第二个矩阵按键S2时,LCD1602显示02;依次类推,如下图所示:
当按下S1时:
当按下S2时:
依次类推。
目标2:利用矩阵键盘实现密码锁
密码锁具体的过程如下,当上电后,该密码锁在LCD1602上显示初始值Password:0000
,
然后当我们按下S1按键时,显示数字1,如下:
接着我们按下S2时,显示数字2,如下:
接着我们按下S3,显示数字3,如下:
最后我们按下S4,显示数字4,如下:
最终的结果是我们输入了密码1234,(说明:S1-S9对应着数字1-9,S10表示数字0,S11表示“确认”,S12表示取消
),然后按下S11确认,结果显示ERR,表示密码错误,并将数字清零,如下:
因为我们设置的正确密码是2345,所以输入2345后,结果显示OK,表示密码正确,如下:
二、读取并显示矩阵键盘按键
代码路径:51单片机入门教程资料\课件及程序源码\程序源码\KeilProject\6-1 矩阵键盘
具体代码:
#include <REGX52.H>
#include "Delay.h" //包含Delay头文件
#include "LCD1602.h" //包含LCD1602头文件
#include "MatrixKey.h" //包含矩阵键盘头文件
unsigned char KeyNum;
void main()
{
LCD_Init(); //LCD初始化
LCD_ShowString(1,1,"MatrixKey:"); //LCD显示字符串
while(1)
{
KeyNum=MatrixKey(); //获取矩阵键盘键码
if(KeyNum) //如果有按键按下
{
LCD_ShowNum(2,1,KeyNum,2); //LCD显示键码
}
}
}
代码解释:
该代码中包含的Delay.h
和LCD1602.h
分别用于延时以及LCD1602的显示,在前面已经进行详细的介绍。
MatrixKey.h
是矩阵键盘头文件,里面包含了MatrixKey接口,具体代码如下:
#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__
unsigned char MatrixKey();
#endif
MatrixKey接口的实现在MatrixKey.c
文件中,如下:
#include <REGX52.H>
#include "Delay.h"
/**
* @brief 矩阵键盘读取按键键码
* @param 无
* @retval KeyNumber 按下按键的键码值
如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键键码,没有按键按下时,返回0
整个函数实现的过程就是对16个矩阵按键扫描了一遍
*/
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;}
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_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_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_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;
}
该接口其实现的功能就是将矩阵键盘的16个按键扫描了一遍,返回按下的按键的键码;
最终实现的结果就是按下某个按键,其表示的键码会显示在LCD1602上,即本节的目标1.
三、矩阵键盘密码锁
代码路径:51单片机入门教程资料\课件及程序源码\程序源码\KeilProject\6-2 矩阵键盘密码锁
具体代码:
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"
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; //密码左移一位
Password+=KeyNum%10; //获取一位密码
Count++; //计次加一
}
LCD_ShowNum(2,1,Password,4); //更新显示
}
if(KeyNum==11) //如果S11按键按下,确认
{
if(Password==2345) //如果密码等于正确密码
{
LCD_ShowString(1,14,"OK "); //显示OK
Password=0; //密码清零
Count=0; //计次清零
LCD_ShowNum(2,1,Password,4); //更新显示
}
else //否则
{
LCD_ShowString(1,14,"ERR"); //显示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); //更新显示
}
}
}
}
最终实现的结果就是本节的目标2。