学习硬件测试04:触摸按键+PWM 驱动蜂鸣器+数码管(P62~P67、P71、P72)
一、触摸按键
1.1理论讲解
1.1.1实验现象
- 触摸按键 1 单击与长按,控制 LED1;
- 触摸按键 2 单击与长按,控制 LED2;
- 触摸按键 3 单击与长按,控制 LED3;
- 触摸按键 4 单击与长按,控制继电器;
1.1.2硬件电路
是原理图上触摸按键、继电器、LED 灯三部分电路。
注意;按键一般为高电平,按下后为低电平,在配置时就要注意是下降沿触发。
1.1.3外部中断


1.1.4HAL库函数

第一行:读管脚状态,要么低电平,要么高电平。
第二行:写管脚状态,写高或者写低。
第三行:选择一个管脚,状态取反。
第四行:锁定管脚,进行保护状态,不能写了。
第五行:中断处理函数,软件自动生成的,后续讲解。
第六行:外部中断的回调函数,其中的变量是指示具体管脚,是具体管脚的回调函数。(如PA~PA15共用一个外部中断,如上图,共用一个回调函数,通过变量去判断具体是哪一个管脚引起的中断)
1.2初始化
1.2.1继电器初始化
推挽输出,默认低电平,使其刚开始处于断开的模式。

1.2.2触摸按键初始化
一般为高电平,按下后为低电平,故配置成下降沿触发。
(如果配上升沿触发,单击按键松开才触发,长按不触发;如果配置成均触发,则单击触发两次,所以触发方式的配置和硬件紧密相连)
注意不是配置成输入模式,而是配置成中断模式,后面软件编写也是启动中断的功能。
注意当按键 1 配置成中断时,与其共使用一个外部中断的其他引脚配置成的中断就会自动消失


1.2.3配置按键的中断

1.3编程
在 main.c 中代码都是一样的,但是代码调用的代码是不一样的,不论是软件自动生成的初始化代码,还是我们自己编写的代码。

MyInit.Peripheral_Set() 自定义初始化代码如下:
static void Peripheral_Set()
{printf("----此程序实现触摸按键单击与长按功能----\r\n");printf("Initialization completed, system startup!\r\n");printf("Software version is V%.1f\r\n\r\n",SoftWare_Version);printf("等待触摸按键:\r\n\r\n");
}
说明:
- 代码比较灵活,长按的时间可以自由设定。
- 单击的时间也可以自由设定,可以不是10ms检查一次,可以是5ms检查一次,用户就不用等待那么长的时间。
- 本测试中按键式中断,并且是不影响其他中断的运行或者被影响,当有别的中断并不会影响该中断检查是不是长按/ 单击的程序。
- 注意上面说的别的中断,以及在其他任何项目中的一般中断,都要遵循“中断快进快出”的原则,运行几十微秒~几百微秒,问题都不大。
1.4实验现象
单击翻转 LED 灯的状态,长按 ≥2S 翻转两次 LED 灯的状态,两次间隔 200ms。
触摸按键
二、PWM 驱动蜂鸣器
2.1理论讲解
2.1.1程序功能
上电后,无源蜂鸣器发出声音,通过触摸按键关闭或打开蜂鸣器。
2.1.2无源蜂鸣器
无源蜂鸣器没有振动源,驱动需要 PWM 波来驱动,通过改变 PWM 波的频率来改变蜂鸣器的声音。
2.1.3 PWM
英文全称 Pulse-Width Modulation,脉冲宽度调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,通过调占空比调节光的强度、声音、电机等。本次是通过通用定时器进行频率调节。
2.1.4通用定时器 TIMx
本次是通过通用定时器来调节 PWM 的频率,TIMx 器是一个通过可编程预分频器驱动的 16 位自动装载计数器构成。它适用于多种场合,包括测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)。使用定时器预分频器和 RCC 时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整,每个定时器都是完全独立的,没有互相共享任何资源,可以一起同步操作,包含:
- 计数器寄存器(TIMx_CNT)
- 预分频器寄存器 (TIMx_PSC)
- 自动装载寄存器 (TIMx_ARR)

2.1.5计数模式
在向上计数模式中,计数器从0计数到自动加载值(TIMx_ARR计数器的内容),然后重新从0开始计数并且产生一个计数器溢出事件。这样的计数方式更加灵活,在计数中间时可以和另一个设定的值进行比较,进行其他需要的操作。
2.1.6 PWM模式
脉冲宽度调制模式可以产生一个由 TIMx_ARR 寄存器确定频率、由TIMx_CCRx寄存器确定占空 比的信号。

