51单片机独立按键以及矩阵按键的使用以及其原理--独立按键 K1 控制 D1 指示灯亮灭以及数码管显示矩阵按键 S1-S16 按下后键值 0-F

IO 的使用–按键

本文主要涉及8051单片机按键的使用,包括独立按键以及矩阵按键的使用以及其原理,其中代码实例包括:
1.独立按键 K1 控制 D1 指示灯亮灭
2.通过数码管显示矩阵按键 S1-S16 按下后键值 0-F

文章目录

  • IO 的使用--按键
    • 一、按键消抖
    • 二、独立按键
      • 独立按键 K1 控制 D1 指示灯亮灭
    • 二、 矩阵按键
      • 通过数码管显示矩阵按键 S1-S16 按下后键值 0-F

按键是一种电子开关,使用时轻轻按开关按钮就可使开关接通,当松开手时, 开关断开。

在了解按键之前,我们需要先了解一下按键消抖

一、按键消抖

通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,电压信号
如下图所示:
在这里插入图片描述

由于机械点的弹性作用,按键开关在闭合时不会马上稳定的接通,在断开时也不会一下子断开,因而在闭合和断开的瞬间均伴随着一连串的抖动。抖动时间的长短由按键的机械特性决定的,一般为 5ms 到 10ms。

按键消抖有两种方式,一种是硬件消抖,另一种是软件消抖。为了使电路更加简单,通常采用软件消抖。

常用的软件去抖动方法:
1,先设置 IO 口为高电平(由于开发板 IO 都有上拉电阻,所以默认 IO 为高
电平)。
2,读取 IO 口电平确认是否有按键按下。
3,如有 IO 电平为低电平后,延时几个毫秒
4,再读取该 IO 电平,如果仍然为低电平,说明按键按下。
5,执行按键控制程序。

二、独立按键

独立按键电路构成是由各个按键的一个管脚连接在一起接地,按键其他引脚分别接到单片机 IO 口。

独立按键的原理图如下:
在这里插入图片描述

从上图中可以看出,4 个独立按键的控制管脚连接到 51 单片机的 P3.0-P3.3脚上。其中 K1 连接在 P3.1 上,K2 连接在 P3.0 上,K3 连接在 P3.2 上,K4 连接在 P3.3 上。4 个按键另一端全部连接在 GND,当按键按下后,对应 IO 口即为低电平

独立按键 K1 控制 D1 指示灯亮灭

#include "reg52.h"
typedef unsigned int u16; //对系统默认数据类型进行重定义
typedef unsigned char u8;
//定义独立按键控制脚
sbit KEY1=P3^1;
sbit KEY2=P3^0;
sbit KEY3=P3^2;
sbit KEY4=P3^3;
//定义 LED1 控制脚
sbit LED1=P2^0;
//使用宏定义独立按键按下的键值
#define KEY1_PRESS 1
#define KEY2_PRESS 2
#define KEY3_PRESS 3
#define KEY4_PRESS 4
#define KEY_UNPRESS 0

void delay_10us(u16 ten_us)
{
while(ten_us--);
}

u8 key_scan(u8 mode)
{
    static u8 key=1;
    if(mode)key=1;//连续扫描按键
    if(key==1&&(KEY1==0||KEY2==0||KEY3==0||KEY4==0))//任意按键按下
    {
        delay_10us(1000);//消抖
        key=0;
        if(KEY1==0)
        return KEY1_PRESS;
        else if(KEY2==0)
        return KEY2_PRESS;
        else if(KEY3==0)
        return KEY3_PRESS;
        else if(KEY4==0)
        return KEY4_PRESS;
    }
    else if(KEY1==1&&KEY2==1&&KEY3==1&&KEY4==1) //无按键按下
    {
     key=1;
    }
    return KEY_UNPRESS;
}
void main()
{
u8 key=0;
while(1)
{
    key=key_scan(0);
    if(key==KEY1_PRESS)//检测按键 K1 是否按下
    LED1=!LED1;//LED1 状态翻转
}
}

key_scan 函数带一个形参 mode,该参数用来设定是否连续扫描按键,如果mode 为 0只能操作一次按键,只有当按键松开后才能触发下次的扫描,这样做的好处是可以防止按下一次出现多次触发的情况。如果 mode 为 1,函数是支持连续扫描的,即使按键未松开,在函数内部有 if(mode==1)这条判断语句,因此 key 始终是等于 1 的,所以可以连续扫描按键,当按下某个按键,会一直返回这 个按键的键值,这样做的好处是可以很方便实现连按操作.

二、 矩阵按键

