51单片机入门_江协科技_15~16_OB记录的笔记

15. 矩阵键盘

  • 15.1. 矩阵键盘介绍

  • •在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式

    •采用逐行或逐列的“扫描”,就可以读出任何位置按键的状态

在这里插入图片描述

在这里插入图片描述

  • 15.2. 扫描的概念:
    •数码管扫描(输出扫描)

    原理:显示第1位→显示第2位→显示第3位→……,然后快速循环这个过程,最终实现所有数码管同时显示的效果

•矩阵键盘扫描(输入扫描)

原理:读取第1行(列)→读取第2行(列) →读取第3行(列) → ……,然后快速循环这个过程,最终实现所有按键同时检测的效果

•以上两种扫描方式的共性:节省I/O口

  • 15.3. 开发板采用逐列扫描代替逐行扫描的原因是P15口连接蜂鸣器会导致如果用逐行扫描,蜂鸣器会有规律的响,所以用逐列扫描;

  • 15.4. 单片机IO口特性弱上拉,强下拉

  • 15.5. 矩阵键盘程序模块实操;

    • 建立矩阵键盘程序文件夹 6-1 矩阵键盘

    • 将之前项目钟的LCD1602.c与LCD1602.h;以及delay_xms.c 与delay_xms.h ;拷贝到项目目录中,并在Keil项目目录中导入;

    • Keil中转到template类别:
      在这里插入图片描述

    • 右键点击空白区域选择configure templates
      在这里插入图片描述

    • 点击左边的图标新建模板,右边的x是对选中的模板进行删除
      在这里插入图片描述

    • 新建一个#include名称的模板,在下面的text中输入如下代码,以便于后续新建51程序的编程;
      在这里插入图片描述

    • 在main.c程序中测试模板如下:
      在这里插入图片描述

  • 15.6. 程序中之前定义的函数无法转到相应的函数的定义,根据作者说明和尝试,需要关闭Keil程序,然后重新打开生效:
    在这里插入图片描述

    • 关闭Keil并重新打开后如图可以转到 LCD_Init()函数定义:
      在这里插入图片描述
  • 15.7. 编程的理念是边做边测试,以及早发现问题并解决相应的问题。

  • 15.8. MATRIXKEY.c 有返回值的矩阵键盘模块程序样例;

#include <REGX52.h>
#include "delay_xms.h"
/**
  * @brief 矩阵键盘读取按键码程序
  * @param  无
  * @retval KeyNumber按下按键的键码值
  如果按键按下不放,程序会停留在此函数,松手瞬间,返回按键键码值,
  没有按键按下时,返回0;
  */


unsigned char MatrixKey()
{
	unsigned char KeyNumber=0;//初始化KeyNumber为0;
	P1=0xff;//P1先全部置于1;
	P1_3=0; //再将P13口置于0;以下为S1,S5,S9,S13的检测
	if(P1_7==0){delay_xms(20);while(P1_7==0);delay_xms(20);KeyNumber=1;}
	if(P1_6==0){delay_xms(20);while(P1_6==0);delay_xms(20);KeyNumber=5;}
	if(P1_5==0){delay_xms(20);while(P1_5==0);delay_xms(20);KeyNumber=9;}
	if(P1_4==0){delay_xms(20);while(P1_4==0);delay_xms(20);KeyNumber=13;}

	P1=0xff;//P1先全部置于1;
	P1_2=0; //再将P12口置于0;以下为S2,S6,S10,S14的检测
	if(P1_7==0){delay_xms(20);while(P1_7==0);delay_xms(20);KeyNumber=2;}
	if(P1_6==0){delay_xms(20);while(P1_6==0);delay_xms(20);KeyNumber=6;}
	if(P1_5==0){delay_xms(20);while(P1_5==0);delay_xms(20);KeyNumber=10;}
	if(P1_4==0){delay_xms(20);while(P1_4==0);delay_xms(20);KeyNumber=14;}

	P1=0xff;//P1先全部置于1;
	P1_1=0; //再将P11口置于0;以下为S3,S7,S11,S15的检测
	if(P1_7==0){delay_xms(20);while(P1_7==0);delay_xms(20);KeyNumber=3;}
	if(P1_6==0){delay_xms(20);while(P1_6==0);delay_xms(20);KeyNumber=7;}
	if(P1_5==0){delay_xms(20);while(P1_5==0);delay_xms(20);KeyNumber=11;}
	if(P1_4==0){delay_xms(20);while(P1_4==0);delay_xms(20);KeyNumber=15;}
	
	P1=0xff;//P1先全部置于1;
	P1_0=0; //再将P11口置于0;以下为S4,S8,S12,S16的检测
	if(P1_7==0){delay_xms(20);while(P1_7==0);delay_xms(20);KeyNumber=4;}
	if(P1_6==0){delay_xms(20);while(P1_6==0);delay_xms(20);KeyNumber=8;}
	if(P1_5==0){delay_xms(20);while(P1_5==0);delay_xms(20);KeyNumber=12;}
	if(P1_4==0){delay_xms(20);while(P1_4==0);delay_xms(20);KeyNumber=16;}
	
	return KeyNumber;
}
  • 15.9. 矩阵键盘MatrixKey.h文件代码:
  #ifndef _MATRIXKEY_H_ 
