STC8增强型单片机进阶开发--独立按键

知不足而奋进 望远山而前行


文章目录

  • 目录

    文章目录

    前言

    目标

    内容

    原理图

    按键消抖

    软件设计

    要求

    分析

    实现单个按钮

    实现多个按钮

    使用位操作存储状态

    总结



前言

本次学习旨在探索按键操作及按键消抖的原理和实现方法。通过学习原理图、按键消抖的三种方法以及软件设计的要求和分析,我们将实现单个按钮和多个按钮的按键状态监控,并通过串口将按键事件发送出来。在这个过程中,我们将运用软件延时法、硬件滤波法和程序消抖法,以及位操作存储状态的方法来实现按键操作的稳定性和准确性


目标

  1. 能够读取按键操作
  2. 能够处理按键消抖

内容

原理图

按键消抖

  1. 软件延时法:在按键按下时,使用软件延时一段时间,例如10毫秒,然后再检测按键是否还处于按下状态,如果是,则认为按键有效。这种方法简单易行,但会浪费一定的处理器时间,同时需要根据实际情况调整延时时间。
  2. 硬件滤波法:在按键输入引脚上添加RC滤波电路,可以有效地去除按键信号上的瞬间噪声。这种方法对于高频噪声的去除效果较好,但需要一定的电路设计能力。
  3. 程序消抖法:在程序中记录按键前后两次的状态,如果两次状态不同,则认为按键有效。这种方法可以根据需要调整检测时间,消抖效果较好,但需要额外的程序设计。

我们采用程序消抖法。

软件设计

要求

当用户按下,或者松开按键时,捕获到这个事件。将事件通过串口发出来。

分析

监控引脚的高低电平变化。记录状态,比对实时状态。

  • 监控:死循环去读取电平信息
  • 记录与比对:通过变量记录,实时拿到当前状态,与记录的上一次进行比对。
