学习硬件测试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模拟器玩玩魂斗罗。 思路很简单&…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)
参考官方文档:https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java(供 Kotlin 使用) 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...
均衡后的SNRSINR
本文主要摘自参考文献中的前两篇,相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程,其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt 根发送天线, n r n_r nr 根接收天线的 MIMO 系…...
如何在网页里填写 PDF 表格?
有时候,你可能希望用户能在你的网站上填写 PDF 表单。然而,这件事并不简单,因为 PDF 并不是一种原生的网页格式。虽然浏览器可以显示 PDF 文件,但原生并不支持编辑或填写它们。更糟的是,如果你想收集表单数据ÿ…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