2.1.7HAL库函数

这些是定时器关于PWM的函数:
- 上面4个是:初始化函数,不用我们写
- 第4个:DMA功能,没用到
- 第3个:中断,没用到
- 第2个:启动、停止输出功能,后续就是通过触摸按键调用这两个函数打开或者关闭报警。
2.2软件初始化

2.2.1 框1
蜂鸣器的引脚为 PA8 ,在 Cubemx 中 PA8 只能设置成为定时器 1,定时器 1 是高级定时器,具有上面所讲的通用定时器的功能,我们也只使用通用定时器的功能,其他的功能不展开讲解和使用。
2.2.2 框2
Clock Source 时钟源:选择使用内部时钟
Channel1:输出 PWM 波
注意在这里设置完之后,引脚可能会自动跳变到默认引脚,这里是 PE9,还需要手动重新设置为我们蜂鸣器的 PA8。
2.2.3 框3
(1)预分频器

系统时钟 72M,AHB2 的时钟频率也是 72M ,故 PA8 的初始时钟也是 72M ,通过预分频器企图达到的目标评率为 1M 。
预分频器可以进行 0~65535 分频(因为零也算,所以后面要加一),计算预分频器具体分频数 X 的公式如下:
![]()

所以在软件配置的值为:72000000/1000000-1(目标频率是 1M )
(2)其他
Counter Mode 计数模式:向上
Counter Period 自动重装定时器:设置 PWM 波的频率
频率=预分频器频率/次数=1000000/1000=1000HZ
![]()
Internal Clock Division 内部时钟分频器:不需要
Repetition Counter 重复计数器:高级定时器功能,此处不需要
auto-reload preload 自动重新装载:必须使能,由于后续需要改变蜂鸣器的音色,就需要改变频率,该变频率就需要重装载。如果没有使能,后续即使改变 ARR 值夜不会重新装载进去。
2.2.4 框4
这里主要是设置占空比。

Mode 模式:PWM 模式 1
Pulse 脉冲(16 位值):500,这个值就是 CCR
(你可以这么理解,通过预分频器最后的时钟频率是1M,但是我还要自己更加灵活的控制PWM的频率,灵机一动想到了计数的方式。
所以才有了通过上面的设置让计数 1000 次(ARR),周期就变成了 1M×1000 =1ms 。
就这么利用一下这个计数,未免也太浪费资源了吧,既然它在向上计数,那就在中间设计一个比较值 CCR,利用 CCR 来调节占空比,小于 CCR 时 PWM 波输出高电平,大于 CCR 是 PWM 波输出低电平。)
Qutput compare preload 输出比较预加载:使能(可以改变占空比,而不是固定占空比)
极速模式:关闭
CH 极性:高(小于 CCR 的状态)
状态:重置
2.2.5达到的状态
每隔一毫秒中断一次,占空比为 50% 。
2.3编程
2.3.1文件结构
Buzzer.c:控制蜂鸣器的开启,并记录其状态。
Timer6.c:通过定时器 6 改变频率,发出不同的声音。
触摸按键:触发中断关闭或者打开蜂鸣器。
2.3.2文件内容
(1)运行函数
main.c → System.c
运行函数中没有内容,因为这一次是通过按键中断来改变声音。

(2)蜂鸣器结构体
Buzzer.h

Buzzer.c
#include "MyApplication.h"static void Buzzer_ON(void);
static void Buzzer_OFF(void); //定义结构体
Buzzer_t Buzzer =
{OFF_Status,//默认蜂鸣器初始状态是关闭Buzzer_ON,Buzzer_OFF//两个函数赋给函数指针,函数如下
};static void Buzzer_ON(void)//打开蜂鸣器
{Buzzer.Status = ON_Status;//更新一下状态为打开状态HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);//通过这个HAL库函数打开定时器(定时器1,通道1)
}static void Buzzer_OFF(void)//关闭蜂鸣器,理论同上
{Buzzer.Status = OFF_Status;HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_1);
}
(3)Myinit.c
上电初始化只是打开蜂鸣器

