news 2026/9/8 4:27:25

STM32定时器PWM驱动蜂鸣器播放音乐实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32定时器PWM驱动蜂鸣器播放音乐实战指南

简介:野火STM32指南者开发板是嵌入式入门的常用平台,资源内含一个基于该开发板的完整工程,实现通过蜂鸣器播放《红尘情歌》,面向正在学习STM32的开发者,尤其是想掌握GPIO控制、定时器中断以及音频驱动原理的爱好者。资源包为RAR压缩包,大小约4.33MB,共177个文件,以C源文件、H头文件、编译生成的O/D目标文件和Keil工程配置为主,包含可直接打开的uvprojx工程文件,方便查看代码和重新编译。功能上支持按键KEY1启动播放、复位键重置状态,通过定时器产生不同频率驱动蜂鸣器,代码覆盖音符频率编码、中断服务程序、音乐数据循环读取等关键环节,能帮助读者理解蜂鸣器发声机制与嵌入式音频播报的基本思路。目前已有4744人浏览学习,适合作为STM32进阶练习、课程设计或项目复现的参考。资源内文件类型齐全,工程结构清晰,可以辅助快速定位到定时器配置和音乐播放函数。 把野火STM32指南者开发板拿在手里,跑通第一个蜂鸣器例程的时候,所有人听到的都是“嘀——嘀——嘀”那种死板声音。我当时总觉得哪里不对劲:蜂鸣器既然能被驱动,为什么不能像手机铃声一样响出一段旋律?后来查了一堆资料才明白,问题不在写代码,而在蜂鸣器本身。这个项目就是用指南者配合定时器PWM,让蜂鸣器一段段“唱”出《红尘情歌》,整个过程踩了不少坑,但也把STM32的定时器、PWM、引脚重映射、音乐频率换算这些知识点串起来了。如果你手头有一块STM32F103的板子,不管是不是指南者,想搞懂“单片机如何播放音乐”,这篇应该能帮你省下不少时间。

1. 让蜂鸣器开口唱歌的前提:有源和无源是两种完全不同的东西

1.1 为什么有源蜂鸣器只能“滴”不能“哆来咪”

蜂鸣器按内部结构分两类:有源蜂鸣器和无源蜂鸣器。“有源”的“源”指的是振荡源,不是电源。有源蜂鸣器内部集成了一颗多谐振荡器,只要你给它通上直流电,它自己就会以固定频率振动,一般是2.7kHz左右。这块板子一上电,你听到的“嘀”声就是它发出来的。这种蜂鸣器你不管写什么程序,声音永远是同一个音调,因为它的频率被锁死了,程序改不了。

无源蜂鸣器内部没有振荡源,它的本质就是一坨线圈加振膜,或者一片压电陶瓷。它自己不产生频率,必须由外部给它一个方波信号,方波的频率是多少,它振动出来的声音就是多少赫兹。也就是说,音高完全由软件控制,频率变了,音调就变了。这就是无源蜂鸣器能够播放《红尘情歌》的根本原因。

做个不太严谨的类比:有源蜂鸣器像一个只会吹一个调的口哨,无源蜂鸣器像一个喇叭,你给我什么信号,我就出什么声音。

1.2 判断你的蜂鸣器类型,以及指南者上的实际接法

最笨也最有效的判断方法:把蜂鸣器接到3.3V电源上,正负一碰,如果立刻响,就是有源;如果不响,就是无源。或者直接看封装底部的丝印和规格书,有源蜂鸣器一般会标“内置振荡电路”或者型号里带“Active”,无源蜂鸣器标的是“External Drive”。

野火指南者开发板上蜂鸣器的驱动引脚是PB5,经过一颗S8550三极管做电流放大。这里有个需要注意的地方:指南者不同批次的板子,板载蜂鸣器到底是有源还是无源,不完全是统一的。如果你的板载蜂鸣器是有源的,直接用它播放音乐只会听到一个固定频率的刺耳声音。我这次做的时候为了排除干扰,直接外接了一个3.3V无源蜂鸣器模块,信号线接到PB5,电源接3.3V,GND接板子的GND。PCB上的板载蜂鸣器如果冲突,可以断开或者用飞线绕过,以你自己的原理图为准。

从驱动极性来说,PB5输出高电平时三极管导通,蜂鸣器通电;输出低电平时三极管截止,蜂鸣器断电。这个“高电平导通”的电路对无源蜂鸣器播放音乐其实很合适,后面配置PWM时就按这个极性来。

2. 把《红尘情歌》拆成“频率+时长”:音乐的数据化过程

2.1 一个音高对应一个频率:十二平均律快速查表

要让STM32播放音乐,第一步是把简谱里每个音转换成具体的频率值。音乐里的标准音A4是440Hz,其他音高都通过十二平均律推出来。公式是:f = 440 × 2^(n/12),其中n是目标音与A4相差的半音数,比A4高就是正数,低就是负数。比如C4,也就是中央C,比A4低9个半音,算出来就是440 × 2^(-9/12) ≈ 261.63Hz。

实际项目中我不会每次都在单片机上算这个公式,而是直接把C调常用音高的频率算好,做成一张查表。下面这张表就是《红尘情歌》主旋律里用到的音高:

