参考资料:
1、正点原子探索者STM32f407开发板-《STM32f407开发指南-库函数版本》-第14章;
2、STM32F4xx 官方参考资料《STM32F4xx中文参考手册》-第15.4章-TIM2到TIM5寄存器。
目录
PWM工作原理
设置输出电平占空比的原理
关于有效电平≠高低电平
总结:
PWM输出配置步骤
⑤关于TIM_OCxInit();——初始化输出比较参数函数——输出极性的含义
⑦关于自动装载的预装载寄存器
⑨关于占空比改变函数TIM_SetComparex();
总示例
写初始化pwm函数
在main函数中使用
1、CNT和CCR1比较,比较结果有“>”或者“≤”两种;
2、将结果送给TIMx_CCR1的OC1M位决定,结果有有效电平或者无效电平两种,就是那个oc1ref;
3、将结果送给TIMx_CCR1的CC1P位决定,CC1P位分别决定有效电平和无效电平是高电平还是低电平;
4、输出使能电路(TIMx_CCR1的CC1E位使能),即输出高低电平。
上图CCR1:OC1M位,可以看到有PWM 模式 1 和PWM 模式 2 ,在递增计数模式下,只要 TIMx_CNT 用人话说就是:在PWM 模式 1下,向上计数时,小于自己设置的值就是有效电平;向下计数则相反,大于自己设置的值就是有效电平。ARR就是计到的最大数值(自动装载值),TIMx_CNT就是实时变化的计数器的值,TIMx_CCR1就是设定的阈值。控制输出占空比就是控制这个阈值与ARR的比例。 那么有效电平是高电平还是低电平呢?这还是得靠自己设定,由CCER:CC1P位决定: 然后由CCER:CC1E位决定输入/捕获1输出使能: ① 使能定时器x和相关IO口时钟: 使能定时器x时钟:RCC_APB1PeriphClockCmd(); 使能GPIOF时钟:RCC_AHB1PeriphClockCmd(); ② 初始化IO口为复用功能输出。函数:GPIO_Init(); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能 ③ GPIOFX复用映射到定时器x: GPIO_PinAFConfig(GPIOF,GPIO_PinSourceX,GPIO_AF_TIMx); ④ 初始化定时器:ARR、PSC等:TIM_TimeBaseInit(); ⑤ 初始化输出比较参数:TIM_OCxInit(); ⑥ 使能预装载寄存器: TIM_OCxPreloadConfig(TIMx, TIM_OCPreload_Enable); ⑦ 使能自动重装载的预装载寄存器允许位:TIM_ARRPreloadConfig(TIMx,ENABLE); ⑧ 使能定时器:TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState); ⑨ 改变比较值CCRx,达到不同的占空比效果:TIM_SetComparex(); 注:第⑨步可在主函数中设置。 其中“x”是对应的通道,如TIM2_CH3就是定时器2,通道(channel)3。 使用示例: 输出极性高低意思就是说有效电平是高电平还是低电平 作用就是更新ARR的值 简单的说,ARPE=0,ARR立即生效;APRE=1,ARR下个比较周期生效。 应用示例: 比如我设定的是TIM2_CH3,因为是通道3,所以用TIM_SetCompare3,通道几就用compare几。 而一百表示计数器一直在与100比较。 Fin.关于有效电平≠高低电平
总结:
PWM输出配置步骤
⑤关于TIM_OCxInit();——初始化输出比较参数函数——输出极性的含义
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); //根据指定的参数初始化外设TIM3 OC2
⑦关于自动装载的预装载寄存器
void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
⑨关于占空比改变函数TIM_SetComparex();
TIM_SetCompare3(TIM2 ,100);
总示例
写初始化pwm函数
#include "pwm.h"
#include "led.h"
#include "usart.h"
//TIM2 PWM部分初始化
//PWM输出初始化
//arr:自动重装值
//psc:时钟预分频数
void TIM2_PWM_Init(u32 arr,u32 psc)
{
//此部分需手动修改IO口设置
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //TIM14时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); //使能PORTB时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //GPIOB10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOB,&GPIO_InitStructure); //初始化PB10
GPIO_PinAFConfig(GPIOB,GPIO_PinSource10,GPIO_AF_TIM2); //GPIOB10复用为定时器2
TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);//初始化定时器2
//初始化TIM2 Channel3 PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性低(有效电平为0)
TIM_OC1Init(TIM2, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM2 OC1
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); //使能TIM2在CCR1上的预装载寄存器
TIM_ARRPreloadConfig(TIM2,ENABLE);//ARPE使能
TIM_Cmd(TIM2, ENABLE); //使能TIM2
}
在main函数中使用
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "pwm.h"
int main(void)
{
u16 led0pwmval=0;
u8 dir=1;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
delay_init(168); //初始化延时函数
uart_init(115200);//初始化串口波特率为115200
TIM2_PWM_Init(500-1,84-1); //84M/84=1Mhz的计数频率,重装载值500,所以PWM频率为 1M/500=2Khz.
while(1) //实现比较值从0-300递增,到300后从300-0递减,循环
{
delay_ms(10);
if(dir)led0pwmval++;//dir==1 led0pwmval递增
else led0pwmval--; //dir==0 led0pwmval递减
if(led0pwmval>300)dir=0;//led0pwmval到达300后,方向为递减
if(led0pwmval==0)dir=1; //led0pwmval递减到0后,方向改为递增
TIM_SetCompare3(TIM2,led0pwmval); //修改比较值,修改占空比
}
}