因为之前学习STM32系列芯片的时候编程用的是寄存器的方式,现在开始学习使用库函数版本来完成相应的功能,在我用开发板学习完定时器3(TIM3)中断控制led后就想用定时器(TIM4)产生PWM波来控制LED。我按照TIM3产生PWM波的方式完成初始化工作:
//arr自动重装载值
//psc预分频系数
void TIM3_PWM_Init(u32 arr,u32 psc)
{
//此部分需手动修改IO口设置
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); //TIM3时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能PORTA时钟
GPIO_PinAFConfig(GPIOA,GPIO_PinSource6,GPIO_AF_TIM3); //GPIOA6复用为定时器3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; //GPIOFA
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(GPIOA,&GPIO_InitStructure); //初始化PA6
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(TIM3,&TIM_TimeBaseStructure);//初始化定时器3
//初始化TIM14 Channel1 PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性低
TIM_OC1Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM1 4OC1
TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); //使能TIM3在CCR1上的预装载寄存器
TIM_ARRPreloadConfig(TIM3,ENABLE);//ARPE使能
TIM_Cmd(TIM3, ENABLE); //使能TIM3
}
完成之后按照TIM3的方式完成主函数的编程,一运行之后发现LED没反应,检查之后发现硬件没问题,我就把初始化代码中TIM4替换掉,变成上面的那段代码,一运行发现可以,这个时候我就猜想应该是两者之间有什么不同导致,然后再网上查找相关资料发现的却是不同,两者产生PWM波的方式不一样:
其他定时器使用:TIM_SetCompare1(TIM14,625);来设置产生PWM
但是这个办法对TIM4行不通。
TIM4使用
TIM_OCInitStructure.TIM_Pulse = dutyCycle;
于是我参考网上关于TIM4的初始化代码完成相应的操作运行之后发现可以正常运行
pwm.c代码:
void TIM4_PWM_Init(u32 arr,u32 psc,u32 date)
{
//此部分需手动修改IO口设置
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); //TIM3时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); //使能PORTA时钟
GPIO_PinAFConfig(GPIOD,GPIO_PinSource15,GPIO_AF_TIM4); //GPIOA6复用为定时器3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; //GPIOFA
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(GPIOD,&GPIO_InitStructure); //初始化PA6
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(TIM4,&TIM_TimeBaseStructure);//初始化定时器3
//初始化TIM14 Channel1 PWM模式
TIM_OCInitStructure.TIM_Pulse=date;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性低
TIM_OC4Init(TIM4, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM1 4OC1
TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable); //使能TIM3在CCR1上的预装载寄存器
TIM_ARRPreloadConfig(TIM4,ENABLE);//ARPE使能
TIM_Cmd(TIM4, ENABLE); //使能TIM3
}
main.c代码:
int main()
{
u16 led0pwmval=0;
u8 dir=1;
delay_init(168);
led_init();
while(1)
{
delay_ms(10);
if(dir)led0pwmval++;//dir==1 led0pwmval递增
else led0pwmval--; //dir==0 led0pwmval递减
if(led0pwmval>400)dir=0;//led0pwmval到达300后,方向为递减
if(led0pwmval==0)dir=1; //led0pwmval递减到0后,方向改为递增
TIM4_PWM_Init(500,840,led0pwmval);//定时器4
}
}
写这个笔记是想让自己以后记得。
接触到HAL库的时候发现HAL库里面也存在这种现象,不过其它定时器也可以使用TIM4的方法改变输出的PWM占空比,
HAL库其它定时器改变占空比的函数:__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, pwm_value);
TIM4需要自定义函数来实现改变Pulse从而改变占空比:
void user_pwm_setvalue(uint16_t pwm_value)
{
TIM_OC_InitTypeDef sConfigOC;
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = pwm_value;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);//这个函数在main函数的begin2-end2之间还要再调用一次
}