简谱唱名频率(Hz)说明
低音3165基本用不到,但保留
低音5196歌曲低音区偶尔出现
低音6220歌曲低音区常用
1(do)262C4
2(re)294D4
3(mi)330E4
5(sol)392G4
6(la)440A4,标准音
高音1523C5
高音2587D5
高音3659E5
高音5784G5

在代码里我直接用宏定义把这些频率写死,比如#define NOTE_G4 392,这样乐谱数组写起来跟简谱一样直观。

2.2 一个节拍对应一个时长:4/4拍怎么量化

决定音高的是频率,决定节奏的是每个音符持续的时间。我这里用的《红尘情歌》版本是4/4拍,也就是以四分音符为一拍,每小节四拍。程序中四分音符用一个基准值Q表示,八分音符就是Q/2,二分音符就是Q×2,全音符就是Q×4。

我取Q = 500ms,也就是每分钟120拍的速度,听起来比较轻快,跟原曲那种中速的感觉差不多。如果你想更慢更有感情,把Q改成600甚至700都行。歌曲里那种“停顿”用休止符表示,频率为0,时长照常保留。

宏定义这样写就够了:

#define Q 500 // 四分音符,一拍 #define E Q / 2 // 八分音符 #define H Q * 2 // 二分音符

2.3 用结构体数组描述一首歌

把频率和时长打包成一个结构体,再做成数组,一首歌就是一张“乐谱数据表”。结构体定义如下:

typedef struct { uint16_t freq; // 频率(Hz),0表示休止 uint16_t duration; // 时长(ms) } MusicNote;

播放的时候,程序从头到尾遍历数组,每取到一个音符,就设置一次PWM频率,保持对应的时长,然后切到下一个。这种设计扩展性很好,想换歌只需要改数组内容,播放逻辑完全不用动。我把这个数组写成const,让它存在Flash里而不是RAM里,STM32F103的RAM本来就不大,一首歌几百个音符全塞RAM里有点浪费。

3. PB5上的PWM配置:TIM3通道2部分重映射的完整思路

3.1 为什么非要用PB5,为什么是部分重映射

指南者的板载蜂鸣器已经焊死在PB5上,所以我优先考虑把PWM信号输出到PB5。查一下STM32F103的引脚复用表,TIM3的通道2默认是PA7,但它支持部分重映射,重映射之后TIM3_CH2会跑到PB5上。这就是“部分重映射”的含义:不是所有通道都换位置,而是把一部分通道重新分配到别的引脚。

还要注意一个连带影响:启用TIM3的部分重映射后,TIM3_CH1会从默认的PA6变到PB4。如果你的项目里同时用到了PA6或者PA7的定时器功能,就要特别小心,重映射会让它们彻底失效。如果只是像我一样单纯想用PB5输出PWM,那这个重映射是划算的。另外,PB4在STM32F103上默认是JTAG的NJTRST引脚,如果哪天你想把PWM输出到PB4,必须先禁用JTAG功能。我用的是PB5,不受这个限制,但如果你照抄代码然后发现PB4不工作,原因就在这。

3.2 预分频计算与PWM输出代码

STM32F103的系统时钟经过SystemInit初始化后是72MHz,TIM3挂载在APB1上,APB1预分频为2时,定时器时钟会倍频到72MHz。我要产生一个频率可变的方波,思路是把计数频率固定下来,然后通过修改自动重装载值ARR来改变PWM周期。

我设置预分频PSC = 71,这样定时器计数频率 = 72MHz / (71 +

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 7:25:43

交易纪律三件事:怕就减、移动止盈、形态加仓

在8月10日的复盘笔记里,我写下了一句看起来特别朴素的话:“怕就减,再往上带好移动止盈,等形态做加仓(指数/熟悉个股)。”如果只看字面,它不像什么高深策略,但它几乎把我过去几年大部…

作者头像 李华
网站建设 2026/9/6 2:02:29

数据库起不来?用PRM-DUL从Oracle数据文件中手工恢复数据

简介:PRM-DUL(Oracle数据库恢复工具)v4.1是一份面向数据库运维与灾难恢复场景的企业级工具包,专为Oracle 9i/10g/11g/12c各版本的数据救援而设计,可在AIX、HPUX、SOLARIS、Linux、Windows等主流平台上运行,…

作者头像 李华
网站建设 2026/9/5 9:53:19

3步导出微信聊天记录:WeChatMsg使用指南

3步导出微信聊天记录:WeChatMsg使用指南 【免费下载链接】WeChatMsg 提取微信聊天记录,将其导出成HTML、Word、CSV文档永久保存,对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/WeChatMsg 上个…

作者头像 李华
网站建设 2026/9/4 7:45:46

C#上位机用S7net与西门子PLC通信的实战指南

简介:面向C#开发人员与工业自动化工程师,这套西门子PLC S7通信资料围绕S7-200、S7-300、S7-1200、S7-1500系列,讲解如何借助C#与S7net库实现PLC数据交互、远程监控与数据采集。资源共249个文件,压缩包仅3.66MB,内容以C…

作者头像 李华