51 单片机[6]:矩阵键盘及密码锁

ops/2024/10/17 7:53:53/

一、认识矩阵键盘

在键盘中按键数量较多时,为了减少I/O口的占用,通常将按键排列成矩阵形式
采用逐行或逐列的“扫描”,就可以读出任何位置按键的状态

img

扫描的概念

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

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

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

单片机的I/O口是弱上拉、强下拉

img

当引脚输出为1时,驱动能力很弱,允许外部装置将其拉低。当引脚输出为低时,它的驱动能力很强,可吸收相当大的电流

二、简单的矩阵键盘实现

目标 :按下按键后,LCD屏显示键码。

把上节的Delay.c、Delay.h和LCD1602.c、LCD1602.h复制到项目中。

新建一个MatrixKey.c文件和MatrixKey.h

  1. 点击templates,在空白处右键,点击configure templates

img

  1. 点击新建图标,输入#ifndef,在Text中输入模板内容,点击OK

img

注意,要在下划线中间打一个竖杠,这样在点击模板后,光标会出现在该位置。

  1. 在MatrixKey.h文件中编辑,双击#ifndef,可以看到

img

在光标处输入MATRIXKEY

完整的MatrixKey.h文件内容为:

#ifndef __MATRIXKEY__H__
#define __MATRIXKEY__H__unsigned char MatrixKey();#endif
  1. 矩阵键盘的输入扫描要先确定列,再确定行。完整的MatrixKey.c文件为:
#include <REGX52.H>
#include "Delay.h"
/*** @brief   矩阵键盘读取按键键码* @param   无* @retval  KeyNumber 按下按键的键码值如果按下按键不松手,程序会停留在此函数,松手的一瞬间,返回按键键码;没有按键按下时,返回0*/
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;
}
  1. main.c文件:
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"unsigned char KeyNum;void main()
{LCD_Init();//上电初始化LCD_ShowString(1, 1, "MatrixKey");while(1){KeyNum=MatrixKey();if(KeyNum){LCD_ShowNum(2, 1, KeyNum, 2);}}
}

三、矩阵键盘密码锁

目标:S1 ~ S9为数字1 ~ 9,S10为0,S11为确认,S12为取消。

把刚刚的简单项目复制一份,在旧项目的基础上进行过更改。

  1. 先实现一位数字输出。main.c文件如下:
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"unsigned char KeyNum;
unsigned int Passward;void main()
{LCD_Init();//上电初始化LCD_ShowString(1, 1, "Passward:");while(1){KeyNum=MatrixKey();if(KeyNum){if(KeyNum<=10)  //是否按下S1~S10{Passward = KeyNum%10;  //获取一位密码}LCD_ShowNum(2, 1, Passward, 2);}}
}

按下S1,LCD显示01,按下S2,LCD显示02……按下S10,LCD显示00.

  1. 实现输入一串数字
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"unsigned char KeyNum;
unsigned int Passward;void main()
{LCD_Init();//上电初始化LCD_ShowString(1, 1, "Passward:");while(1){KeyNum=MatrixKey();if(KeyNum){if(KeyNum<=10)  //是否按下S1~S10{Passward *= 10;         //密码左移一位Passward += KeyNum%10;  //获取一位密码}LCD_ShowNum(2, 1, Passward, 4);}}
}

这个程序好像可以实现密码输入。按下S1,显示0001,按下S3,显示0013。但是当数字很大超出数据范围时,密码就出现错误了,显示的数字就不按按下的按键显示了。

所以就需要计次。定义一个变量Count

#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"unsigned char KeyNum;
unsigned int Passward, Count;void main()
{LCD_Init();//上电初始化LCD_ShowString(1, 1, "Passward:");while(1){KeyNum=MatrixKey();if(KeyNum){if(KeyNum<=10)  //是否按下S1~S10{if(Count<4){Passward *= 10;         //密码左移一位Passward += KeyNum%10;  //获取一位密码}Count++;}LCD_ShowNum(2, 1, Passward, 4);}}
}
  1. 验证密码,若正确则OK,否则ERR
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"unsigned char KeyNum;
unsigned int Passward, Count;void main()
{LCD_Init();//上电初始化LCD_ShowString(1, 1, "Passward:");while(1){KeyNum=MatrixKey();if(KeyNum){if(KeyNum<=10)  //是否按下S1~S10{if(Count<4)  //次数判断{Passward *= 10;         //密码左移一位Passward += KeyNum%10;  //获取一位密码Count++;  //计次加一}LCD_ShowNum(2, 1, Passward, 4);}if(KeyNum == 11)  //是否按下S11确认{if(Passward == 4399){LCD_ShowString(1, 14, "OK");}else{LCD_ShowString(1, 14, "ERR");}}}}
}