实现单个按钮
#include "Config.h"
#include "Delay.h"
#include "GPIO.h"
#include "UART.h"
#include "NVIC.h"
#include "Switch.h"#define KEY1 P51void GPIO_config(void) {P5_MODE_IO_PU(GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4);
}void UART_config(void) {COMx_InitDefine		COMx_InitStructure;					//结构定义COMx_InitStructure.UART_Mode      = UART_8bit_BRTx;	//模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTxCOMx_InitStructure.UART_BRT_Use   = BRT_Timer1;			//选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)COMx_InitStructure.UART_BaudRate  = 115200ul;			//波特率, 一般 110 ~ 115200COMx_InitStructure.UART_RxEnable  = ENABLE;				//接收允许,   ENABLE或DISABLECOMx_InitStructure.BaudRateDouble = DISABLE;			//波特率加倍, ENABLE或DISABLEUART_Configuration(UART1, &COMx_InitStructure);		//初始化串口1 UART1,UART2,UART3,UART4NVIC_UART1_Init(ENABLE,Priority_1);		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3UART1_SW(UART1_SW_P30_P31);		// 引脚选择, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}u8 last_key_state = 1; // 抬起void main(){GPIO_config();UART_config();EA = 1;while(1){if(KEY1 == 1 && last_key_state == 0){ // 当前是抬起Up 1, 上一次是按下Down 0printf("KEY1 up\n");last_key_state = 1;}else if(KEY1 == 0 && last_key_state == 1){// 当前是按下Down 0, 上一次是抬起Up 1printf("KEY1 down\n");	last_key_state = 0;}delay_ms(20);}
}
实现多个按钮
#include "Config.h"
#include "Delay.h"
#include "GPIO.h"
#include "UART.h"
#include "NVIC.h"
#include "Switch.h"#define KEY1 P51
#define KEY2 P52
#define KEY3 P53
#define KEY4 P54void GPIO_config(void) {P5_MODE_IO_PU(GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4);
}void UART_config(void) {COMx_InitDefine		COMx_InitStructure;					//结构定义COMx_InitStructure.UART_Mode      = UART_8bit_BRTx;	//模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTxCOMx_InitStructure.UART_BRT_Use   = BRT_Timer1;			//选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)COMx_InitStructure.UART_BaudRate  = 115200ul;			//波特率, 一般 110 ~ 115200COMx_InitStructure.UART_RxEnable  = ENABLE;				//接收允许,   ENABLE或DISABLECOMx_InitStructure.BaudRateDouble = DISABLE;			//波特率加倍, ENABLE或DISABLEUART_Configuration(UART1, &COMx_InitStructure);		//初始化串口1 UART1,UART2,UART3,UART4NVIC_UART1_Init(ENABLE,Priority_1);		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3UART1_SW(UART1_SW_P30_P31);		// 引脚选择, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}#define	DOWN	0
#define	UP		1u8 last_key_states[] = {UP, UP, UP, UP};		// key的最后一次状态// 判断指定位置【是否是】按下或抬起
#define	IS_KEY_DOWN(i)		last_key_states[i] == DOWN
#define	IS_KEY_UP(i)		last_key_states[i] == UP// 将指定位置值【设置】为按下或抬起
#define SET_KEY_DOWN(i)		last_key_states[i] = DOWN
#define SET_KEY_UP(i)		last_key_states[i] = UPvoid main(){GPIO_config();UART_config();EA = 1;while(1){if(KEY1 && IS_KEY_DOWN(0)){ // 这次是抬起Up 1, 上一次是按下Down 0printf("KEY1 up\n");SET_KEY_UP(0);}else if(!KEY1 && IS_KEY_UP(0)){// 这次是按下Down 0, 上一次是抬起Up 1printf("KEY1 down\n");	SET_KEY_DOWN(0);}if(KEY2 && IS_KEY_DOWN(1)){ // 这次是抬起Up 1, 上一次是按下Down 0printf("KEY2 up\n");SET_KEY_UP(1);}else if(!KEY2 && IS_KEY_UP(1)){// 这次是按下Down 0, 上一次是抬起Up 1printf("KEY2 down\n");	SET_KEY_DOWN(1);}if(KEY3 && IS_KEY_DOWN(2)){ // 这次是抬起Up 1, 上一次是按下Down 0printf("KEY3 up\n");SET_KEY_UP(2);}else if(!KEY3 && IS_KEY_UP(2)){// 这次是按下Down 0, 上一次是抬起Up 1printf("KEY3 down\n");	SET_KEY_DOWN(2);}if(KEY4 && IS_KEY_DOWN(3)){ // 这次是抬起Up 1, 上一次是按下Down 0printf("KEY4 up\n");SET_KEY_UP(3);}else if(!KEY4 && IS_KEY_UP(3)){// 这次是按下Down 0, 上一次是抬起Up 1printf("KEY4 down\n");	SET_KEY_DOWN(3);}delay_ms(20);}
}
使用位操作存储状态
// P51, P52, P53, P54
//u8 last_key_states[] = {UP, UP, UP, UP}; 
// 0b 0 0 0 0 - 1 1 1 1
u8 last_key_states = 0x0F; 	// KEY最后一次状态的8个位(只使用低4位)// 判断指定位置【是否】是按下
//  0b 0 0 0 0 - 0 0 0 0
//& 0b 0 0 0 0 - 0 1 0 0		----- 判断指定位i=2是否是0
//  0b 0 0 0 0 - 0 0 0 0			== 0
#define IS_KEY_DOWN(i)			(last_key_states & (1 << i)) == 0// 判断指定位置【是否】是抬起
//  0b 0 0 0 0 - 1 1 0 0
//& 0b 0 0 0 0 - 1 0 0 0		----- 判断指定位i=3是否是1
//  0b 0 0 0 0 - 1 0 0 0			> 0
#define IS_KEY_UP(i)			(last_key_states & (1 << i)) > 0// 将指定位置值【设置】为按下
//   0b 0 0 0 0 - 1 1 0 0			
//&= 0b 1 1 1 1 - 1 0 1 1		------ 将指定位i=2设置为0,按下
//&=~0b 0 0 0 0 - 0 1 0 0
//	 0b 0 0 0 0 - 1 0 0 0		
#define SET_KEY_DOWN(i)			last_key_states &= ~(1 << i)// 将指定位置值【设置】为抬起
//   0b 0 0 0 0 - 1 1 0 0			
//|= 0b 0 0 0 0 - 0 0 1 0		------ 将指定位i=1设置为1,抬起
//   0b 0 0 0 0 - 1 1 1 0
#define SET_KEY_UP(i)			last_key_states |= (1 << i)
  • u16存储状态: 16个 1 << i 只能存 16 位
  • u32存储状态: 32个, 1 << i 要改成 1L << i 能存32位