无论是独立键盘还是矩阵键盘,单片机检测其是否被按下的依据都是一样的,也就是检测与该键对应的 I/O 口是否为低电平。独立键盘有一端固定为低电平,此种方式编程比较简单。 而矩阵键盘两端都与单片机 I/O 口相连,因此在检测时需编程通过单片机 I/O 口送出低电平。检测方法有多种,最常用的是行列扫描线翻转法

行列扫描法检测时,先送一列为低电平,其余几列全为高电平(此时我们确定了列数),然后立即轮流检测一次各行是否有低电平,若检测到某一行为低电平(这时我们又确定了行数),则我们便可确认当前被按下的键是哪一行哪一列的,用同样方法轮流送各列一次低电平,再轮流检测一次各行是否变为低电平,这样即可检测完所有的按键,当有键被按下时便可判断出按下的键是哪一个键。当然我们也可以将行线置低电平,扫描列是否有低电平。从而达到整个键盘的检测。

线翻转法,就是使所有行线为低电平时,检测所有列线是否有低电平,如果有,就记录列线值;然后再翻转,使所有列线都为低电平,检测所有行线的值,由于有按键按下,行线的值也会有变化,记录行线的值。从而就可以检测到全部按键。

在这里插入图片描述

4*4 矩阵按键引出的 8 根控制线直接连接到 51 单片机的P1 口上。电路中的 P17 连接矩阵键盘的第 1 行,P13 连接矩阵键盘第 1 列

通过数码管显示矩阵按键 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};