#define _MATRIXKEY_H_  

unsigned char MatrixKey();

#endif
  • 15.10. 矩阵键盘按任意数字LCD1602显示相应的数字的测试程序
#include <REGX52.h>
#include "LCD1602.h"
#include "delay_xms.h"
#include "MatrixKey.h"

unsigned char KeyNum;	//定义KeyNum接一下MatrixKey返回值

void main()
{
	LCD_Init();			//LCD1602初始化	
	LCD_ShowString(1,1,"Input Password:");

	while(1)
	{
		KeyNum=MatrixKey();//KeyNum接返回的MatrixKey返回值
		if(KeyNum)			//如果KeyNum不为0,即为真1,如果不加此if判断
							//则按键按下的时候瞬间跳一个S*的值然后归0000
							//进入到下一个循环中!!
			{
			LCD_ShowNum(2,1,KeyNum,4);
		
			}
	}
	
}
  • Proteus测试结果如下:
    在这里插入图片描述

  • 15.11. 模块化编程规范注释-模板:

/**
  * @brief |
  * @param 
  * @retval 
  */

16. 矩阵键盘密码锁

  • 16.1. 直接拷贝上一节的工程目录,更改目录名称成为新的工程“ 6-2 矩阵键盘密码锁”
#include <REGX52.h>
#include "LCD1602.h"
#include "delay_xms.h"
#include "MatrixKey.h"

unsigned char KeyNum,countnum;	//定义KeyNum接一下MatrixKey返回值
unsigned int psw;
void main()
{
	LCD_Init();			//LCD1602初始化	
	LCD_ShowString(1,1,"Password:");

	while(1)
	{
		KeyNum=MatrixKey();//KeyNum接返回的MatrixKey返回值
		if(KeyNum)			//如果KeyNum不为0,即为真1,如果不加此if判断
							//则按键按下的时候瞬间跳一个S*的值然后归0000
							//进入到下一个循环中!!
			{
				if(KeyNum<=10) //如果S1~S10按键按下,输入密码
				{
					if(countnum<4)
					{
						psw*=10; //密码左移一位
						psw+=KeyNum%10; //获取一位密码,让S10按下的时候为0;
						countnum++;	
					}
						LCD_ShowNum(2,1,psw,4);
				}
				if(KeyNum==11)  //S11定义为确认键
					{
						if(psw==2345) //如果密码等于正确密码2345
						{
							LCD_ShowString(1,14,"OK "); //显示OK
							psw=0;		//密码清零
							countnum=0; //计次清零
							LCD_ShowNum(2,1,psw,4); //清零后继续显示
						}
						else			//如果不等于正确密码
						{
							LCD_ShowString(1,14,"ERR"); //显示ERR错误
							psw=0;		//密码清零
							countnum=0; //计次清零
							LCD_ShowNum(2,1,psw,4); //清零后继续显示
						}
					}
				if(KeyNum==12) //S12 定义为取消键,直接密码和计次清零,重新输入
				{
					psw=0;		//密码清零
					countnum=0; //计次清零
					LCD_ShowNum(2,1,psw,4); //清零后继续显示
				}
			}
	}
	
}
  • 16.2. Proteus测试没问题;
    在这里插入图片描述

  • 16.3. 小结:

  • 程序设计要有结构化的思维;

  • 主要难点在于逻辑表达;

  • 边设计边测试比较好;

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-04 22:58:02       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-04 22:58:02       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-04 22:58:02       87 阅读
  4. Python语言-面向对象

    2024-04-04 22:58:02       96 阅读

热门阅读

  1. 每天定时杀spark进程

    2024-04-04 22:58:02       33 阅读
  2. 算法——验证二叉树的前序序列化

    2024-04-04 22:58:02       39 阅读
  3. API 接口类型有哪些:入门指南

    2024-04-04 22:58:02       33 阅读
  4. Vue3 自定义指令Custom Directives

    2024-04-04 22:58:02       42 阅读
  5. php身份证实名认证接口、社交平台实名制

    2024-04-04 22:58:02       39 阅读
  6. C++内存池

    2024-04-04 22:58:02       38 阅读
  7. Vue3 & Vite 整合组件脚手架笔记

    2024-04-04 22:58:02       39 阅读
  8. 速盾:怎么通过cdn防御ddos

    2024-04-04 22:58:02       33 阅读