矩阵键盘
矩阵键盘一般和之前学的LCD1602液晶屏一起控制,建议先看一下之前的博客学习一下液晶屏的使用。
当然矩阵键盘也可以和数码管和LED等一起操作,但是数码管需要扫描,很费CPU,LED又不能直观的看到键盘的操作。用LCD1602来学习矩阵键盘比较合适。
简介
在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排成矩阵形。
采用逐行或逐列扫描,就可以读出任意位置按键的状态。
解释一下
从原理图中我们可以看到,独立按键每个按键要使用一个I/O口,而矩阵键盘只用了8个I/O口。
假如矩阵键盘用独立按键的控制方式,四行四列需要16个I/O口。但是采用了扫描的控制方式后,我们只用了4+4=8个I/O口。
扫描的原理:
我们之前了解过数码管的扫描,叫做输出扫描。从第一位依此往下扫描到最后一位,然后快速循环,最终实现所有数码管同时显示。优点是解决了多位数码管不能在同一时间显示不同数字的情况,缺点是很费CPU。这里比较难理解,可以看看之前分析动态数码管的博客
矩阵键盘的扫描叫做输入扫描。单片机读取每一行(列)的状态,然后快速循环,最终实现所有按键同时检测的效果。
扫描也是显示器的一种显示方式,里面也有很多学问,感兴趣的朋友们可以去学习一下
原理
现在说一下矩阵键盘的使用原理。
大家想象一下,假如把矩阵键盘的第一行,全部接地(即P17赋值为0),那么是不是第一行就变成了一组独立按键呢?这个时候我们判断一下P10~P3是否位0,就能看出哪个按键按下了。(如果按键按下,说明和P17短路了,对应的管脚口肯定就是是0了)
那么扫描第一行的方式就是:P17赋值为0,P16~P14赋值为1,判断P10~P13哪个为零,对应的按键就按下了。比如这个时候我们检测到P11为零, 说明S3按键按下了。
以此类推,扫描第二行的方式就是:P16赋值为0,P17,P15,P14赋值为1,判断P10~P13哪个为零。……这种方法叫做逐行扫描。
同理,我们也可以用逐列扫描,先依次给P10~ P13低电平,依次判断P14~P17的电平,来判断哪个按键被按下了。
弱上拉(强下拉)模式
再来了解一下弱上拉模式:具有较弱的拉高电平或电位的能力,虽然弱,但是能够实现电平改变。
说人话,比如扫描第一行按键,P17赋值0,我们以前说过,单片机上电后每个I/O都是高电平,我们按下S1,P13和P17短接,我们的单片机是弱上拉模式,拉高电平能力有限,所以P13口的电平才能够被拉低。P13就变成了低电平。假如这是一个强上拉模式的单片机,那么即使P17被赋低电平,按下S1,P13的电平也不能够被拉低,因为单片机上电后的电平被强上拉了。
内部原理
画个草图,单片机内部是这样的,上电后,VCC和单片机读取电平的部分连接,这样I/O口就会输出高电平,同时单片机读取到高电平。
施密特触发器是数电里的一个知识点,是一种正反馈比较器,内部有高电阻。当外部接地后,强电流会趋向于往电阻较低的方向流,相当于节点和触发器那一部分断开了,这样单片机就读取不到电平了。
如果大家的数电模电底子比较扎实,应该很容易理解这个意思。当然没有看明白的朋友也不必担心,这些都是了解性内容,大概知道一下就行
除了弱上拉模式,单片机还有推挽输出(没有上拉电阻,高电平直接接VCC,低电平直接接GND)、高阻输入(既没有上拉,也没有下拉)、开漏输出……这些模式是嵌入式和开关电源的知识点,我们的管脚口是可以自由配置。现在不用理解太深,以后会再提。
大家可以在我们STC89C52的手册上查看一下
写代码
新建工程
同时去以前我们写过的工程里,把LCD1602的驱动和Delay的模块复制并添加进来。
编译好之后,我们会发现下面有一下关于函数定义的报错,其实影响不大,如果觉得碍眼可以关掉。
添加模块MatrixKey
生成.h的模板
我们在左侧的工具栏点击Functions就可以看到我们在各个文件内定义的函数了。
同样,点击books就可以看到一些官方给的参考资料。
点击Templates能够看到官方给的模板,点击就可以直接生成这些模板。
当然我们也可以自己配置模板,右键选择“Cofigure Templates”,来修改自己的配置。
按照如下操作,来添加一个模板吧!
#ifndef __|_H__
#define
#endif
第一行的 “|“ 意思是生成模板后光标的位置。
MatrixKey文件
根据自己学到的内容,写如下代码
#include <REGX52.H>
#include "Delay.H"
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_7==0);
Delay(20);
KeyNumber = 5;
}
if(P1_5==0)
{
Delay(20);
While(P1_7==0);
Delay(20);
KeyNumber = 9;
}
if(P1_4==0)
{
Delay(20);
While(P1_7==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;
}
以上是我们比较容易判断的代码,当然我们也可以看一看单片机给的例程,学习一下矩阵键盘的代码,不过那种代码的逻辑比较复杂,不太好理解。
头文件如下:
#ifndef __MatrixKey_H__
#define __MatrixKey_H__
unsigned char Matrixkey();
#endif
主函数的内容:
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"
unsigned char KeyNum;
void main()
{
LCD_Init();
LCD_ShowString(1,1,"HelloWorld!");
while(1)
{
KeyNum = MatrixKey();
if(KeyNum)
{
LCD_ShowNum(2,1,KeyNum,2);
}
}
}
烧录程序就能看到,按下按键,显示屏第一行显示Hello world,第二行显示按下的键码值。
试着自己写注释
创建一个模板,名字叫做:@brief,brief是内容说明,param是参数说明,retval是返回值说明。有了这个模板,我们以后模块化编程的时候就更方便写注释方便自己和别人阅览。
给我们的工程加上这段注释,那么MatrixKey.c文件前面就会有这么一段话
|