51单片机 第六节 矩阵键盘

本笔记默认学习者已拥有:
1.Keil5和stc烧写工具 等各种软件、驱动、环境;
2.有一个属于自己的 51单片机开发板及相关零件 ;
3.认识C语言的语法;
本人使用的51开发板为 郭天祥C51 TX-1C增强版开发板 ;
本笔记根据B站up主:江科大自化协的教学视频 整理得到ヾ(•ω•)




6-1 矩阵键盘

数码管显示的弊端:需要不断地扫描,而且显示的内容也非常少;
通过串口将数据传输到电脑上显示:太依赖电脑了,显得单片机系统很不独立;

矩阵键盘I/O口由 16个 减少到 8个,矩阵连接地越多,减少I/O口越明显;
视频的1080P 的 像素比例为 1920 * 1080,有2,073,600个像素点,要显示彩色还需要3色LED,
若每个单独判断,则需6,220,800个I/O口,但如果连接成矩阵形式的话,只需 (1920 +1080) * 3=9000 个I/O口即可;
减少 I/O口 效率是十分明显的;




原理分析

上图为TX-1C的原理图部分,注意接口与视频中不同

1.观察 独立按键 与 矩阵按键 的区别与相同之处;
发现 独立按键 公共端都连接在 GND 上,另一端都分别连接在 I/O口 上;
如果将 矩阵键盘 一行四个 单独拿出来看,
如果这一行的公共端连接在 GND 上,就会发现 矩阵键盘 与 独立按键 基本相似;

先理解简单的,再将复杂的转化为简单的,这样复杂的就变成简单的了;

2.这就是 按行扫描,第一个接到 GND 上,使用四个 if 进行判断

\[\begin{cases} if(P13==0) \to s1按下了 \\if(P12==0) \to s2按下了 \\if(P11==0) \to s3按下了 \\if(P10==0) \to s4按下了 \end{cases} \]

3.对于接下来每行的判断,若想判断第二行,
给第一行 1,给第二行 0,给第三、四行 1,判断四个I/O口;
4.这样 逐行扫描,就可以实现 矩阵键盘的扫描了;

但是视频中的 P15口 还连接到了 其他模块(连接到了BZ口),会不时给 0或1;

这个模块 相当于 一个驱动器,增大输出电流能力,而 BZ口连接到了蜂鸣器;
视频开发板中的蜂鸣器是一种无源蜂鸣器,如BZ口以一定频率高低变化,蜂鸣器就会响;

5.这样逐行扫描的话,蜂鸣器就会不自主地响,这是由于引脚冲突造成的;
6.为避免这种问题,即采用 逐列扫描

而引脚冲突在TX-1C中尤为严重,P3.4、P3.5口 都被 LCD1602占用,且P3.4口为使能端,故本笔记使用3*4矩阵键盘,代码采用逐列扫描
本人能力有限,无法找到有效的解决端口占用的方法,只能废掉s6,s10,s14,s18这一列按键了;




关于单片机的I/O口

1.单片机的I/O口的模式为一种 弱上拉 模式,又叫 准双向口
2.即I/O口 既可以输入(Input),又可以输出(Output);

一个I/O口给高电平 1,另一个I/O口给低电平 0,将两者连接在一起,虽然这确实相当于短路,但实际上并不会短路;

3.弱上拉,输出 1 的驱动能力是有限的,输出 0 的驱动能力是相对较强的,就是说 弱上拉,强下拉

4.如上图为单片机的内部结构简化示意图;
若输出高电平,就通过一个电阻接到VCC,若输出低电平,就直接接到GND;
读入会通过 斯密特触发器 进行读入;
若读入时外界 什么都没接(或接入高电平),那么读入的是高电平;
若外界直接接到GND(输入0),虽然输出的是 1 ,但它读入的 仍然是 0;

P1、P2、P3引脚配置 均采用 弱上拉 的工作模式,P0使用的是 开漏输出 的工作模式,
但开发板上 P0 已经接到 上拉电阻 了,所以说 开发板上 P0、P1、P2、P3 都是这种工作模式,而且不可更改;
而现在 STC公司推出的 高系列 单片机 的I/O模式 都是可以配置的,比如 推挽输出
推挽输出 才是 没有上拉电阻,高电平直接接到VCC,低电平直接接到GND,其只能输出不能输入;
还有一种 高阻输入,高阻输入既没有上拉也没有下拉,仅作输入,以减少上拉电阻对输入的影响;
还有一种 开漏输出
有关模式的详细介绍,可以参考STC89C52.pdf(提取码:ncst)的 第4章STC89C52系列单片机的I/O口结构 ;

准双向口输出类型可用作输出和输入功能而不需重新配置口线输出状态。这是因为当口线
输出为1时驱动能力很弱,允许外部装置将其拉低。当引脚输出为低时,它的驱动能力很强,
可吸收相当大的电流。

Q:驱动LED为什么低电平点亮,高电平熄灭?
A:因为其输出 1 时驱动能力很弱;

