STM32入门_PWM_蜂鸣器播放音乐

609 阅读5分钟

0、 前言

PWM技术在开关电源、电机控制等领域具有广泛的应用。STM32集成了多个定时器,可以配置输出PWM,掌握STM32配置PWM的方法,具有重要的应用意义。


1、 PWM基础概念

PWM(Pulse Width Modulation)是一种通过调节脉冲宽度来控制模拟信号的技术。其核心是通过改变占空比(高电平时间与周期的比值)来等效输出不同电压或功率。

  • 频率(Frequency):每秒脉冲周期数,单位为Hz。高频PWM适用于电机控制(如20kHz),低频PWM适用于LED调光(如500Hz)。

  • 占空比(Duty Cycle):高电平时间Ton占整个周期的比例,范围0%~100%。占空比越大,等效输出电压越高。

image.png 下图展示了利用PWM不同占空比等效不同电压,

image.png


2、配置PWM底层代码

步骤1:使能时钟源

使能时钟源为外部晶振,并配置调试接口。 在这里插入图片描述

步骤2:配置时钟树

系统配置最大系统时钟72MHz,各个总线时钟按照最大时钟配置。 在这里插入图片描述

步骤3:配置PWM输出引脚

STM32的高级定时器的框图如下所示[1],高级定时器具有4个通道TIM1_CH1~TIM1_CH4,每个通道都可以独立配置输出不同形式的PWM,具有输出互补PWM的功能,可以用于无刷直流电机控制。本文仅使用TIM1的通道1,输出单路的PWM。STM32高级定时器的框图如下所示, 在这里插入图片描述 选择高级定时器TIM1,时钟选择内部时钟72MHz,配置通道1输出单路PWM, 在这里插入图片描述

步骤4:配置PWM频率、占空比

  • 配置PWM频率的方法:计数器计数模式为向上计数(波形为锯齿波),通过配置计数器的计数器峰值决定PWM的频率,计数器峰值 = 定时器时钟频率/分频系数/PWM频率
  • 配置PWM占空比的方法:计数器计数值小于比较值,PWM输出高,大于比较值,PWM输出高,通过配置比较值决定PWM的占空比,改变比较值可以改变PWM的占空比,,比较值 = 计数器峰值*占空比

芯片一般会有专门的寄存器去存储计数器峰值、比较值,更改寄存器中的值,就可以改变PWM的频率与占空比,对于STM32芯片,计数峰值存放在TIMx_ARR寄存器,,比较值存放在TIMx_CCRx寄存器。

如下图配置TIM1的计数器峰值、比较值在PA8引脚上输出频率为4KHz,占空为50%的PWM, 在这里插入图片描述 步骤5:生成底层配置代码

配置工程名称,选择对应的IDE,自动生成代码。STM32CubuMX使用细节可以参考: STM32入门_GPIO_STM32CubuMX配置点亮LED

在这里插入图片描述


3、蜂鸣器播放音乐

无源蜂鸣器是一种需要外部驱动信号才能发声的电子元件,内部不含振荡电路,必须通过方波、正弦波等周期性电信号驱动。STM32的PWM引脚输出不同频率、占空比的PWM信号可以驱动无源蜂鸣器发出不同的声音,频率决定音调,占空比决定强度。

image.png

步骤1:驱动蜂鸣器发声

生成底层配置代码后,添加开启定时器的代码,即可输出PWM信号驱动蜂鸣器发声,代码如下所示,

  /* USER CODE BEGIN 2 */
  HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1); //开启定时器
  /* USER CODE END 2 */

步骤2:基础音符实现

无源蜂鸣器频率与音符的对应关系如下表所示, 利用定时器 让蜂鸣器输出不同音符的关键点在于更改PWM频率,编写用于更新PWM频率的函数,代码如下,

/**
  * @brief 更新定时器PWM输出频率
  * @param htim:定时器
  * @param channel:PWM输出通道
  * @param pwm_freq:频率,单位Hz
  * @retval None
  */
void Tim_Update_PwmFreq(TIM_HandleTypeDef *htim, uint32_t channel, uint32_t pwm_freq) 
{
    uint32_t new_arr = 0;
    new_arr = 72000000/7200/pwm_freq                  //计数器峰值= 定时器时钟频率/分频系数/PWM频率
    HAL_TIM_PWM_Stop(htim, channel);                  
    __HAL_TIM_SET_AUTORELOAD(htim, new_arr);          
    __HAL_TIM_SET_COMPARE(htim, channel, new_arr/2);  //保持50%占空比
    HAL_TIM_PWM_Start(htim, channel);
}

C调对应的频率数组如下,结合PWM频率更新函数即可演奏基础音阶。

uint16_t Note[21] ={131,147,165,175,196,221,248,
					262,294,330,350,393,441,495,
					525,589,661,700,786,882,990 };

步骤3:根据乐谱生成数组 歌曲的本质就是音调组合+节拍,节拍可以通过延时函数来实现,如四分音符是延时500ms。下面是小星星对应的频率、节拍数组,

// 小星星简谱对应频率(单位:Hz)
uint16_t tone[] = {
    262, 262, 392, 392, 440, 440, 392,   // 前4小节
    349, 349, 330, 330, 294, 294, 262,   // 后4小节
    392, 392, 349, 349, 330, 330, 294,
    392, 392, 349, 349, 330, 330, 294,
};

// 每个音符持续时间(单位:节拍)
uint16_t beat[] = {
    1,1,1,1,1,1,2,
    1,1,1,1,1,1,2,
    1,1,1,1,1,1,2,
    1,1,1,1,1,1,2,
};

//音乐播放
for(i = 0; i < 28; i++) 
{
	Tim_Update_PwmFreq(&htim1,TIM_CHANNEL_1,tone[i]); 
	HAL_Delay(beat[i]*500); 

  	HAL_TIM_PWM_Stop(&htim1,TIM_CHANNEL_1);  //音符间隔
	HAL_Delay(50); 
}

4、测试

实际测试效果视频如下,

B站视频链接


5、参考

[1].RM0008 STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx and STM32F107xx advanced Arm-based 32-bit MCUs (version 20)