总结

通过本次学习,我们深入了解了按键操作的原理及按键消抖的多种方法。从简单的软件延时法到更高效的程序消抖法,我们掌握了不同的实现技巧,并学会了如何利用位操作来存储按键状态。通过实现单个按钮和多个按钮的按键监控系统,我们进一步加深了对按键操作的理解,并提升了对嵌入式系统设计的能力。这些知识和技能将为我们在实际项目中处理按键操作提供重要的参考和指导

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

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

相关文章

如何选择D类音频放大器(数字功率放大器)

1 简介 多年来&#xff0c;音频内容一直在不断发展。从当地唱片店购买 12 英寸 LP 黑胶唱片的时代已经成为过去&#xff0c;现在我们通过流式传输几乎可即时播放云端的任何内容。虽然一些音频爱好者会为了获得新奇体验而重拾黑胶唱片&#xff0c;但今天绝大多数的音频都是以数…

JVM学习笔记(持续更新)

JDK、JRE、JVM区别&#xff1f; 类加载过程 装载 验证 准备 解析 初始化 类加载器分类 双亲委派模型 如何打破双亲委派模型&#xff1f; 自定义类加载器&#xff0c;集成ClassLoader类重写loadClass,如Tomcat JVM内存模型 JVM 需要使用计算机的内存&#xff0c;Java 程序…

【LeetCode 101】对称二叉树

1. 题目 2. 分析 这道题比较经典。我又一次做错了&#xff0c;这次是花了20min都没有做出来。 最开始我的思想就是&#xff0c;递归比较左根节点的左子树和右根节点的右子树是否对称即可&#xff0c;然后觉得能解决问题了&#xff0c;便动手coding。哪知道&#xff0c;又碰到了…

电源滤波器怎么选用

电源滤波器怎么选用 滤波器应用场景及作用第一步&#xff1a;第二步&#xff1a;第三步&#xff1a;第四步&#xff1a; 滤波器应用场景及作用 可以有效解决EMC测试无法通过、端口防护、滤除干扰、设备保护等问题 主要功能有: 1、降低主电源谐波; 2、保护驱动装置电力电子元件…

算法人生(18):从神经网络的“剪枝策略”看“怎么找回时间”

IT人的工作和生活难平衡这事&#xff0c;到底要怎么解决呢&#xff0c;让我们从神经网络的“剪枝策略”中找点灵感吧&#xff01; 剪枝策略是指训练和优化深度神经网络时采取的一种技术&#xff0c;从名字就知道&#xff0c;它就像修剪树木一样&#xff0c;去除不必要的枝叶&a…

Vuex 是什么?VueX简介

聚沙成塔每天进步一点点 本文内容 ⭐ 专栏简介Vuex 是什么核心概念1.State&#xff08;状态&#xff09;2. Getter&#xff08;获取器&#xff09;3. Mutation&#xff08;突变&#xff09;4. Action&#xff08;动作&#xff09;5. Module&#xff08;模块&#xff09; 原理解…

使用STS临时访问凭证通过客户端直连OSS对象存储服务器

目录 1、导论 2、客户端直传 3、创建RAM用户以及RAM角色 4、如何实现客户端直传 4.1、跨域访问 4.2、安全授权 5、代码示例 5.1、后端代码实例 5.2、客户端代码实例 1、导论 最近在做项目的过程中使用到了阿里云OSS来存储客户端上传的文件&#xff0c;方法是直接将客…

Keras深度学习框架实战(3):EfficientNet实现stanford dog分类

1、通过EfficientNet进行微调以实现图像分类概述 通过EfficientNet进行微调以实现图像分类&#xff0c;是一个使用EfficientNet作为预训练模型&#xff0c;并通过微调&#xff08;fine-tuning&#xff09;来适应特定图像分类任务的过程。一下是对相关重要术语的解释。 Effici…

Flutter-自定义可展开文本控件

Flutter 在移动开发中&#xff0c;常常需要处理一些长文本显示的场景&#xff0c;如何优雅地展示这些文本并允许用户展开和收起是一个常见的需求。在本文中&#xff0c;我将分享如何使用Flutter实现一个可展开和收起的文本控件。 效果 我们将实现一个可展开和收起的文本控件…

