最近因为从标准库过渡到hal库,又重新温习了一遍定时器相关的功能,在stm32中定时器经常被用作输出PWM波,在此对定时器常用来输出PWM的两种模式:输出比较模式和PWM模式做一个总结
本次实验使用stm32G431,使用cubemx生成底层代码。
输出比较模式和PWM模式都可以用来输出PWM波,在功能上两者有相同之处,对于一个定时器这两种方式都可以做到四路输出PWM,每一路PWM占空比都可调,也有不同之处,输出比较模式可以方便的调节每一路PWM波的频率,可以输出四路频率不同,占空比不同的PWM。但是PWM模式如果想要调节PWM波的频率,那么就只能重新设置预分频系数或者自动重装载寄存器ARR,并且输出的四路PWM频率必定一致。
PWM模式是输出比较模式的子集。
二、PWM模式 1.原理在预分频系数确定的条件下,PWM模式的信号频率是由自动重装载寄存器ARR来确定的,占空比则由比较寄存器CCR来确定。
PWM模式分为两种,PWM1和PWM2,都可以设置计数器递增计数或者递减计数。具体如下表
在使用PWM模式时,我们只需要设置预分频系数PSC,自动重装载值ARR,即可确定PWM具体频率,即 PWM频率 =(系统时钟频率)/((ARR+1)*(PSC+1))(单位:Hz)
这里以PWM1的递增计数方式为例,假定系统时钟频率设置为80MHz,那么当ARR取999,PSC取79的时候,PWM的频率即为1kHz。配置完成后对时钟进行初始化,此时时钟开始以预分频之后的频率即1MHz开始计数,当CNT的值小于设置的CCR的值时,PWM输出引脚输出为高电平,当CNT的值大于CCR的值时,PWM输出引脚输出为低电平,当CNT计数至ARR时,计数器产生上溢事件,计数器的值更新为0,以此往复。
2.配置cubemx1、首先需要对时钟频率进行设置,这里设置系统时钟频率为80MHz
2、此处选用TIM3通用定时器,配置时钟来源为内部时钟,选择Channel1和Channel2的PWM模式
3、配置PSC为79,ARR为999,向上计数模式,使能自动重载预装载,Channel1选择PWM1模式,pulse值取200,这里的pulse就是指比较寄存器CCR,理论上计算可得PWM频率为1KHz,占空比为20%
Channel2的pulse值取300,其余和Channel1一致
4、最后,配置project相关参数,生成代码。
3.代码及验证cubemx配置生成完成后只需要再启动一下定时器即可完成PWM的输出
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);
__HAL_TIM_CLEAR_IT(&htim3,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
__HAL_TIM_CLEAR_IT(&htim3,TIM_CHANNEL_2);
此处实验使用的是TIM3的Channel1和Channel2,相应的引脚为PA6、PA7,下载到开发板上用逻辑分析仪可以得到如下波形
可以看到波形符合预期,当然在代码中也可以通过
__HAL_TIM_SET_COMPARE(HANDLE, CHANNEL, COMPARE)
来重新设置CCR更改PWM的占空比
或者通过__HAL_TIM_SET_AUTORELOAD(HANDLE, AUTORELOAD)
来重新设置ARR来改变PWM的频率
在上面的PWM模式下我们看一发现Channel1和Channel2的占空比可以不一样,但是其频率是一致的,那么如果需要在一个定时器下的多个通道分别输出频率不同,占空比不同的PWM那么就需要使用输出比较模式了。
输出比较模式和PWM模式的原理很相似,在输出比较模式输出PWM的实验中,有一点不同的是PWM1递增模式下CNT与CCR作比较,若CNT小于CCR则输出为高电平,若CNT大于CCR则输出为低电平,并且在CNT计数至ARR时,CNT会更新至0并产生上溢事件。但是输出比较模式在CNT与CCR不断做比较的过程中,若CNT等于CCR,产生的则是电平翻转,并且会产生中断,通过对中断回调函数的编写,就能够实现多路不同频率信号的输出。
例如,我们定义duty作为占空比,定义pulse作为周期计数数目,若duty为10%,pulse为10000,取ARR为大值65535(在输出比较模式中ARR没啥用,定义成大值就不用经常更新CNT为0了)系统时钟频率为80MHz,预分频系数为79,则预分频之后的时钟频率为1MHz,那么当计pulse个数目,则时间为10ms,占空比为10%,则所需高电平时间为1ms。
当第一次CNT等于CCR时,进入中断回调函数,让CCR加上(pulse-pulse*duty),即9ms后再次进行反转电平,此时PWM持续了9ms的低电平;
当第二次CNT等于CCR是,进入中断回调函数,让CCR加上(pulse*duty),即1ms后再进行反转电平,此时PWM持续了1ms的高电平;
这样即可完成输出比较PWM的配置。
有人可能会问,为什么CNT可以加这么多数,那是因为当CNT从65535溢出后,仍然会从头开始计数,对程序没有影响,具体如下图。
2.配置cubemx1、依然配置系统时钟频率为80MHz,此处选用TIM3通用定时器,配置时钟来源为内部时钟,选择Channel1和Channel2的输出比较模式
2、如图配置参数,需要注意的是自动重载预装载和输出比较预装载都需要关闭,
模式需要选择toogle on match
3、最后配置project相关参数,生成代码
cubemx配置生成完成后,首先需要启动一下定时器,清除中断标志位
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);
__HAL_TIM_CLEAR_IT(&htim3,TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
__HAL_TIM_CLEAR_IT(&htim3,TIM_CHANNEL_2);
然后对中断回调函数进行编写
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{uint32_t OC_Count = 0;
OC_Count = __HAL_TIM_GET_COUNTER(htim);
if(htim->Instance == TIM3)
{if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{ if(GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_6))
{__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,OC_Count + OC_Channel1_Pulse - OC_Channel1_Duty*OC_Channel1_Pulse/100);
}
else
{__HAL_TIM_SET_COMPARE(&htim3,TIM_CHANNEL_1,OC_Count + OC_Channel1_Duty*OC_Channel1_Pulse/100);
}
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_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);
}
}
}
}
此处OC_Channel1_Pulse和OC_Channel2_Pulse 我就是前面“原理”中的pulse,OC_Channel1_Duty和OC_Channel2_Duty就是“原理”中的duty,有定义了两个标志位,通过判断引脚电平,使之能够间次调用。
其中duty和pulse的值可以自己设置,这里由于我duty定义的是整形,所以在代码中对其相应的除以了100,相当于转化为了小数。
若取OC_Channel1_Duty为10%,OC_Channel1_Pulse为10000,则Channel1频率为100Hz,占空比为10%
若取OC_Channel2_Duty为30%,OC_Channel1_Pulse为5000,则Channel1频率为200Hz,占空比为30%
最后下载到开发板中,使用逻辑分析仪观察波形如下
符合实验预期
你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