嵌入式开发学习(STC51-7-矩阵按键)

内容

按下S1-S16键,对应数码管最左边显示0-F

矩阵按键简介

独立按键与单片机连接时,每一个按键都需要单片机的一个I/O 口,若某单片机系统需较多按键,如果用独立按键便会占用过多的I/O口资源;而单片机
系统中I/O口资源往往比较宝贵,当用到多个按键时为了减少I/O口引脚,引入了矩阵按键;

以4*4矩阵键盘为例,键排成4行4列,第一行将每个按键的一端连接在一起构成行线,第一列将每个按键的另一端连接在一起构成列线,这样便一共有4行4列共8根线,我们将这8根线连接到单片机的8个I/O口上,通过程序扫描键盘就可检测16个键;

用这种方法也可实现3行3列9个键、5行5列25个键、6行6列36个键甚至更多;

无论是独立键盘还是矩阵键盘,单片机检测其是否被按下的依据都是一样的,也就是检测与该键对应的I/O口是否为低电平;

独立键盘有一端固定为低电平,此种方式编程比较简单;而矩阵键盘两端都与单片机I/O口相连,因此在检测时需编程通过单片机I/O口送出低电平;

检测方法有多种,最常用的是行列扫描和线翻转法:

  • 行列扫描法检测时,(可以看作是每次把一列当作独立按键来检测)依次送一列为低电平,其余几列全为高电平(行全为高电平),如果检测到该列有行电平变低,即该列有按键按下,就可以确定列,然后立即检测该行哪列为低电平,则可确定行,这样我们就可确认当前被按下的键是哪一行哪一列的;当然我们也可以依次将行线置低电平(其余行列为高电平),扫描列是否有低电平;
  • 线翻转法,就是使所有行线为低电平时,检测所有列线是否有低电平,如果有,就记录列线值;然后再翻转,使所有列线都为低电平,检测所有行线的值,由于有按键按下,行线的值也会有变化,记录行线的值;得到的行列值就是按下的按键;

矩阵键盘也少不了按键消抖的环节;

原理图

线路图
在这里插入图片描述
由线路图可知,P17-14控制行,P13-10控制列

思路

使用行列扫描法,每次把一列当作独立按键来检测,依次让每列为低电位,如果某列有行变为低电位,则该行和列即是按下的按键;

注意消抖;

编码

main.c

