基于C51实现按键控制

2024-03-16 03:40
文章标签 实现 控制 按键 c51

本文主要是介绍基于C51实现按键控制,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

🐋 前言:本实验基于STC89C52RC单片机,根据电路原理图编程通过独立按键控制led灯、通过矩阵按键控制开发板数码管模块。由于51系列单片机结构大同小异,读者可根据此博客举一反三,实现所需完成的功能。


🐬 目录:

  • 一、按键介绍与按键消抖
  • 二、按键原理图分析
  • 三、独立按键控制led灯
  • 四、矩阵按键控制开发板数码管模块

🐇 实验所选单片机及结构展示(以普中C51为例,其他大同小异),本实验所操作的独立按键位于图中序号⑩位置,矩阵按键位于图中序号⑥位置

在这里插入图片描述

一、按键介绍与按键消抖

🐪 按键是一种电子开关,使用时轻轻按开关按钮就可使开关接通,当松开手时,开关断开。实物图如下所示:

在这里插入图片描述

通常的按键所用开关为机械弹性开关,当机械触点断开、闭合时,电压信号如下图所示:
在这里插入图片描述
由于机械点的弹性作用,按键开关在闭合时不会马上稳定的接通,在断开时也不会一下子断开,因而在闭合和断开的瞬间均伴随着一连串的抖动。按键抖动会引起按键被误读多次。为了确保CPU对按键的一次闭合仅做一次处理,必须进行消抖
🐪 按键消抖有两种方式,一种是 硬件消抖,另一种是软件消抖;硬件消抖是通过增加额外的电路来实现,一般有两种方式:RS触发器与电容滤波。实际上,在没有MCU的情况下,对按键进行消抖通常是通过硬件消抖电路来实现。而在嵌入式开发中,大多数情况下都是通过程序来实现按键消抖。一般来说一个简单的按键消抖就是先读取按键的状态。如果得到按键按下以后,延时10ms,再次读取按键的状态,如果得到按键按下之后,延时10ms,再次读取按键的状态,如果按键还是按下状态,说明按键已经按下,其中延时10ms就是软件消抖处理。


二、原理与电路图分析

2.1 独立按键

🐏 本实验对于独立按键操作的具体效果为:按下K1键,LED模块中D1指示灯点亮,再按一下,指示灯熄灭。对于按键操作的重点在于如何识别按键是否按下。实验所用开发板按键模块以及单片机引脚电路如下图所示:
在这里插入图片描述
🐏 从独立按键的电路图可以看出,4个独立按键的控制管脚连接到51单片机的P3.0-P3.3脚上。其中K1连接在P3.1上,K2连接到P3.0上,K3连接在P3.2上,K4连接在P3.3上。4个按键另一端连接在GND。下面以单片机P3.1引脚为例,结合上图P3.X端口内部电路图分析当按键K1按下,从P3,1读取到的电平如何变化。
在这里插入图片描述
当K1按键按下时,右侧为通路,而读电路被短路,读到为低电平,当K1按键没有按下,右侧电路被断路,读引脚电路读到引脚为高电平。即当K1按下时,读到P3.1引脚为低电平,否则为高电平

2.2 矩阵按键

🐏 独无论是独立按键还是矩阵按键,单片机检测其是否按下的依据都是一样:检测与该键对应的I/O口是否为低电平,此外矩阵按键的重点为检测是矩阵中哪个按键按下,检测方法有多种,最常用的是行列扫描线翻转法。本实验以44矩阵按键为实验对象,电路图如下所示。从下图中可以看出。44矩阵按键引出的8根控制线直接连接到51单片机的P1口上。电路中的P17连接矩阵键盘中的1行,P13连接矩阵键盘第1列

在这里插入图片描述

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

🐏 线翻转法:将所有行线输出低电平,检测列线对应引脚是否为低电平,读取引脚电平为低电平,原理同上独立按键,表示为该列有按键按下,记录下列线值;然后翻转,使所有列线都为低电平,检测所有行线的值,记录变化的行线的值。最后根据记录的行线和列线确定是矩阵中按下按键的位置。