void delay_10us(u16 ten_us)
{
    while(ten_us--);
}
//行列式扫描方式
u8 key_matrix_ranks_scan(void)
{
    u8 key_value=0;
    KEY_MATRIX_PORT=0xf7;//给第一列赋值 0,其余全为 1
    if(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,其余全为if(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,其余全为 1
    if(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,其余全为 1
    if(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;
}

//线翻转式扫描方式
u8 key_matrix_flip_scan(void)
{
static u8 key_value=0;
KEY_MATRIX_PORT=0x0f;//给所有行赋值 0,列全为 1
if(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);//等待按键松开
    }
    }
    else
    key_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 段码
}
}

上述学习资料都是来自普中科技😀

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue项目中实现浏览器标签页名字的动态修改

修改router/index.js文件 路由条目下面添加meta属性 meta:{title:DevOps运维平台 }示例 使用Vue的全局守卫函数beforeEach,在路由切换前动态修改浏览器标签页名字 router.beforeEach((to,from,next) > {document.title to.meta.titlenext() })

高项备考葵花宝典-项目进度管理输入、输出、工具和技术(上,很详细考试必过)

项目进度管理的目标是使项目按时完成。有效的进度管理是项目管理成功的关键之一,进度问题在项目生命周期内引起的冲突最多。 小型项目中,定义活动、排列活动顺序、估算活动持续时间及制定进度模型形成进度计划等过程的联系非常密切,可以视为一…

MX6ULL学习笔记 (八) platform 设备驱动实验

前言: 什么是 Linux 下的 platform 设备驱动 Linux下的字符设备驱动一般都比较简单,只是对IO进行简单的读写操作。但是I2C、SPI、LCD、USB等外设的驱动就比较复杂了,需要考虑到驱动的可重用性,以避免内核中存在大量重复代码&…

玩转大数据13: 数据伦理与合规性探讨

1. 引言 随着科技的飞速发展,数据已经成为了现代社会的宝贵资产。然而,数据的收集、处理和利用也带来了一系列的伦理和合规性问题。数据伦理和合规性不仅关乎个人隐私和权益的保护,还涉及到企业的商业利益和社会责任。因此,数据…

Go语言深度优先搜索(DFS)

Go 语言代码段实现了深度优先搜索(DFS)算法,该算法用于遍历图数据结构。以下是代码的主要要点和执行流程的总结: 深度优先搜索函数 (DFS): 接收图的邻接表 (map[int][]int)、访问记录 (map[int]bool) 和当前节点作为参数。将当前…

SpringBoot项目静态资源默认访问目录

SpringBoot项目:静态资源默认访问目录 参考博客:https://blog.csdn.net/weixin_43808717/article/details/118281904

创建Vue2项目,引入chart.js,并生成柱形图、折线图、饼图

基础创建 1. 创建一个新的 Vue 2 项目 如果你还没有创建项目,可以使用 Vue CLI 来创建一个新项目。首先确保你已经安装了 Node.js 和 npm。然后安装 Vue CLI 并创建一个新项目。 npm install -g vue/cli vue create my-vue-chart-project在创建过程中选择 Vue 2 …

End-to-End Reconstruction-Classification Learning for Face Forgery Detection

一、研究背景 现有模型主要通过提取特定的伪造模式进行深度伪造检测,导致学习到的表征与训练集中已知的伪造类型高度相关,因此模型难以泛化到未知的伪造类型上使用。 二、研究动机 1.真实样本的特征分布相对更为紧凑,因此学习真实人脸之间的…

【GEE】时间序列多源遥感数据随机森林回归预测|反演|验证|散点图|完整代码

实验介绍 分类和回归之间的主要区别在于,在分类中,我们的预测目标是离散的类别,而在回归中,预测目标是连续的预测值。 本实验的研究区域位于佛蒙特州的埃塞克斯郡,使用训练数据来模拟土壤氧化还原深度,然…

Chart 7 内存优化

文章目录 前言7.1 Adreno GPU OpenCL内存7.1.1 内存声明周期7.1.2 Loacl Memory7.1.3 Constant memory(常量内存)7.1.4 Private Memory7.1.5 Global Memory7.1.5.1 Buffer Object7.1.5.2 Image Object7.1.5.3 Image object vs. buffer object7.1.5.4 Use of both Image and buf…

基于Python+Django+mysql图书管理系统

基于PythonDjangomysql图书管理系统 一、系统介绍二、功能展示三、其它系统四、获取源码 一、系统介绍 程序开发软件:Pycharm 数据库:mysql 采用技术: Django(一个MVT框架,类似Java的SSM框架) 人生苦短,我用Python&a…

【Vue】日常错误总结(持续更新)

日常遇到的小问题汇总, 内容小篇幅少的就全放这里了, 内容多的会在Vue专栏单独分享~ 目录 【Q】 el-form-item值为 null 或 undefined显示““ 【Q】dialog内组件数据刷新总是延迟慢一拍 问题背景描述 解决方案 代码简单模拟 JS 【Q】el-input 不能输入的解决办法 方法…

LeetCode008之字符串转换整数 (相关话题:状态机)

题目描述 请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C 中的 atoi 函数)。 函数 myAtoi(string s) 的算法如下: 读入字符串并丢弃无用的前导空格检查下一个字符(假设还…

TailwindCSS 支持文本文字超长溢出截断、文字文本省略号

前言 文本文字超长截断并自动补充省略号,这是前端日常开发工作中常用的样式设置能力,文字超长截断主要分为单行超长截断和多行超长截断。本文通过介绍基本CSS样式、tailwindcss 类设置两种基础方式来实现文字超长截断。 TailwindCSS 设置 单行文字超长…

编写Yaml文件当Poc,利用Nuclei扫描器去扫描漏洞

编写Yaml文件当Poc,利用Nuclei扫描器去扫描漏洞 YAML是一种数据序列化语言,它的基本语法规则注意如下: -大小写敏感 -使用缩进表示层级关系 -缩进时不允许使用Tab键,只允许使用空格。 -缩进的空格数目不重要,只要相同层级的元…

springboot_ssm_java学位论文盲审系统

本系统主要实现用户登录验证,用户使用邮箱,密码和选择身份进行登录,用户查看个人中心,提交论文,发表留言和问题反馈。用户在线注册。学生模块功能实现:学生注册,查看信息,修改资料&a…

C++新经典模板与泛型编程:将trait类模板用作模板参数

将trait类模板用作模板参数 template<typename T> struct SumFixedTraits;template<> struct SumFixedTraits<char> {using sumT int;static sumT initValue() {return 0;} };template<> struct SumFixedTraits<int> {using sumT __int64;sta…

2023年 - 我的程序员之旅和成长故事

2023年 - 我的程序员之旅和成长故事 &#x1f525; 1.前言 大家好&#xff0c;我是Leo哥&#x1fae3;&#x1fae3;&#x1fae3;&#xff0c;今天咱们不聊技术&#xff0c;聊聊我自己&#xff0c;聊聊我从2023年年初到现在的一些经历和故事&#xff0c;我也很愿意我的故事分…

力扣:199. 二叉树的右视图(Python3)

题目&#xff1a; 给定一个二叉树的 根节点 root&#xff0c;想象自己站在它的右侧&#xff0c;按照从顶部到底部的顺序&#xff0c;返回从右侧所能看到的节点值。 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;力扣&#xff08;LeetCode&#xff09…

Error: Cannot find module ‘E:\Workspace_zwf\mall\build\webpack.dev.conf.js‘

执行&#xff1a;npm run dev E:\Workspace_zwf\zengwenfeng-master>npm run dev> mall-app-web1.0.0 dev E:\Workspace_zwf\zengwenfeng-master > webpack-dev-server --inline --progress --config build/webpack.dev.conf.jsinternal/modules/cjs/loader.js:983thr…
最新文章