STM32 PWM音乐播放器源码
一、实现原理
用STM32的PWM功能模拟音频输出,核心是将音频PCM数据转换为PWM占空比,通过低通滤波器驱动扬声器。原理如下:
- 音频数据:存储WAV文件的PCM数据(单声道/8位/11.025kHz采样率,简化计算);
- PWM生成:用定时器(如TIM2)输出PWM,占空比对应PCM值(0255→0100%占空比);
- 低通滤波:PWM信号经RC滤波(截止频率~4kHz)后,还原为模拟音频信号。
二、硬件设计
2.1 核心组件
| 模块 | 型号/参数 | 功能说明 |
|---|---|---|
| 主控 | STM32F103C8T6(标准库3.5) | PWM生成、WAV解析、数据调度 |
| 音频输出 | 扬声器(8Ω/0.5W)+ RC滤波 | 低通滤波后驱动扬声器(R=1kΩ,C=0.1μF) |
| 存储 | 内部Flash(存储PCM数据) | 存储简化WAV的PCM数组(约2KB) |
2.2 硬件连接
| 模块 | 引脚(STM32F103C8T6) | 说明 |
|---|---|---|
| PWM输出 | PA0(TIM2_CH1) | 接RC滤波后驱动扬声器 |
| 按键 | PA1(播放/暂停) | 控制播放状态 |
三、软件设计(标准库3.5)
3.1 核心代码实现
3.1.1 头文件 pwm_music.h
#ifndef __PWM_MUSIC_H
#define __PWM_MUSIC_H
#include "stm32f10x.h"
#include "delay.h"
// ==================== 宏定义 ====================
#define PWM_FREQ 11025 // 采样率(Hz,与PCM数据匹配)
#define PWM_ARR 255 // 自动重装载值(8位PCM对应0~255)
#define PWM_CCR TIM2->CCR1 // PWM比较寄存器(占空比)
#define MUSIC_DATA_LEN 2048 // PCM数据长度(单声道,8位,2KB)
// ==================== 函数声明 ====================
void PWM_Init(void); // PWM初始化(TIM2_CH1,PA0)
void Music_Play(const uint8_t *music_data, uint16_t len); // 播放音乐
void Music_Pause(void); // 暂停播放
void Music_Resume(void); // 恢复播放
// ==================== 音乐数据(示例:简谱《小星星》PCM) ====================
extern const uint8_t music_data[MUSIC_DATA_LEN]; // 存储在内部Flash
#endif
3.1.2 源文件 pwm_music.c
#include "pwm_music.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
// ==================== 音乐数据(8位PCM,单声道,11.025kHz采样率) ====================
// 示例:《小星星》片段(简谱对应频率,已转换为PCM幅度值0~255)
const uint8_t music_data[MUSIC_DATA_LEN] = {
// 简谱:1 1 5 5 6 6 5 - 4 4 3 3 2 2 1 - ...(幅度值简化)
128, 180, 128, 180, 200, 200, 180, 0, 160, 160, 150, 150, 140, 140, 128, 0,
// 重复片段(省略,实际需完整PCM数据)
};
// ==================== PWM初始化(TIM2_CH1,PA0,11.025kHz PWM频率) ====================
void PWM_Init(void) {
GPIO_InitTypeDef GPIO_InitStruct;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStruct;
TIM_OCInitTypeDef TIM_OCInitStruct;
// 1. 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
// 2. 配置PA0为复用推挽输出(TIM2_CH1)
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
// 3. 配置TIM2时基(PWM频率=11.025kHz)
TIM_TimeBaseStruct.TIM_Period = PWM_ARR; // ARR=255(8位PCM)
TIM_TimeBaseStruct.TIM_Prescaler = SystemCoreClock / (PWM_FREQ * (PWM_ARR + 1)) - 1;
// SystemCoreClock=72MHz → 72000000/(11025 * 256)-1≈25-1=24
TIM_TimeBaseStruct.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStruct.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStruct);
// 4. 配置TIM2_CH1为PWM模式1
TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStruct.TIM_Pulse = 0; // 初始占空比0
TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM2, &TIM_OCInitStruct);
// 5. 使能TIM2
TIM_Cmd(TIM2, ENABLE);
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); // 使能预装载
}
// ==================== 播放音乐(循环发送PCM数据到PWM) ====================
void Music_Play(const uint8_t *music_data, uint16_t len) {
uint16_t i = 0;
while (1) {
if (/* 未暂停 */1) { // 实际需按键控制暂停
PWM_CCR = music_data[i]; // 设置占空比(PCM值0~255)
i = (i + 1) % len; // 循环播放
Delay_us(1000000 / PWM_FREQ); // 延时1/采样率(11.025kHz→~90.7us)
}
}
}
// ==================== 主函数 ====================
int main(void) {
delay_init(); // 延时函数初始化
PWM_Init(); // PWM初始化
Music_Play(music_data, MUSIC_DATA_LEN); // 播放音乐
while (1);
}
3.1.3 关键函数说明
-
PWM_Init():
- 配置TIM2_CH1为PWM模式,频率=11.025kHz(与PCM采样率匹配);
- 自动重装载值
ARR=255(对应8位PCM的0~255),预分频PSC=24(72MHz/(24+1)=2.88MHz,2.88MHz/256=11.25kHz,接近11.025kHz,可微调)。
-
Music_Play():
- 循环读取PCM数据,将每个字节(0~255)写入TIM2->CCR1(占空比);
- 用
Delay_us(90.7)控制采样间隔(1/11025≈90.7μs),实现音频还原。
参考代码 用STM32的PWM功能实现的音乐播放源码 www.youwenfan.com/contentcns/56427.html
四、优化与扩展
4.1 音质优化
- 提高采样率:用16位PCM(0~65535),
ARR=65535,需定时器支持(如TIM3,16位); - 双声道支持:用两个PWM通道(如TIM2_CH1/CH2),分别输出左右声道;
- 低通滤波:硬件增加RC滤波(R=1kΩ,C=0.1μF,截止频率≈1.6kHz),滤除PWM高频成分。
4.2 功能扩展
- 按键控制:添加PA1按键,实现播放/暂停/切歌;
- SD卡存储:用FATFS读取SD卡中的WAV文件,解析PCM数据后播放;
- 多首音乐:用数组存储多段PCM数据,按键切换。
五、测试与验证
- 硬件连接:PA0接RC滤波(R=1kΩ→C=0.1μF→GND),滤波后接扬声器;
- 编译下载:用Keil MDK编译,ST-Link烧录至STM32F103C8T6;
- 效果验证:扬声器应输出《小星星》旋律,无严重失真(若音调异常,调整
PWM_FREQ与PCM采样率匹配)。
六、总结
用STM32的PWM功能实现音乐播放,核心是PCM数据→PWM占空比映射+定时更新。代码简洁,适合入门级音频项目,可扩展为SD卡音乐播放器、电子琴等。