yolov10模块

yolov10模块 1 C2f2 C2fCIB2.1 CIB2.2 RepVGGDW 3 PSA4 SCDown5 v10Detect 论文代码&#xff1a;https://github.com/THU-MIG/yolov10 论文链接&#xff1a;https://arxiv.org/abs/2405.14458 Conv是Conv2dBNSiLU PW是Pointwise Convolution(逐点卷积) DW是Depthwise Convolut…

【SQL学习进阶】从入门到高级应用【企业真题】

文章目录 第一题第二题第三题第四题第五题第六题第七题第八题第九题MySQL行转列使用case whengroup by完成 第十题 &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f495;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01; &#x1f495;希望您在这…

疫情物资捐赠和分配系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;管理员管理&#xff0c;机构管理&#xff0c;用户管理&#xff0c;发放管理&#xff0c;物资管理 前台账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;物资论坛&#xff0c;公告信息…

STM32作业设计

目录 STM32作业设计 STM32作业实现(一)串口通信 STM32作业实现(二)串口控制led STM32作业实现(三)串口控制有源蜂鸣器 STM32作业实现(四)光敏传感器 STM32作业实现(五)温湿度传感器dht11 STM32作业实现(六)闪存保存数据 STM32作业实现(七)OLED显示数据 STM32作业实现(八)触摸按…

彻底卸载Windows Defender

概述 卸载Windows Defender的方法有很多&#xff0c;如修改注册表、组策略&#xff0c;执行脚本等等&#xff0c;这些方法操作过于繁琐和复杂&#xff0c;不适合小白&#xff0c;今天带来一款强大的卸载工具&#xff0c;只需要以管理员身份运行该软件即可&#xff0c;不用其他操…

禹晶、肖创柏、廖庆敏《数字图像处理(面向新工科的电工电子信息基础课程系列教材)》Chapter 6插图

禹晶、肖创柏、廖庆敏《数字图像处理&#xff08;面向新工科的电工电子信息基础课程系列教材&#xff09;》 Chapter 6插图

Stable Diffusion详细教程

目录 &#x1f40b;引言 &#x1f40b;Stable Diffusion基本概念 &#x1f988;潜在扩散模型 &#x1f988;图像生成原理 &#x1f40b;Stable Diffusion安装部署 &#x1f988;环境要求 &#x1f988;安装步骤 &#x1f40b;Stable Diffusion阶段 &#x1f988;准备阶…

PHP 页面报错Warning</b>: Cannot modify header information - headers already sent by

先给出解决方案再解释&#xff0c;如果急着用就不用看解释了。 解决方案一&#xff1a;保存php文件编码为utf-8无BOM码&#xff0c;具体操作可以用notepad等编辑器完成&#xff0c;把 sesstion_start() 放在文档所有输出&#xff08;包括html标签和php的输出语句&#xff0c;具…

ch4网络层---计算机网络期末复习(持续更新中)

网络层概述 将分组从发送方主机传送到接收方主机 发送方将运输层数据段封装成分组 接收方将分组解封装后将数据段递交给运输层网络层协议存在于每台主机和路由器上 路由器检查所有经过它的IP分组的分组头 注意路由器只有3层(网络层、链路层、物理层) 网络层提供的服务 一…

Java筑基-集合[Set、Map、List、Stack、Queue]

这里写目录标题 一、Collection接口结构图二、Set集合1、常用方法 三、List集合1、List集合常用方法2、代码案例 四、Stack集合1、方法2、代码展示 五、Queue集合1、常用的方法2、代码展示 六、Map集合1、基本概念2、常用方法3、代码展示 一、Collection接口结构图 二、Set集合…

小熊家务帮day8-day9 客户管理模块2 (用户定位,地址簿,实名认证,银行卡信息上传等功能)

客户管理模块 0.用户定位功能0.1 需求0.2 接口分析0.3 接口开发Controller层开发Service层开发 1.我的地址簿功能1.1 需求1.2 数据库设计1.3 新增地址簿1.3.1 接口设计1.3.2 接口开发Controller层开发Service层开发测试功能 1.4 地址簿查询1.4.1 接口设计1.4.2 接口开发Control…