脉冲宽度调制(Pulse width modulation,即PWM)是一种模拟控制方式,根据相应载荷的变化来调制晶体管基极或MOS管栅极的偏置,来实现晶体管或MOS管导通时间的改变,从而实现开关稳压电源输出的改变。这种方式能使电源的输出电压在工作条件变化时保持恒定,是利用微处理器的数字信号对模拟电路进行控制的一种非常有效的技术。广泛应用在从测量、通信到功率控制与变换的许多领域中。
实验要求为利用定时器输出的PWM脉冲,控制LED0进行类似手机呼吸灯的闪烁。
首先我们要确定PWM脉冲的周期由以下公式确定Tout=(ARR+1)*(PSC+1)/Ft(单位为us,我们最好转化为ms),即我们之前的定时器的周期公式。Ft为我们定时器的时钟信号来源APB1的72MHz,PSC为预分频系数,ARR为我们的自动装载系数。后两个参数是需要我们自己编写的。举个例子,比如我们需要输出一个2kHz的PWM方波,则我们的ARR设置为499,PSC设置为71,最后计算所得的周期时间为500us,转化为频率便是2kHz。
接下来我们设置输出比较模式,设置为PWM模式1、通道输出极性为低电平有效。对于LED0的PB5串口,我们可以看到对应的定时器通道为TIM3的通道2。
然后我们在检查TIM3通道2的重映射功能,我们需要操作相应的TIM3_REMAP的两位寄存器,将之设置为10的部分映射。
接下来我们编写实验代码。
首先是我们的函数头文件gtim.h:
#ifndef __GTIM_H
#define __GTIM_H
#include "./SYSTEM/sys/sys.h"
extern TIM_HandleTypeDef g_timx_pwm_chy_handle;
void gtim_timx_pwm_chy_init(uint16_t arr, uint16_t psc);
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim);
#endif
接下来是函数文件gtim.c:
#include "./BSP/GTIM/gtim.h"
#include "./BSP/LED/led.h"
TIM_HandleTypeDef g_timx_pwm_chy_handle;
void gtim_timx_pwm_chy_init(uint16_t arr, uint16_t psc){
TIM_OC_InitTypeDef timx_oc_pwm_chy;
g_timx_pwm_chy_handle.Instance = TIM3;
g_timx_pwm_chy_handel.Init.Prescaler = psc;
g_timx_pwm_chy_handle.Init.Period = arr;
g_timx_pwm_chy_handle.Init.CounterMode = TIM_COUNTERMODE_UP;//向上计数模式
HAL_TIM_PWM_Init(&g_timx_pwm_chy_handle);
timx_oc_pwm_chy.OCMode = TIM_OCMODE_PWM1;//选择PWM1模式
timx_oc_pwm_chy.Pulse = arr / 2;//设置占空比的比较值
timx_oc_pwm_chy.OCPolarity = TIM_OCPOLARITY_LOW;//输出极性:低极性
HAL_TIM_PWM_ConfigChannel(&g_timx_pwm_chy_handle, &timx_oc_pwm_chy, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&g_timx_pwm_chy_handle, TIM_CHANNEL_2);
}
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim){
if(htim->Instance == TIM3){
GPIO_InitTypeDef gpio_init_struct;
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_TIM3_CLK_ENABLE();
gpio_init_struct.Pin = GPIO_PIN_5;
gpio_init_struct.Mode = GPIO_MODE_AF_PP;
gpio_init_struct.Pull = GPIO_PULLUP;
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &gpio_init_struct);
__HAL_RCC_AFIO_CLK_ENABLE();
__HAL_AFIO_REMAP_TIM3_PARTIAL();
}
}
最后编写我们的主函数main.c:
#include "./SYSTEM/delay/delay.h"
#include "./SYSTEM/usart/usart.h"
#include "./BSP/LED/led.h"
#include "./BSP/GTIM/gtim.h"
int main(void){
uint16_t ledrpwmval = 0;//设置比较值
uint8_t dir = 1;//控制比较值增减方向
HAL_Init();
sys_stm32_clock_init(RCC_PLL_MUL9);
delay_init(72);
led_init();
gtim_timx_pwm_chy_init(500 - 1, 72 - 1);
while(1){
delay_ms(10);
if (dir)ledrpwmval++;
else ledrpwmval--;
if (ledrpwmval > 300)dir = 0;
if (ledrpwmval == 0)dir = 1;
__HAL_TIM_SET_COMPARE(&g_timx_pwm_chy_handle, TIM_CHANNEL_2, ledpwmval);
}
}
最后PWM的波形如下:
最后就完成了我们的实验。