一、PWM是什么?
脉冲宽度调制(PWM),利用微处理器的数字输出来对模拟电路进行控制。
1.PWM工作过程
上一节说过,向上计数从0到ARR(自动装载值)产生中断。那么如何在计数过程中用到PWM呢?
下图是向上计数,计数器在计数时,捕获比较寄存器(CCRx)和计数器的值相比较,当CCRx > 计数器的值就为低电平,CCRx < 计数器的值就为高电平(根据CCER寄存器来配置是高电平有效还是低电平有效),计数器的值到达ARR的值时,开始重装载,以此来循环。
2.PWM总结
PWM模式(脉冲宽度调制模式)可以生成一个信号,该信号频率是由TIMx_ARR寄存器的值来决定的,其占空比则是由TIMx_CCRx寄存器值决定。
PWM模式1:向上计数时,TIMx_CNT<TIMx_CCR1时,通道1为有效电平,否则为无效电平;在向下计数时,TIMx_CNT>TIMx_CCR1时,通道1为无效电平,否则为有效电平。
PWM模式2:向上计数时,TIMx_CNT<TIMx_CCR1时,通道1为无效电平,否则为有效电平;在向下计数时,TIMx_CNT>TIMx_CCR1时,通道1为有效电平,否则为无效电平。
二、PWM编程流程(HAL库)
1.开启TIM3和GPIO时钟
__HAL_RCC_TIM3_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE(); // 复用的时候用
2.初始化PWM时基参数
HAL_TIM_PWM_Init();
3.初始化PWM通道参数
HAL_TIM_PWM_ConfigChannel();
4.使能定时器PWM
HAL_TIM_PWM_Start();
5.配置IO口复用映射
HAL_GPIO_Init();
三、小实验程序要求
使用定时器PWM功能,输出占空比可变的PWM波,用来驱动LED灯,从而达到LED亮度由暗变亮,又从亮变暗,如此循环。
四、代码实现
tip:1.PB0和PB1为小灯,PB1的话我们需要用复用TIM3_CH4(第4频道);
2.在TIM3_PWM_Init()里占空比是固定的,所以创建TIM3_PWM_SetValue函数改变占空比的值。
1.pwm.h
#ifndef __PWM_H
#define __PWM_H
#include "sys.h"
void TIM3_PWM_Init(void);
void TIM3_PWM_SetValue(TIM_HandleTypeDef *htim, uint32_t value);
extern TIM_HandleTypeDef TIM3_PWM_Struct;
#endif
2.pwm.c
#include "pwm.h"
TIM_HandleTypeDef TIM3_PWM_Struct; // TIM_PWM句柄
TIM_OC_InitTypeDef TIM3_OC_Sturct; // TIM_OC句柄
void TIM3_PWM_Init() // PWM初始化
{
TIM3_PWM_Struct.Instance = TIM3;
TIM3_PWM_Struct.Init.Prescaler = 90 - 1; // 预分频系数
TIM3_PWM_Struct.Init.Period = 500 - 1; // 自动装载值
TIM3_PWM_Struct.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数模式:向上计数
HAL_TIM_PWM_Init(&TIM3_PWM_Struct); // TIM_PWM初始化
TIM3_OC_Sturct.OCMode = TIM_OCMODE_PWM1; // 选择PWM1,还是PWM2
TIM3_OC_Sturct.Pulse = 250; // 占空比:为Period(ARR)一半
TIM3_OC_Sturct.OCPolarity = TIM_OCPOLARITY_LOW; // 因为小灯是低电平有效 选择低电平
HAL_TIM_PWM_ConfigChannel(&TIM3_PWM_Struct, &TIM3_OC_Sturct, TIM_CHANNEL_4); // 初始化PWM通道参数
HAL_TIM_PWM_Start(&TIM3_PWM_Struct, TIM_CHANNEL_4); // 使能定时器PWM
}
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
if (htim->Instance == TIM3)
{
GPIO_InitTypeDef GPIO_Struct; // GPIO句柄
GPIO_Struct.Pin = GPIO_PIN_1; // PB1
GPIO_Struct.Mode = GPIO_MODE_AF_PP; // 推挽输出
GPIO_Struct.Pull = GPIO_PULLUP; // 上拉
GPIO_Struct.Speed = GPIO_SPEED_FAST; // 高速
GPIO_Struct.Alternate = GPIO_AF2_TIM3; // 复用为TIM3
HAL_GPIO_Init(GPIOB, &GPIO_Struct);
__HAL_RCC_TIM3_CLK_ENABLE(); // TIM3时钟使能
__HAL_RCC_GPIOB_CLK_ENABLE(); // GPIOB时钟使能
}
}
void TIM3_PWM_SetValue(TIM_HandleTypeDef *htim, uint32_t value) // 改变PWM占空比的值
{
htim->Instance->CCR4 = value; // 占空比大亮度亮,占空比小亮度暗
}
3.main.c
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "pwm.h"
int main(void)
{
uint8_t direction = 1; // 方向(判断转向)
uint32_t led_pwm_value = 0; // PWM占空比的值
HAL_Init(); // 初始化HAL库
Stm32_Clock_Init(360,25,2,8); // 设置时钟,180Mhz
delay_init(180); // 初始化延时函数
uart_init(115200); // 初始化USART
LED_Init(); // 初始化LED
TIM3_PWM_Init(); // 初始化PWM3
while (1)
{
delay_ms(10);
if (direction) // 判断方向
{
led_pwm_value++;
}
else
{
led_pwm_value--;
}
if (led_pwm_value > 400) // 值最好不要超过Period(ARR)的值
{
direction = 0;
}
if (led_pwm_value == 0)
{
direction = 1;
}
TIM3_PWM_SetValue(&TIM3_PWM_Struct, led_pwm_value);
}
}