三、实现独立按键控制led灯

🌿 根据基于C51实现流水灯以及电路分析,实现代码如下,其中key_scan()函数检测按下的独立按键为哪一个,如果为K1,则将led模块D1状态翻转。

/**************************************************************************************
实验名称:独立按键实验
实验现象:下载程序后,按下“独立按键”模块中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	/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{while(ten_us--);	
}/*******************************************************************************
* 函 数 名       : key_scan
* 函数功能		 : 检测独立按键是否按下,按下则返回对应键值
* 输    入       : mode=0:单次扫描按键mode=1:连续扫描按键
* 输    出    	 : KEY1_PRESS:K1按下KEY2_PRESS:K2按下KEY3_PRESS:K3按下KEY4_PRESS:K4按下KEY_UNPRESS:未有按键按下
*******************************************************************************/
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;		
}
/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
*******************************************************************************/
void main()
{	u8 key=0;while(1){key=key_scan(0);if(key==KEY1_PRESS)//检测按键K1是否按下LED1=!LED1;//LED1状态翻转	}		
}
代码分析

static u8 key=1; //被static修饰后的局部变量被放在静态存储区,能进行默认初始化,而且只能初始化一次,下次访问的时候能保留上一次的值

key_scan函数带一个形参mode,该参数用来设定是否连续扫描按键。main函数中定义了一个while循环,程序不断执行循环内代码,当key_scan函数传入实参0,经过第一次key_scan函数运行后,LED1翻转一次 ,static修饰的局部变量key变为0,只有当按键松开时key才会重新变为1,即按下按键后只会检测一次,这样做的好处是可以防止按一次出现多次触发的情况,delay_10us()用于按键消抖;当key_scan函数传入实参1,key_scan中局部变量key一直为1,while循环一次即检测一次,这样做的好处是可以很方便实现连按操作。


四、矩阵按键控制数码管

🌿 本实验所要实现的功能时:通过开发板上的矩阵键盘控制静态数码管显示对应的键值0-F,结合基于C51实现数码管的显示与上述电路原理图的分析,实现代码如下所示:

/**************************************************************************************
实验名称:矩阵按键实验	
实验现象:下载程序后,按下“矩阵按键”模块中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};	/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
*******************************************************************************/
void delay_10us(u16 ten_us)
{while(ten_us--);	
}/*******************************************************************************
* 函 数 名       : key_matrix_ranks_scan
* 函数功能		 : 使用行列式扫描方法,检测矩阵按键是否按下,按下则返回对应键值
* 输    入       : 无
* 输    出    	 : key_value:1-16,对应S1-S16键,0:按键未按下
*******************************************************************************/
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;		
}/*******************************************************************************
* 函 数 名       : key_matrix_flip_scan
* 函数功能		 : 使用线翻转扫描方法,检测矩阵按键是否按下,按下则返回对应键值
* 输    入       : 无
* 输    出    	 : key_value:1-16,对应S1-S16键,0:按键未按下
*******************************************************************************/
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;		
}/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
*******************************************************************************/
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段码		}		
}
实验效果

实验现象如下:当按下S1-S16键,最左边数码管对应显示0-F

在这里插入图片描述


感谢观看,如对内容有疑惑或补充,欢迎留言讨论,共同进步!!!

在这里插入图片描述

这篇关于基于C51实现按键控制的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/814170

相关文章

C++对象布局及多态实现探索之内存布局(整理的很多链接)

本文通过观察对象的内存布局,跟踪函数调用的汇编代码。分析了C++对象内存的布局情况,虚函数的执行方式,以及虚继承,等等 文章链接:http://dev.yesky.com/254/2191254.shtml      论C/C++函数间动态内存的传递 (2005-07-30)   当你涉及到C/C++的核心编程的时候,你会无止境地与内存管理打交道。 文章链接:http://dev.yesky

通过SSH隧道实现通过远程服务器上外网

搭建隧道 autossh -M 0 -f -D 1080 -C -N user1@remotehost##验证隧道是否生效,查看1080端口是否启动netstat -tuln | grep 1080## 测试ssh 隧道是否生效curl -x socks5h://127.0.0.1:1080 -I http://www.github.com 将autossh 设置为服务,隧道开机启动

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测

