矩阵键盘
矩阵键盘一般和之前学的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的手册上查看一下
写代码
新建工程
添加模块MatrixKey
生成.h的模板
#ifndef __|_H__ #define #endif
MatrixKey文件
//MatrixKey.c #include <REGX52.H>//我们用到了管脚口,所以需要导入这个头文件,它里面 //定义了各个管教口的地址 #include "Delay.H"//我们用到了延时函数,所以需要导入这个头文件 unsigned char Matrixkey() { //我们用逐列扫描 unsigned char KeyNumber = 0; //第一列 P1 = 0xFF;//给P1的所有管脚口置1 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_7==0);//检测松手 Delay(20);//消抖 KeyNumber = 5;//赋值S1 } if(P1_5==0) { Delay(20);//消抖 While(P1_7==0);//检测松手 Delay(20);//消抖 KeyNumber = 9;//赋值S1 } if(P1_4==0) { Delay(20);//消抖 While(P1_7==0);//检测松手 Delay(20);//消抖 KeyNumber = 13;//赋值S1 } //第二列 P1 = 0xFF;//给P1的所有管脚口置1 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 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的所有管脚口置1 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; }
//MatrixKey.h #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是返回值说明。有了这个模板,我们以后模块化编程的时候就更方便写注释方便自己和别人阅览。
/** * @brief | * @param * @retval */
转自:https://blog.csdn.net/Destiny_Di/article/details/126924265