这两天在学习STM32 TIM定时器输出比较模式,按照网上的教程也能实现PWM波的输出,占空比和频率都符合预期。但是当波形时间拉长以后,就会出现ARR周期的高电平或者低电平,定位了好久。
现象:
出现问题的原因很简单:比较寄存器超出ARR设定的值了;
htim3.Instance = TIM3;
htim3.Init.Prescaler = 107;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 60000;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
此时ARR设定的值是6000
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
uint32_t OC_Count = 0;
OC_Count = __HAL_TIM_GET_COUNTER(htim); /* 读取定时器的当前计数值,就是读取TIM1_CNT寄存器的值 */
if(htim->Instance == TIM3){ /* 判断是否是定时器1 */
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1){
// unsigned short i = OC_Count + OC_Channel1_Pulse - OC_Channel1_Duty * OC_Channel1_Pulse/100;
// if(i>= 60000)
// i = 0;
// unsigned short j = OC_Count + OC_Channel1_Duty * OC_Channel1_Pulse/100;
// if(j>= 60000)
// j = 0;
/* 判断是否是通道1 */
if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6)){ /* 判断此时的电平是否为低电平 */
//__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,i);/* 设置比较寄存器CCR的值--0.3ms的低电平 */
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,OC_Count + OC_Channel1_Pulse - OC_Channel1_Duty * OC_Channel1_Pulse/100);/* 设置比较寄存器CCR的值--0.3ms的低电平 */
}else{
//__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,j);/* 设置比较寄存器CCR的值--0.7ms的高电平 */
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,OC_Count + OC_Channel1_Duty * OC_Channel1_Pulse/100);/* 设置比较寄存器CCR的值--0.7ms的高电平 */
}
}else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2){ /* 判断是否是通道2 */
if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7)){
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,OC_Count + OC_Channel2_Pulse - OC_Channel2_Duty * OC_Channel2_Pulse/100);
}else{
__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_2,OC_Count + OC_Channel2_Duty * OC_Channel2_Pulse/100);
}
}
}
}
图中红框CCR的值超过ARR的值了,目前用注释掉的代码测试,现象是没了,但是长时间运行会不会有问题不确定。
更新:
uint32_t OC_Channel1_Pulse = 100; /* TIM1通道1的脉冲宽度 */
uint32_t OC_Channel1_Duty = 70; /* TIM1通道1的占空比 */
uint32_t OC_Channel2_Pulse = 200; /* TIM1通道2的脉冲宽度 */
uint32_t OC_Channel2_Duty = 20; /* TIM1通道2的占空比 */
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
uint32_t OC_Count = 0;
OC_Count = __HAL_TIM_GET_COUNTER(htim); /* 读取定时器的当前计数值,就是读取TIM1_CNT寄存器的值 */
//printf("Count= %d \r\n",OC_Count);
if (htim->Instance == TIM1)
{ /* 判断是否是定时器1 */
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{ /* 判断是否是通道1 */
if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_9))
{ /* 判断此时的电平是否为低电平 */
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, OC_Count + OC_Channel1_Pulse - OC_Channel1_Duty * OC_Channel1_Pulse / 100); /* 设置比较寄存器CCR的值--0.3ms的低电平 */
}
else
{
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, OC_Count + OC_Channel1_Duty * OC_Channel1_Pulse / 100); /* 设置比较寄存器CCR的值--0.7ms的高电平 */
}
if(htim->Instance->CCR1 >= htim->Init.Period)htim->Instance->CCR1=0;
}
else if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{ /* 判断是否是通道2 */
if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_11))
{
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, OC_Count + OC_Channel2_Pulse - OC_Channel2_Duty * OC_Channel2_Pulse / 100);
}
else
{
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_2, OC_Count + OC_Channel2_Duty * OC_Channel2_Pulse / 100);
}
if(htim->Instance->CCR2 >= htim->Init.Period)htim->Instance->CCR2=0;
}
}
}
添加红框里面的代码,做一个判断,目前没出什么问题。
注:不要再回调(中断)里面打印数据,这样出来的波形不准确!!!切记!!!
参考:
https://blog.csdn.net/phker/article/details/80752691