/** @Description: 矩阵按键-按下S1-S16键,对应数码管最左边显示0-F*/
#include "reg52.h"typedef unsigned int u16; // 对系统默认数据类型进行重定义
typedef unsigned char u8;#define KEY_MATRIX_PORT P1 // 使用宏定义矩阵按键控制口#define SMG_A_DP_PORT P0 // 使用宏定义数码管段码口// 共阴极数码管显示0~F的段码数据
u8 gsmg_code[17] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};/*** @description: 延时函数(循环一次大约10us)* @param {u16} ten_us* @return {*}*/
void delay_10us(u16 ten_us)
{while (ten_us--);
}/*** @description: 使用行列式扫描方法,检测矩阵按键是否按下,按下则返回对应键值* @return {u8} key的键值*/
u8 key_matrix_ranks_scan(void)
{u8 key_value = 0;KEY_MATRIX_PORT = 0xf7;		 // 给第一列赋值0,其余全为1if (KEY_MATRIX_PORT != 0xf7) // 判断第一列按键是否按下(如果有按键按下,即其中有行变为低位,则两边就不相等){delay_10us(1000);		 // 消抖switch (KEY_MATRIX_PORT) // 保存第一列按键按下后的键值{case 0x77:key_value = 1;break;case 0xb7:key_value = 5;break;case 0xd7:key_value = 9;break;case 0xe7:key_value = 13;break;}}while (KEY_MATRIX_PORT != 0xf7); // 等待按键松开KEY_MATRIX_PORT = 0xfb;		 // 给第二列赋值0,其余全为1if (KEY_MATRIX_PORT != 0xfb) // 判断第二列按键是否按下{delay_10us(1000);		 // 消抖switch (KEY_MATRIX_PORT) // 保存第二列按键按下后的键值{case 0x7b:key_value = 2;break;case 0xbb:key_value = 6;break;case 0xdb:key_value = 10;break;case 0xeb:key_value = 14;break;}}while (KEY_MATRIX_PORT != 0xfb); // 等待按键松开KEY_MATRIX_PORT = 0xfd;		 // 给第三列赋值0,其余全为1if (KEY_MATRIX_PORT != 0xfd) // 判断第三列按键是否按下{delay_10us(1000);		 // 消抖switch (KEY_MATRIX_PORT) // 保存第三列按键按下后的键值{case 0x7d:key_value = 3;break;case 0xbd:key_value = 7;break;case 0xdd:key_value = 11;break;case 0xed:key_value = 15;break;}}while (KEY_MATRIX_PORT != 0xfd); // 等待按键松开KEY_MATRIX_PORT = 0xfe;		 // 给第四列赋值0,其余全为1if (KEY_MATRIX_PORT != 0xfe) // 判断第四列按键是否按下{delay_10us(1000);		 // 消抖switch (KEY_MATRIX_PORT) // 保存第四列按键按下后的键值{case 0x7e:key_value = 4;break;case 0xbe:key_value = 8;break;case 0xde:key_value = 12;break;case 0xee:key_value = 16;break;}}while (KEY_MATRIX_PORT != 0xfe); // 等待按键松开return key_value;
}/*** @description: 使用线翻转扫描方法,检测矩阵按键是否按下,按下则返回对应键值* @return {u8} key的键值*/
u8 key_matrix_flip_scan(void)
{static u8 key_value = 0;KEY_MATRIX_PORT = 0x0f;		 // 给所有行赋值0,列全为1if (KEY_MATRIX_PORT != 0x0f) // 判断按键是否按下{delay_10us(1000); // 消抖if (KEY_MATRIX_PORT != 0x0f){// 测试列KEY_MATRIX_PORT = 0x0f;switch (KEY_MATRIX_PORT) // 保存行为0,按键按下后的列值{case 0x07:key_value = 1;break;case 0x0b:key_value = 2;break;case 0x0d:key_value = 3;break;case 0x0e:key_value = 4;break;}// 测试行KEY_MATRIX_PORT = 0xf0;switch (KEY_MATRIX_PORT) // 保存列为0,按键按下后的键值{case 0x70:key_value = key_value;break;case 0xb0:key_value = key_value + 4;break;case 0xd0:key_value = key_value + 8;break;case 0xe0:key_value = key_value + 12;break;}while (KEY_MATRIX_PORT != 0xf0); // 等待按键松开}}elsekey_value = 0;return key_value;
}void main()
{u8 key = 0;while (1){key = key_matrix_ranks_scan();if (key != 0)SMG_A_DP_PORT = gsmg_code[key - 1]; // 得到的按键值减1换算成数组下标对应0-F段码}
}

编译和结果

按F7编译,无错误,生成.hex文件,使用pz-isp将hex文件下载到单片机

结果:按下S1-S16键,对应数码管最左边显示0-F
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/24349.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【elasticsearch】关于elasticsearch的max_result_window限制问题的解决方式思考

事情起因:我们使用es作为日志搜索引擎,客户收集到的业务日志非常之大,每次查询后,返回页数较多,由于我们web界面限制每页返回150条,当客户翻到66页之后就会报错。 文章目录 前言 二、实验 1.默认生成20条数…

2.13 Android ebpf非网络相关帮助函数API汇总(十二 本章完)

1.long bpf_user_ringbuf_drain(struct bpf_map *map, void *callback_fn, void *ctx, u64 flags) 描述:从指定的用户环形缓冲区中排出样本,并为每个此类样本调用提供的回调: long (*callback_fn)(struct bpf_dynptr *dynptr, void *ctx); 如果callback_fn返回0,帮助函数…

docker安装code-service在线开发vscode工具及node版本过低问题

docker安装code-service 拉去镜像 docker pull codercom/code-server创建项目存放映射路径 mkdir /data/code-service/project运行 这里不唯一,但注意密码 docker run -itd --name code-service -u root -p 1024:8080 -v /data/code-service/project:/home/cod…

Maven介绍-下载-安装-使用-基础知识

Maven介绍-下载-安装-使用-基础知识 Maven的进阶高级用法可查看这篇文章: Maven分模块-继承-聚合-私服的高级用法 文章目录 Maven介绍-下载-安装-使用-基础知识01. Maven1.1 初识Maven1.1.1 什么是Maven1.1.2 Maven的作用 02. Maven概述2.1 Maven介绍2.2 Maven模型…

hive编译报错整理

背景 最近在修hive-1.2.0的一个bug,需要修改后重新打包部署到集群,打包的时候报下面的错误,原因很简单,从远程仓库里面已经拉不到这个包了。 org.pentaho:pentaho-aggdesigner-algorithm:jar:5.1.5-jhyde was not found in http…

Unity进阶--通过PhotonServer实现联网登录注册功能(服务器端)--PhotonServer(二)

文章目录 Unity进阶--通过PhotonServer实现联网登录注册功能(服务器端)--PhotonServer(二)服务器端大体结构图BLL层(控制层)DAL层(数据控制层)模型层DLC 服务器配置类 发送消息类 以及消息类 Unity进阶–通过PhotonServer实现联网…

factoryBean.setTypeAliasesPackage()详解

示例代码 Bean public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {SqlSessionFactoryBean factoryBean new SqlSessionFactoryBean();factoryBean.setDataSource(dataSource);factoryBean.setTypeAliasesPackage("com.itheima.domain");retu…

HCIP——STP

STP 一、STP概述二、二层环路带来的问题1、广播风暴问题2、MAC地址漂移问题3、多帧复制 三、802.1D生成树STP的BPDU1、配置BPDU2、RPC3、COST4、配置BPDU的工作过程5、TCN BPDU6、TCN BPDU的工作原理 四、STP的角色五、STP角色选举六、STP的接口状态七、接口状态的迁移八、STP的…

minio-分布式文件存储系统

minio-分布式文件存储系统 minio的简介 MinIO基于Apache License v2.0开源协议的对象存储服务,可以做为云存储的解决方案用来保存海量的图片,视频,文档。由于采用Golang实现,服务端可以工作在Windows,Linux, OS X和FreeBSD上。配置…

没有jodatime,rust里怎么将字符串转为日期呢?

关注我,学习Rust不迷路!! 在 Rust 中,有多种方法可以在时间和字符串之间进行转换。以下是五种常见的方式: 1. 使用 chrono 库进行转换: use chrono::{NaiveDateTime, DateTime, Utc, TimeZone};fn main(…

Mysql函数

MySQL -函数 常用字符串函数SELECT... 函数 功能 CONCAT(S1,S2....Sn) 字符串拼接 LOWER(str) 将字符串str全部改成小写 UPPER(str) 将字符串str全部改成大写 LPAD(str,n,pad) 左填充,用字符串pa…

实验5-1 使用函数计算两个复数之积 (10 分)

本题要求现一个函数计算两个复数之积。 函数接口定义: double result_real, result_imag; void complex_prod( double x1, double y1, double x2, double y2 ); 其中用户传入的参数为两个复数x1y1i和x2y2i;函数complex_prod应将计算结果的实部存放在全局…

线程间的同步、如何解决线程冲突与死锁

一、线程同步概念: 线程同步是指在多线程编程中,为了保证多个线程之间的数据访问和操作的有序性以及正确性,需要采取一些机制来协调它们的执行。在多线程环境下,由于线程之间是并发执行的,可能会出现竞争条件&#xf…

【WebRTC---源码篇】(三:一)音频轨

音频轨的创建时序在Conductor::AddTracks()中 rtc::scoped_refptr<webrtc::AudioTrackInterface> audio_track(peer_connection_factory_->CreateAudioTrack(kAudioLabel, peer_connection_factory_->CreateAudioSource(cricket::AudioOptions()))); 通过代码我们…

el-upload批量手动上传,并用form表单校验上传文件

手动上传设置:auto-upload"false" <el-formref"formData"class"formWidth":model"formData"label-width"120px":rules"rules"><el-form-itemlabel"数据"class"uploadClass"required…

RadioButton基本使用

作用&#xff1a;单选框&#xff0c;一般用于设置或者选择某项任务。 常用属性&#xff1a; 常用事件&#xff1a; 选中事件 后台代码&#xff1a; private void radioButton1_CheckedChanged(object sender, EventArgs e){if (radioButton1.Checked){MessageBox.Show(radioB…

AcWing 4310:树的DFS ← vector、auto、邻接表

【题目来源】https://www.acwing.com/problem/content/description/4313/【题目描述】 给定一棵 n 个节点的树。 节点的编号为 1∼n&#xff0c;其中 1 号节点为根节点&#xff0c;每个节点的编号都大于其父节点的编号。 现在&#xff0c;你需要回答 q 个询问。 每个询问给定两…

电脑ADB连接手机的方式通过网络无法adb连接手机的问题(已解决)

首先电脑要下载adb工具&#xff0c;将压缩包解压到C盘&#xff1a;https://download.csdn.net/download/qq_43445867/87975072 1、使用USB线连接 打开手机USB调试&#xff1b;PC端安装手机USB驱动。 1.打开DOS命令窗口&#xff0c;进入adb文件夹,输入adb.exe devices回车列出设…

用shell实现MySQL分库分表操作

#!/bin/bash mysql_cmd-uroot -p123 #定义变量保存密码 exclude_dbinformation_schema|performance_schema|sys #数据库 bak_path/backup/db #备份路径 mysql ${mysql_cmd} -e show databases -N | egrep -v "${exclude_db}" > dbname while read line do …

企业内网终端安全无客户端准入控制技术实践

终端无代理/无客户端准入控制技术因其良好的用户体验而倍受创新企业的青睐。无代理/无客户端准入控制技术&#xff0c;顾名思义&#xff0c;是一种在网络中对终端实施访问控制的方法&#xff0c;无需依赖特定的客户端软件。 不同于银行、医院等传统行业的终端准入控制需求&…