再加上清零和更新显示

			if(KeyNum == 11)  //是否按下S11确认{if(Passward == 4399){LCD_ShowString(1, 14, "OK ");Passward = 0;  //密码清零Count = 0;     //计次清零LCD_ShowNum(2, 1, Passward, 4);  //更新显示}else{LCD_ShowString(1, 14, "ERR");Passward = 0;  //密码清零Count = 0;     //计次清零LCD_ShowNum(2, 1, Passward, 4);  //更新显示}}
  1. 按下取消,清零
#include <REGX52.H>
#include "Delay.h"
#include "LCD1602.h"
#include "MatrixKey.h"unsigned char KeyNum;
unsigned int Passward, Count;void main()
{LCD_Init();//上电初始化LCD_ShowString(1, 1, "Passward:");while(1){KeyNum=MatrixKey();if(KeyNum){if(KeyNum<=10)  //是否按下S1~S10{if(Count<4)  //次数判断{Passward *= 10;         //密码左移一位Passward += KeyNum%10;  //获取一位密码Count++;  //计次加一}LCD_ShowNum(2, 1, Passward, 4);}if(KeyNum == 11)  //是否按下S11确认{if(Passward == 4399){LCD_ShowString(1, 14, "OK ");Passward = 0;  //密码清零Count = 0;     //计次清零LCD_ShowNum(2, 1, Passward, 4);  //更新显示}else{LCD_ShowString(1, 14, "ERR");Passward = 0;  //密码清零Count = 0;     //计次清零LCD_ShowNum(2, 1, Passward, 4);  //更新显示}}if(KeyNum == 12)  //是否按下S12取消{Passward = 0;  //密码清零Count = 0;     //计次清零LCD_ShowNum(2, 1, Passward, 4);  //更新显示}}}
}

http://www.ppmy.cn/ops/48052.html

相关文章

ON DUPLICATE KEY UPDATE 子句

ON DUPLICATE KEY UPDATE 是 MySQL 中的一个 SQL 语句中的子句&#xff0c;主要用于在执行 INSERT 操作时处理可能出现的重复键值冲突。当尝试插入的记录导致唯一索引或主键约束冲突时&#xff08;即试图插入的记录的键值已经存在于表中&#xff09;&#xff0c;此子句会触发一…

QuanTA: 一种新的高秩高效微调范式

QuanTA方法的核心是利用张量操作来模拟量子电路中的门操作。这些张量被设计为仅在特定的轴上应用&#xff0c;类似于量子电路中的单量子比特或双量子比特门。通过这种方式&#xff0c;QuanTA能够以高秩参数化来适应LLMs的权重矩阵。 网址&#xff1a;QuanTA: 一种新的高秩高效微…

系统架构设计师【论文-2016年 试题4】: 论微服务架构及其应用(包括写作要点和经典范文)

论微服务架构及其应用&#xff08;2016年 试题4&#xff09; 近年来&#xff0c;随着互联网行业的迅猛发展&#xff0c;公司或组织业务的不断扩张&#xff0c;需求的快速变化以及用户量的不断增加&#xff0c;传统的单块(Monolithic)软件架构面临着越来越多的挑战&#xff0c;…

Jetpack Compose Navigation 遇上类型安全

Jetpack Compose Navigation 遇上类型安全 引言 随着 Navigation 2.8.0-alpha08 版本的发布&#xff0c;Navigation 组件引入了基于 Kotlin Serialization 的完整类型安全系统&#xff0c;用于在使用 Kotlin DSL 时定义导航图。这一新特性旨在与 Navigation Compose 等集成最…

问题 B: 2.左右(lr.cpp/pas)

目录 题目描述 输入 输出 样例输入 复制 样例输出 复制 提示 题目描述 小明近来开发了一个数字游戏。它随机写了一组数字a1、a2……ai&#xff0c;然后将一个数字m交给一位同学&#xff0c;让他们将数字m插入到a1、a2……ai之间&#xff08;不能在a1前或在an之后&#xff09;。…

操作系统复习-Linux的文件系统

文件系统概述 FAT FAT(File Allocation Table)FAT16、FAT32等&#xff0c;微软Dos/Windows使用的文件系统使用一张表保存盘块的信息 NTFS NTFS (New Technology File System)WindowsNT环境的文件系统NTFS对FAT进行了改进&#xff0c;取代了日的文件系统 EXT EXT(Extended…

计划任务 之 一次性的计划任务

计划任务 作用:定时自动完成特定的工作 计划任务的分类&#xff1a; &#xff08;1&#xff09;一次性的计划任务 例如下周三对系统的重要文件备份一次 &#xff08;2&#xff09;周期性重复计划任务 例如每天晚上12&#xff1a;00备份一次 一次性的任务计划&#xff1a…

30岁迷茫?AI赛道,人生新起点

前言 30岁&#xff0c;对于许多人来说&#xff0c;是一个人生的分水岭。在这个年纪&#xff0c;有些人可能已经在某个领域取得了不小的成就&#xff0c;而有些人则可能开始对未来的职业方向感到迷茫。如果你正处于这个阶段&#xff0c;那么你可能会问自己&#xff1a;30岁转行…