当前位置: 首页 > news >正文

用STM32F103的PWM和定时器,让无源蜂鸣器唱出《两只老虎》

用STM32F103的PWM和定时器实现《两只老虎》音乐盒

记得第一次听到电子设备播放音乐时,那种神奇的感觉至今难忘。作为一个嵌入式开发者,用单片机播放音乐不仅是技术实践,更是一种情怀。本文将带你用STM32F103的PWM和定时器,让无源蜂鸣器唱出经典的《两只老虎》,从乐理到代码实现完整解析。

1. 硬件基础与原理

1.1 无源蜂鸣器的工作原理

无源蜂鸣器与有源蜂鸣器的核心区别在于内部是否集成振荡电路:

特性无源蜂鸣器有源蜂鸣器
驱动方式需要外部PWM信号直流电压即可
音调控制可调频率,能演奏音乐固定频率
价格相对便宜稍贵
应用场景音乐播放、报警音简单提示音

无源蜂鸣器本质上是一个电磁线圈+振动膜结构,当输入方波信号时,线圈会产生交变磁场,带动振动膜周期性振动发声。振动频率与输入方波频率一致,这就是我们能用它演奏音乐的基础。

1.2 STM32的PWM生成机制

STM32的定时器模块非常灵活,以TIM4为例,PWM生成涉及几个关键参数:

  1. 时钟源:通常使用内部72MHz时钟
  2. 预分频器(Prescaler):降低定时器时钟频率
  3. 自动重装载值(ARR):决定PWM周期
  4. 比较寄存器(CCR):决定PWM占空比

PWM频率计算公式:

PWM频率 = 定时器时钟 / ((Prescaler + 1) * (ARR + 1))

在代码中,我们使用HAL库配置TIM4的CH2通道输出PWM:

htim4.Instance = TIM4; htim4.Init.Prescaler = 9-1; // 72MHz / 9 = 8MHz htim4.Init.CounterMode = TIM_COUNTERMODE_UP; htim4.Init.Period = 65535-1; // ARR值 htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&htim4);

2. 从乐谱到代码的转换

2.1 音乐频率的数学基础

《两只老虎》主要使用C大调音阶,各音符对应频率如下:

音符频率(Hz)简谱表示
C4261.631
D4293.662
E4329.633
F4349.234
G4392.005
A4440.006

在代码中,我们定义频率数组:

uint16_t C_FREQ[] = {0,262,294,330,349,392,440,494,523}; // 0为休止符,1-8对应简谱1-7和高音1

2.2 歌曲编码实现

《两只老虎》的简谱转换为两个数组:

  • 音符序列:记录每个音符的音高
  • 节拍序列:记录每个音符的持续时间
/* 频率序列 */ uint8_t music_two_tiger_f[] = { 1,2,3,1, 1,2,3,1, 3,4,5, 3,4,5, 5,6,5,4,3,1, 5,6,5,4,3,1, 1,5,1, 1,5,1 }; /* 节拍序列 */ uint8_t music_two_tiger_t[] = { P_1,P_1,P_1,P_1, P_1,P_1,P_1,P_1, P_1,P_1,P_2, P_1,P_1,P_2, P_4_3,P_4_1,P_4_3,P_4_1,P_1,P_1, P_4_3,P_4_1,P_4_3,P_4_1,P_1,P_1, P_1,P_1,P_2, P_1,P_1,P_2 };

其中节拍定义:

#define P_1 1 // 1拍 #define P_2 2 // 2拍 #define P_4_1 1 // 1/4拍 #define P_4_3 3 // 3/4拍

3. 系统设计与实现

3.1 硬件连接

使用STM32F103C8T6最小系统板,连接方式:

  • PB7 → 蜂鸣器正极
  • 蜂鸣器负极 → GND
  • 建议串联一个100Ω限流电阻

注意:无源蜂鸣器有正负极之分,接反会导致音量减小

3.2 软件架构

系统采用双定时器协同工作:

  • TIM4:产生PWM波控制音高
  • TIM2:1ms中断控制节拍

核心代码逻辑:

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim->Instance == TIM2) { // 节拍定时器 static uint32_t tick = 0; if(tick++ >= current_note_duration) { tick = 0; play_next_note(); // 切换到下一个音符 } } } void play_next_note() { current_note = music_two_tiger_f[note_index]; current_note_duration = music_two_tiger_t[note_index] * base_tempo; if(current_note == 0) { // 休止符 __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, 0); } else { uint16_t arr = (8000000 / C_FREQ[current_note]) - 1; __HAL_TIM_SET_AUTORELOAD(&htim4, arr); __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, arr/2); // 50%占空比 } note_index = (note_index + 1) % music_length; }

3.3 定时器配置关键参数

TIM2配置(节拍控制):

htim2.Instance = TIM2; htim2.Init.Prescaler = 7200-1; // 72MHz/7200 = 10kHz htim2.Init.Period = 10-1; // 10kHz/10 = 1kHz (1ms) HAL_TIM_Base_Start_IT(&htim2);

TIM4配置(PWM生成):

htim4.Instance = TIM4; htim4.Init.Prescaler = 9-1; // 72MHz/9 = 8MHz htim4.Init.Period = 65535-1; // 初始ARR HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2);

4. 调音技巧与优化

4.1 音准校准方法

  1. 使用手机调音器APP监测蜂鸣器发出的音高
  2. 微调C_FREQ数组中的频率值
  3. 常见问题:
    • 高音偏高:减小ARR计算时的基准频率
    • 低音偏闷:检查蜂鸣器共振特性

实测优化后的频率表:

uint16_t C_FREQ[] = {0,262,294,330,350,392,440,495,525}; // 调整了4(F4)和7(B4)的音高

4.2 节奏感优化

影响节奏感的三个因素:

  1. 基准节拍时长:music_two_tiger_t_echo值
    • 建议值:120-180ms(对应每分钟100-80拍)
  2. 中断优先级:确保TIM2中断不被阻塞
    HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0);
  3. 音符过渡处理:在切换音符时重置计数器
    __HAL_TIM_SET_COUNTER(&htim4, 0);