(4)改变频率来改变音色
也是在 CallBack.c 文件中,共有三个参数:
- f:频率 → 通过改变 ARR(1000:1ms;2000:2ms;500:0.5ms)
- cnt:在某一频率是重复的时间长度
#include "MyApplication.h"/** @name HAL_TIM_PeriodElapsedCallback* @brief 定时器中断回调函数* @param *htim -> 处理定时器的结构体指针* @retval None
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{static uint8_t Fre_Cnt = 0;if(htim->Instance == htim6.Instance){//程序支持运行,指示灯间隔1s闪烁if(++Timer6.usMCU_Run_Timer >= TIMER0_1S){Timer6.usMCU_Run_Timer = 0;LED.LED_Flip(LED1);}//控制PWM的频率长度与大小if(Fre_Cnt++ >= 2){Fre_Cnt = 0;//定时器时钟 = 1MHzPWM频率 = 1/((1/1000000)*ARR) = 1000000/ARR //ARR = 250, PWM频率为4KHz//ARR = 500, PWM频率为2KHz//ARR = 1000,PWM频率为1KHz//ARR = 2000,PWM频率为0.5KHZTIM1->ARR -= 10;if(TIM1->ARR <= 500)TIM1->ARR = 2000;//设置占空比为50%TIM1->CCR1 = TIM1->ARR / 2;}}
}
(5)CallBack.c
只控制蜂鸣器打开或者关闭,按下按键就翻转蜂鸣器的状态。
#include "MyApplication.h"void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin == KEY1_Pin){LED.LED_Flip(LED2);//控制蜂鸣器开关if(Buzzer.Status == ON_Status){Buzzer.OFF();}else{Buzzer.ON();}}
}
2.3.3整体框架
等我明天(8.3)画出来,等我!
2.3.4实验现象
PWM波驱动蜂鸣器
三、数码管
3.1数码管驱动 IC 手册阅读
3.2编程
相关文章:
学习硬件测试04:触摸按键+PWM 驱动蜂鸣器+数码管(P62~P67、P71、P72)
一、触摸按键 1.1理论讲解 1.1.1实验现象 触摸按键 1 单击与长按,控制 LED1;触摸按键 2 单击与长按,控制 LED2;触摸按键 3 单击与长按,控制 LED3;触摸按键 4 单击与长按,控制继电器; 1.1.2硬件电路 是原理图上触摸…...
JS原型链
JS的原型链 文章目录 JS的原型链前言一、原型是什么?二、原型链总结 前言 在使用数组或对象中的方法时,你是不是会感觉很奇怪,为什么仅仅是创建了一个数组或是对象,就能够使用它提供的方法呢?JS是怎么做到的呢&#x…...
《Java初阶数据结构》----5.<二叉树的概念及使用>
前言 大家好,我目前在学习java。之前也学了一段时间,但是没有发布博客。时间过的真的很快。我会利用好这个暑假,来复习之前学过的内容,并整理好之前写过的博客进行发布。如果博客中有错误或者没有读懂的地方。热烈欢迎大家在评论区…...
git查看记录详解
文章目录 git查看记录查看文件修改列表查看修改差异友好的查看修改记录结合多个选项查看记录示例输出 git查看记录 使用 git log 你不仅可以查看提交记录,还可以通过一些选项查看文件的修改列表、修改差异,并以更友好的方式查看修改记录。以下是一些常用…...
检索增强生成RAG系列10--RAG的实际案例
讲了很多理论,最后来一篇实践作为结尾。本次案例根据阿里云的博金大模型挑战赛的题目以及数据集做一次实践。 完整代码地址:https://github.com/forever1986/finrag.git 本次实践代码有参考:https://github.com/Tongyi-EconML/FinQwen/ 目录 …...
程序员自我提升的全面指南
程序员自我提升的全面指南 1. 技术基础巩固重要性实践方法 2. 技术栈拓展重要性实践方法 3. 软技能提升重要性实践方法 4. 实践与项目经验重要性实践方法 5. 持续学习与职业规划重要性实践方法 6. 代码质量与优化重要性实践方法 7. 思维与创新能力重要性实践方法 8. 健康与心理…...
【golang】Golang手写元组 tuple | golang tuple
Golang手写元组 tuple 1、源码 如下: package tupletype Tuple[T any, U any] struct {First TSecond U }// zip combines elements of two slices into a slice of pairs (tuples), which is useful for combining related data. func Zip[T any, U any](slice…...
golang中struct的tag -简记
今天 简单整理一下,关于golang中struct的tag type User struct {UId int gorm:"column:uid;type:bigint;unique_index;not null;comment:用户id"Name string json:"name"Age int bson:"age"From string binding:"requi…...
分布式领域扩展点设计稿
分布式领域扩展点设计稿 背景坐标设计理念设计图Quick Start相关组件 背景 随着交易业务和基础知识的沉淀,愈发觉得扩展点可以在大型交易分布式架构中可以做更多的事情。 经过一个月的思考,决定将 单点领域扩展点(savior-ext) 从…...
玩转微信公众号变现:从新手到专家的全攻略
个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119qq.com] 📱…...
JVM: 方法调用
文章目录 一、介绍二、方法调用的原理1、静态绑定2、动态绑定(1)介绍(2)原理 一、介绍 在JVM中,一共有五个字节码指令可以执行方法调用: invokestatic: 调用静态方法。invokespecial:调用对象…...
测试面试宝典(四十一)—— 接口自动化的优缺点
接口自动化测试的优点: 1. 提高测试效率:能够快速执行大量的测试用例,节省了手动测试重复执行的时间和人力成本。 2. 尽早发现问题:可以在软件开发的早期阶段介入,有助于及时发现接口层面的缺陷,降低修复…...
“火炬科企对接”先进计算产业推进会 | 麒麟信安受邀参加,并签署开源生态合作协议
7月30日,“火炬科企对接”先进计算产业推进会在长沙隆重召开。大会由工业和信息化部火炬高技术产业开发中心、湖南省科学技术厅、湖南省工业和信息化厅、湖南湘江新区管理委员会、中国邮政储蓄银行联合举办。麒麟信安与来自国内先进计算领域的专家学者,2…...
中文网址导航模版HaoWa1.3.1/模版网站wordpress导航主题
HaoWa v1.3.1由挖主题开发的一款网址导航类主题。 HaoWA主题除主体导航列表外,对主题所需的小模块都进行了开放式的HTML编辑器形式的功能配置,同时预留出默认的代码结构,方便大家在现有的代码结构上进行功能调整。 同时加入了字体图标Font …...
图欧学习资源网创站以来的更新日志(截止至2022.5.6)不完全统计
一、网站创立和初步发展 2021年10月28日创建【TUO图欧视频备份站】,当时只有【单词视频】文件夹. 小学、初中、高中、大学、四六级、专四、专八、专升本、考研、考博、托福、雅思、托业、GRE、SAT、GMAT、MBA、新概念等 数量:500个文件,60个…...
现代前端架构介绍(第二部分):如何将功能架构分为三层
远离JavaScript疲劳和框架大战,了解真正重要的东西 在这个系列的前一部分 《App是如何由不同的构建块构成的》中,我们揭示了现代Web应用是由不同的构建块组成的,每个构建块都承担着特定的角色,如核心、功能等。在这篇文章中&#…...
LeetCode Easy|【21. 合并两个有序链表】
力扣题目链接 状态:拿到本题的第一反应就是使用双指针,分别指向两个链表的开头位置。 随后的思路就是以第一条链表为基准完成插入,并且对于遍历到的每个节点都应该保存其状态。 写了一下代码后发现,我们应该以第一个节点较小的链表…...
大模型的架构参数是指定义模型基本结构和组成的各种参数,这些参数对模型的性能、训练效率和泛化能力具有重要影响。以下是对大模型架构参数的详细介绍
大模型架构参数 大模型的架构参数是指定义模型基本结构和组成的各种参数,这些参数对模型的性能、训练效率和泛化能力具有重要影响。以下是对大模型架构参数的详细介绍: 一、基本结构和组成 层数:模型的层数是指模型中全连接网络或特定结构…...
人工智能会越来越闭源——对话东北大学副教授王言治 | Open AGI Forum
作者 | Annie Xu 责编、采访 | Echo Tang 出品丨GOSIM 开源创新汇 在读期间研究方向为并不“火”的模式识别与深度学习,毕业却刚好踩上人工智能计算研究的风口……来自美国东北大学的王言治副教授深耕深度学习与大模型,前瞻性地探索大模型的本地化部署…...
【前端】(仅思路)如何在前端实现一个fc手柄,将手机作为游戏手柄设备。
文章目录 背景界面demo原型图(没错,就是它,童年回忆) 遇到的问题最终后端demo(甚至比前端逻辑更简单) 背景 突发奇想,想要在前端实现一个fc游戏手柄,然后控制电脑的nes模拟器玩玩魂斗罗。 思路很简单&…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?
大家好,欢迎来到《云原生核心技术》系列的第七篇! 在上一篇,我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在,我们就像一个拥有了一块崭新数字土地的农场主,是时…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
