一、 PWM 概述
- 定义
PWM(Pulse Width Modulation), 脉冲宽度调制。
脉冲: 方波, 频率(freq)
宽度: 高电平的宽度, 占空比(duty)
详细波形如下图。
-
用途
控制灯光的亮度(手机/平板/显示器背光灯)
电机的转速
...
-
灯光的控制细节
频率要大于 25Hz, 灯光的亮度的变化是跟着占空比而变化, 占空比越大, 灯光越暗; 占空比越小, 灯光越亮。
-
STM32工作过程
CCR1:捕获比较(值)寄存器(x=1,2,3,4):设置比较值。
CCMR1: OC1M[2:0]位:
对于PWM方式下,用于设置PWM模式1【110】或者PWM模式2【111】
CCER:CC1P位:输入/捕获1输出极性。0:高电平有效,1:低电平有效。
CCER:CC1E位:输入/捕获1输出使能。0:关闭,1:打开。
PWM模式1 & PWM模式2
寄存器TIMx_CCMR1的OC1M[2:0]位来分析:
c
void TIM_OCxPreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
自动重载的预装载寄存器
c
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
简单的说,ARPE=1,ARR立即生效。。。APRE=0,ARR下个比较周期生效。
STM32 定时器14输出通道引脚
PWM输出库函数
c
void TIM_OCxInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
typedef struct
{
uint16_t TIM_OCMode; //PWM模式1或者模式2
uint16_t TIM_OutputState; //输出使能 OR失能
uint16_t TIM_OutputNState;
uint16_t TIM_Pulse; //比较值,写CCRx
uint16_t TIM_OCPolarity; //比较输出极性
uint16_t TIM_OCNPolarity;
uint16_t TIM_OCIdleState;
uint16_t TIM_OCNIdleState;
} TIM_OCInitTypeDef;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //PWM模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure. TIM_Pulse=100;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC2
设置比较函数:
void TIM_SetCompareX(TIM_TypeDef* TIMx, uint16_t Comparex);
使能输出比较预装载:
void TIM_OCxPreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);
u使能自动重装载的预装载寄存器允许位:
c
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
PWM输出配置步骤:
①使能定时器14和相关IO口时钟.
使能定时器14时钟:RCC_APB1PeriphClockCmd();
使能GPIOF时钟:RCC_AHB1PeriphClockCmd ();
② 初始化IO口为复用功能输出。函数:GPIO_Init();
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能
③ GPIOF9复用映射到定时器14
GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);
④ 初始化定时器:ARR,PSC等:TIM_TimeBaseInit();
⑤ 初始化输出比较参数:TIM_OC1Init();
⑥ 使能预装载寄存器:TIM_OC1PreloadConfig(TIM14, **TIM_OCPreload_Enable);
⑦使能自动重装载的预装载寄存器允许位TIM_ARRPreloadConfig(TIM14,ENABLE);
⑧使能定时器.
⑨不断改变比较值CCRx,达到不同的占空比效果:TIM_SetCompare1();
二. 程序设计
- 原理图
不同的定时器, 输出通道的数目都有所不一样。 在高级定时器输出多路的 PWM,
比可以是不一样的, 能够由 TIM_SetComparex[1-3]来进行设置不同的通道占空比!
-
配置频率
c/* TIM14 clock enable , 定时器 14 时钟使能*/ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE); /* Time base configuration , 定时器基本配置, TIM_Period 是计数值*/ TIM_TimeBaseStructure.TIM_Period = (10000/100)-1; //输出频率为 100Hz,(10000/100) -1 得到的结果就是计数值。 TIM_TimeBaseStructure.TIM_Prescaler = 8400-1; //预分频值 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频, 也称之为二次分频,当前是 1 分频, 说白了不分频, 不降低频率 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数的方法 TIM_TimeBaseInit(TIM14, &TIM_TimeBaseStructure); //初始化
-
配置PWM输出功能
c
/* PWM1 Mode configuration: Channel1 , 让 PWM 的通道 1 工作在模式 1*/
//PWM 模式 1, 在递增模式下, 只要 TIMx_CNT < TIMx_CCR1, 通道 1 便为有效状态(高电平), 否则为无效状态(低电平)。
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //允许输出
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //有效的时候, 输出高电平
TIM_OC1Init(TIM14, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable); //自动重载初值, 不断输出 PWM 脉冲
TIM_ARRPreloadConfig(TIM14, ENABLE); //自动重载初值使能
/* TIM14 enable counter, 使能定时器 14 工作 */
TIM_Cmd(TIM14, ENABLE);
demo:
c
#include "beep.h"
#include "sys.h"
#include "delay.h"
// LED pwm定时器设置
void init_TIM14()
{
// 定义GPIO外设
GPIO_InitTypeDef GPIO_InitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
// 使能定时器14系统时钟源
// APB1 :42M
// TIM3 : 42*2 = 84M == 1s
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14, ENABLE);
// 配置定时时间 10ms
TIM_TimeBaseStructure.TIM_Period = 100-1; // 重装载寄存器
TIM_TimeBaseStructure.TIM_Prescaler = 8400-1; // 分频系数
TIM_TimeBaseStructure.TIM_ClockDivision = 0; // 时钟二次分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM14, &TIM_TimeBaseStructure);
/* PWM1 Mode configuration: Channel1 */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; // pwm1模式,CNT < CCR,输出有效电平
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; // 输出使能
TIM_OCInitStructure.TIM_Pulse = 0; // CCR初始值,通过改变CCR设置占空比
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; // 有效电平为高电平
TIM_OC1Init(TIM14, &TIM_OCInitStructure);
// 自动重装载器使能
TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);
/* TIM14 enable counter */
TIM_Cmd(TIM14, ENABLE);
// 初始化LED PF9
// 使能F组管脚工作
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // 复用模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 推挽模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; // 无拉电阻
GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed;
// 初始化GPIO
GPIO_Init(GPIOF, &GPIO_InitStructure);
// 将PF9和定时器进行绑定
GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);
}
int main()
{
uint32_t pwm_cmp;
init_TIM14();
while(1)
{
// 设置占空比,pwm_cmp小于ARR(重装载寄存器)值
for(pwm_cmp = 0; pwm_cmp < 100; pwm_cmp++)
{
TIM_SetCompare1(TIM14, pwm_cmp);
delay_ms(20);
}
for(pwm_cmp = 100; pwm_cmp > 0; pwm_cmp--)
{
TIM_SetCompare1(TIM14, pwm_cmp);
delay_ms(20);
}
}
}