Q:按键为什么也采用 低电平视为按下,高电平视为未按,为什么不将公共端接VCC,读取高电平呢?
A:因为输出低电平,再把它拉高,就会产生很大的电流,所以一般按键检测0,接到低电平上;




MatrixKey.c

#include<reg51.h>
#include<Delayms.h>
/**
  * @brief  3*4矩阵键盘读取按键键码
  * @param  无
  * @retval KeyNumber 按下按键的键码值
	          如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键键码,没有按键按下时,返回0
*/
unsigned char MatrixKey(){
	unsigned char KeyNumber=0;
	
	P3=0xFF;
	T1=0; 
	if(RXD==0){ Delayms(20); while(RXD==0); Delayms(20); KeyNumber=1; }
	if(TXD==0){ Delayms(20); while(TXD==0); Delayms(20); KeyNumber=4; }
	if(INT0==0){ Delayms(20); while(INT0==0); Delayms(20); KeyNumber=7; }
	if(INT1==0){ Delayms(20); while(INT1==0); Delayms(20); KeyNumber=10; }
	
	P3=0xFF;
	WR=0; 
	if(RXD==0){ Delayms(20); while(RXD==0); Delayms(20); KeyNumber=2; }
	if(TXD==0){ Delayms(20); while(TXD==0); Delayms(20); KeyNumber=5; }
	if(INT0==0){ Delayms(20); while(INT0==0); Delayms(20); KeyNumber=8; }
	if(INT1==0){ Delayms(20); while(INT1==0); Delayms(20); KeyNumber=11; }
	
	
	P3=0xFF;
	RD=0; 
	if(RXD==0){ Delayms(20); while(RXD==0); Delayms(20); KeyNumber=3; }
	if(TXD==0){ Delayms(20); while(TXD==0); Delayms(20); KeyNumber=6; }
	if(INT0==0){ Delayms(20); while(INT0==0); Delayms(20); KeyNumber=9; }
	if(INT1==0){ Delayms(20); while(INT1==0); Delayms(20); KeyNumber=12; }
	
	return KeyNumber;
}



MatrixKey.h

#ifndef __MATRIXKEY_H__
#define __MATRIXKEY_H__

unsigned char MatrixKey();

#endif



矩阵键盘.c

#include<reg51.h>
#include<Delayms.h>
#include<LCD1602.h>
#include<MatrixKey.h>
unsigned char KeyNum;
void main(){
	LCD_Init();
	LCD_ShowString(1,1,"Hello World!");
	while(1){
		KeyNum=MatrixKey();
		if(KeyNum) LCD_ShowNum(2,1,KeyNum,2);
	}
}

运行结果如下




6-2 矩阵键盘密码锁.c

#include<reg51.h>
#include<Delayms.h>
#include<LCD1602.h>
#include<MatrixKey.h>
unsigned char KeyNum;
unsigned int Password=0;
void main(){
	
	LCD_Init();
	LCD_ShowString(1,1,"Password:");
	LCD_ShowNum(2,1,Password,4);
	while(1){
		KeyNum=MatrixKey();
		if(KeyNum){
			if((KeyNum<=9 || KeyNum==11) && Password<999){ //按下数字键 且 Password不到四位
					if(KeyNum<=9) Password=Password*10+KeyNum;
					else Password=Password*10+0; 
					LCD_ShowNum(2,1,Password,4);
				}
				if(KeyNum==12){ //按下确认键
					if(Password==2345) LCD_ShowString(1,14,"OK "); //正确显示OK
					else LCD_ShowString(1,14,"ERR"); //错误显示ERR
					Password=0; //密码清零
					LCD_ShowNum(2,1,Password,4);
				}
				if(KeyNum==10){ //按下退格键
					Password/=10; //清除最后一位
					LCD_ShowNum(2,1,Password,4);
				}
		}
	}
}
/*
 s7   s8  s9
 1    2   3

 s11  s12 s13
 4    5   6

 s15  s16 s17
 7    8   9

 s19  s20 s21
 退格  0   确认

*/

部分运行结果演示

运行结果请使用TX-1C开发板进行尝试(ง •_•)ง




软件相关

1.在 Keil5 编译程序时,会发现软件提醒 函数为使用的警告;
2.右键Target 1 ——>点击 Options for Target 'Target 1'——>点击 BL51 Misc

3.Disable Warning Numbers 栏 填写 警告编号 16,该类型的警告便不再提醒;


1.在 Keil5 界面的左侧,有四个快捷栏
2. Project即我们的工程树;

3.Books中有全英文的用户手册等 指导书;

4.Functions可以列出当前文件里所有的函数,双击可以跳转到函数代码位置;

5.Templates能快速编写代码,其中有一些代码模板,双击能直接写出代码;

右键——>点击Configure Templates...可以配置模板;

|的意思为,插入此模板后,光标会移到|的位置;

原文地址:https://www.cnblogs.com/Potrem/p/51_6.html