STM32 PWM音乐播放器源码

STM32 PWM音乐播放器源码

一、实现原理

用STM32的PWM功能模拟音频输出,核心是将音频PCM数据转换为PWM占空比,通过低通滤波器驱动扬声器。原理如下:

  1. 音频数据:存储WAV文件的PCM数据(单声道/8位/11.025kHz采样率,简化计算);
  2. PWM生成:用定时器(如TIM2)输出PWM,占空比对应PCM值(0255→0100%占空比);
  3. 低通滤波: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 关键函数说明

  1. 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,可微调)。
  2. 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 音质优化

4.2 功能扩展

五、测试与验证

  1. 硬件连接:PA0接RC滤波(R=1kΩ→C=0.1μF→GND),滤波后接扬声器;
  2. 编译下载:用Keil MDK编译,ST-Link烧录至STM32F103C8T6;
  3. 效果验证:扬声器应输出《小星星》旋律,无严重失真(若音调异常,调整PWM_FREQ与PCM采样率匹配)。

六、总结

用STM32的PWM功能实现音乐播放,核心是PCM数据→PWM占空比映射+定时更新。代码简洁,适合入门级音频项目,可扩展为SD卡音乐播放器、电子琴等。

专注于matlab/simulink,电子电路,编程