4.3 扩展功能实现

多歌曲管理系统

struct MUSIC_T { uint8_t *f; // 频率数组指针 uint8_t *t; // 节拍数组指针 uint16_t len; // 数组长度 uint16_t t_each; // 基准节拍(ms) uint8_t *name; // 歌曲名称 }; struct MUSIC_T music_t; music_t.f = music_two_tiger_f; music_t.t = music_two_tiger_t; music_t.len = sizeof(music_two_tiger_f)/sizeof(uint8_t); music_t.t_each = 150; // 1/4拍=150ms music_t.name = "Two Tigers";

音量控制

void set_volume(uint8_t vol) { // vol: 0-100 uint16_t pulse = (ARR * vol) / 100; __HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, pulse); }

在项目调试过程中,最令人惊喜的时刻莫过于第一次听到蜂鸣器完整奏响《两只老虎》的瞬间。那种将理论知识转化为实际成果的成就感,正是嵌入式开发的魅力所在。建议初学者可以尝试修改乐谱数组,创造属于自己的单片机音乐作品。

http://www.jsqmd.com/news/634694/

相关文章:

  • 奖励稀疏性危机全解析,深度解读RLHF、Inverse RL与可微分奖励建模的协同破局路径
  • 终极指南:如何使用go-cqhttp构建高效QQ机器人应用
  • Kirikiri视觉小说引擎资源处理终极指南:脚本解密与存档破解完全教程
  • ROS Nano工作空间搭建指南
  • Rufus深度解析:从USB启动盘制作到Windows系统部署的全能工具实践指南
  • 【Kubernetes】从零构建:生产级备份恢复体系的实战指南
  • 我试图用机器学习预测股市,结果:一个软件测试工程师的专业反思
  • lvgl-micropython、lv_micropython和lv_binding_micropython到底啥关系?一文读懂澄
  • 漫谈温州水木南山装饰,绿色装修价格多少实力口碑咋样 - 工业推荐榜
  • 2026年客服系统哪家好用?简单易用平台操作便捷大盘点 - 品牌2026
  • Tiny11Builder终极指南:为老旧设备注入新生命,系统性能提升40%的完整解决方案
  • Mac NTFS读写技术方案:Nigate跨平台文件系统管理实战指南
  • Qwen3-VL-2B与InternVL对比:轻量多模态模型选型建议
  • 性价比高的塑料制品厂家分析,广州市泓信制品有限公司靠不靠谱 - mypinpai
  • MedGemma Medical Vision Lab镜像免配置:Docker一键运行+Web界面自动加载MedGemma权重
  • 揭秘File Browser:打造个人云端文件管理系统的终极实战指南
  • 终极NCM解密指南:3分钟解锁网易云音乐加密文件,实现跨平台自由播放
  • 2026年金相镶嵌机哪家好?国产金相镶嵌机品牌测评及耐用性对比 - 品牌推荐大师1
  • LiuJuan Z-Image详细步骤:自定义权重注入全流程(含键名清洗脚本)
  • 告别编译报错!手把手教你用CMake和VS2022在Windows上编译SOEM 1.4.0主站库
  • Solaar:Linux上管理罗技设备的终极解决方案
  • Qwen3.5-4B-Claude-Opus应用场景:前端工程师CSS布局问题结构化分析
  • Google 迎来「DeepSeek 时刻」:TurboQuant算法实现bit无损、×加速、×压缩、零预处理锥
  • 如何绕过Windows驱动签名强制验证:DSEFix的实战解析与风险指南
  • 【独家速递】SITS2026未剪辑演讲实录节选(含3段原始决策日志+人工干预阈值配置表),仅开放72小时
  • Intv_ai_mk11 在VSCode中的高效开发:Codex插件集成与调试技巧
  • 长芯微LD1120完全P2P替代ADS1120,是一款精密、低功耗、兼容 SPI 接口、16 位 ΔΣ ADC
  • stock-sdk-mcp 的实践整理懈
  • 2026年中小企业客服系统,预算低本地服务好价格透明全满足 - 品牌2026
  • WSL2 + VcXsrv