时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测 目录 时序预测 | MATLAB实现LSTM时间序列未来多步预测-递归预测基本介绍程序设计参考资料 基本介绍 MATLAB实现LSTM时间序列未来多步预测-递归预测。LSTM是一种含有LSTM区块(blocks)或其他的一种类神经网络,文献或其他资料中LSTM区块可能被描述成智能网络单元,因为

vue项目集成CanvasEditor实现Word在线编辑器

CanvasEditor实现Word在线编辑器 官网文档:https://hufe.club/canvas-editor-docs/guide/schema.html 源码地址:https://github.com/Hufe921/canvas-editor 前提声明: 由于CanvasEditor目前不支持vue、react 等框架开箱即用版,所以需要我们去Git下载源码,拿到其中两个主

android一键分享功能部分实现

为什么叫做部分实现呢,其实是我只实现一部分的分享。如新浪微博,那还有没去实现的是微信分享。还有一部分奇怪的问题:我QQ分享跟QQ空间的分享功能,我都没配置key那些都是原本集成就有的key也可以实现分享,谁清楚的麻烦详解下。 实现分享功能我们可以去www.mob.com这个网站集成。免费的,而且还有短信验证功能。等这分享研究完后就研究下短信验证功能。 开始实现步骤(新浪分享,以下是本人自己实现

基于Springboot + vue 的抗疫物质管理系统的设计与实现

目录 📚 前言 📑摘要 📑系统流程 📚 系统架构设计 📚 数据库设计 📚 系统功能的具体实现    💬 系统登录注册 系统登录 登录界面   用户添加  💬 抗疫列表展示模块     区域信息管理 添加物资详情 抗疫物资列表展示 抗疫物资申请 抗疫物资审核 ✒️ 源码实现 💖 源码获取 😁 联系方式 📚 前言 📑博客主页:

探索蓝牙协议的奥秘:用ESP32实现高质量蓝牙音频传输

蓝牙(Bluetooth)是一种短距离无线通信技术,广泛应用于各种电子设备之间的数据传输。自1994年由爱立信公司首次提出以来,蓝牙技术已经经历了多个版本的更新和改进。本文将详细介绍蓝牙协议,并通过一个具体的项目——使用ESP32实现蓝牙音频传输,来展示蓝牙协议的实际应用及其优点。 蓝牙协议概述 蓝牙协议栈 蓝牙协议栈是蓝牙技术的核心,定义了蓝牙设备之间如何进行通信。蓝牙协议

python实现最简单循环神经网络(RNNs)

Recurrent Neural Networks(RNNs) 的模型: 上图中红色部分是输入向量。文本、单词、数据都是输入,在网络里都以向量的形式进行表示。 绿色部分是隐藏向量。是加工处理过程。 蓝色部分是输出向量。 python代码表示如下: rnn = RNN()y = rnn.step(x) # x为输入向量,y为输出向量 RNNs神经网络由神经元组成, python

Java研学-RBAC权限控制(八)

九 登录登出 1 登录作用   判断员工是否有权限访问,首先得知道现在操作的人是谁,所以必须先实现登录功能 2 登录流程   ① 提供登录页面,可输入用户名与密码信息,并添加执行登录的按钮。(登录页面不能被拦截)   ② 给按钮绑定点击事件(异步操作,POST请求)   ③ 事件中发送登录请求,使用 AJAX 方式提交。(使用 AJAX 原因:用户体验更好,既可保留用户刚输入的用户名和密码

利用Frp实现内网穿透(docker实现)

文章目录 1、WSL子系统配置2、腾讯云服务器安装frps2.1、创建配置文件2.2 、创建frps容器 3、WSL2子系统Centos服务器安装frpc服务3.1、安装docker3.2、创建配置文件3.3 、创建frpc容器 4、WSL2子系统Centos服务器安装nginx服务 环境配置:一台公网服务器(腾讯云)、一台笔记本电脑、WSL子系统涉及知识:docker、Frp