STM32CubeMX教程6 TIM 通用定时器 - 生成PWM波
读者可访问 GitHub - lc-guo/STM32CubeMX-Series-Tutorial 获取原始工程代码
1、准备材料
开发板(STM32F407G-DISC1)
STM32CubeMX软件(Version 6.10.0)
keil µVision5 IDE(MDK-Arm)
逻辑分析仪nanoDLA
2、实验目标
使用STM32CubeMX软件配置STM32F407通用定时器生成可变占空比PWM波形,并将其输出到LED灯引脚实现呼吸灯效果
3、实验流程
3.0、前提知识
STM32F407有10个通用定时器,其中TIM2、TIM3、TIM4和TIM5有4个捕获/比较通道,TIM9、TIM12两个定时器有2个捕获/比较通道,剩下的TIM10、TIM11、TIM13和TIM14只有一个捕获/比较通道
只有一个捕获/比较通道的通用定时器在CubeMX配置页面无“Slave Mode”和“Trigger Source”的选项,也不能联合通道,相较于拥有多个捕获/比较通道的定时器较为简单,这10个通用定时器具体特性如下表所示 (注释1)
对于通用定时器来说,其每个通道均可以实现 ① 输入捕获、② 输出比较和 ③ PWM波生成三种功能,接下来我将分三个实验来分别介绍通用定时器的这三个功能,本小节只介绍通用定时器如何生成PWM波
在“STM32CubeMX教程2 GPIO输出 - 点亮LED灯”实验中我们介绍了如何使用GPIO输出点亮开发板上的LED灯,从而知道了开发板上控制LED灯的四个引脚分别为PD12、PD13、PD14和PD15
这四个引脚刚好可以配置为通用定时器TIM4的四个输出通道,因此接下来我们将配置这四个引脚为通用定时器TIM4的4个通道的PWM输出引脚
3.1、CubeMX相关配置
3.1.0、工程基本配置
打开STM32CubeMX软件,单击ACCESS TO MCU SELECTOR选择开发板MCU(选择你使用开发板的主控MCU型号)选中MCU型号后单击页面右上角Start Project开始工程,具体如下图所示
开始工程之后在配置主页面System Core/RCC中配置HSE/LSE晶振,在System Core/SYS中配置Debug模式,具体如下图所示
详细工程建立内容读者可以阅读“STM32CubeMX教程1 工程建立”
3.1.1、时钟树配置
系统时钟使用8MHz外部高速时钟HSE,HCLK、PCLK1和PCLK2均设置为STM32F407能达到的最高时钟频率,具体如下图所示
3.1.2、外设参数配置
在Pinout & Configuration页面右边芯片引脚预览Pinout view中找到LED灯的四个控制引脚PD12、PD13、PD14和PD15,依次左键单击并配置其功能为TIM4_CHx
然后在页面左侧功能分类栏目中点开Timers栏目,单击栏目下的TIM4,并将其Channel1~4全部配置为PWM Generation CHx
具体配置如下图所示
然后对启用的TIM4定时器的四个通道参数进行设置,下面对重要参数简单介绍
Prescaler :该参数为时钟源预分频系数,由于TIM4时钟来源为APB1 Timer clocks (MHz),笔者这里为84MHz,因此经过8399+1=8400次分频后的频率为10KHz;
Counter Mode :计数模式,可以选择向上、向下、中心对齐等计数方式;
Counter Period :自动重装寄存器ARR值,该参数决定了生成PWM的周期,这里设置为199,表示周期为20ms,注意这里周期不能太长 (注释2);
auto-reload preload :预装载自动重装,设置为Enable后,当修改ARR的值时会在下一个UEV事件生效,否则表示不适用预装载,修改其值会立即生效;
Mode :可以选择模式1/模式2,这两种模式区别为生成的PWM波形不一样,选择PWM模式1且向上计数时,当Pulse值<计数值ARR时此时通道输出有效状态,否则为无效状态,当选择PWM模式2时刚好与模式1相反。如下面两个PWM波形中,上图为采用PWM模式1,通道极性为高电平时产生的PWM波,下图为采用PWM模式2,通道极性为高时产生的PWM波;
Pulse :即捕获/比较寄存器CRR的值,通过设置该参数可以决定PWM的脉冲宽度,这里设置为0,因为程序中可以动态修改该参数;
Output compare preload :输出比较预装载,设置为Enable后,当修改Pulse的值时会在下一个UEV事件生效,否则会立即生效;
CH Polarity :通道极性,设置通道有效状态;
如下图所示为具体参数设置
3.1.3、外设中断配置
在Pinout & Configuration页面左边System Core/NVIC中勾选TIM4全局中断,然后选择合适的中断优先级即可
3.2、生成代码
3.2.0、配置Project Manager页面
单击进入Project Manager页面,在左边Project分栏中修改工程名称、工程目录和工具链,然后在Code Generator中勾选“Gnerate peripheral initialization as a pair of 'c/h' files per peripheral”,最后单击页面右上角GENERATE CODE生成工程,具体如下图所示
详细Project Manager配置内容读者可以阅读“STM32CubeMX教程1 工程建立”实验3.4.3小节
3.2.1、外设初始化调用流程
在工程代码主函数main()中调用MX_TIM4_Init()函数对定时器TIM4计数器参数及四个 PWM通道参数进行了配置
在该MX_TIM4_Init()函数中调用了HAL_TIM_PWM_Init()对定时器PWM输出进行了初始化
然后在HAL_TIM_PWM_Init()函数中调用了HAL_TIM_PWM_MspInit()函数对TIM4时钟和中断设置/使能
如下图所示为具体的TIM4四通道PWM输出初始化调用流程
3.2.2、外设中断调用流程
勾选了TIM4的全局中断之后,在工程文件stm32f4xx_it.c中生成了TIM4全局中断服务函数TIM4_IRQHandler()
该函数调用了HAL库的定时器中断统一处理函数HAL_TIM_IRQHandler(),最终调用PWM脉宽调制完成回调函数 HAL_TIM_PWM_PulseFinishedCallback(),该函数为虚函数
如下图所示为TIM4四通道PWM输出中断调用流程
3.2.3、添加其他必要代码
在tim.c中重新实现PWM脉宽调制完成回调函数HAL_TIM_PWM_PulseFinishedCallback(),在该回调函数中实现了对四个通道PWM的占空比重新调节的目的,即重新配置参数里的Pulse,实现了从最低占空比逐渐到最大占空比然后再逐渐减少至最低占空比的无限循环,具体代码如下所示
源代码如下
uint16_t pulseWidth=0;
uint8_t dirInc=1;
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance != TIM4)
return;
if(dirInc == 1)
{
pulseWidth ++;
if(pulseWidth >= 195)
{
pulseWidth = 195;
dirInc = 0;
}
}
else
{
pulseWidth --;
if(pulseWidth <= 5)
{
pulseWidth = 5;
dirInc = 1;
}
}
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_1, pulseWidth);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_2, pulseWidth);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_3, pulseWidth);
__HAL_TIM_SET_COMPARE(&htim4, TIM_CHANNEL_4, pulseWidth);
}
最后在主函数中以中断方式启动生成PWM即可,如下所示为启动代码
4、常用函数
/*启动定时器*/
HAL_StatusTypeDef HAL_TIM_Base_Start(TIM_HandleTypeDef *htim)
/*停止定时器*/
HAL_StatusTypeDef HAL_TIM_Base_Stop(TIM_HandleTypeDef *htim)
/*启动PWM输出*/
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef *htim, uint32_t Channel)
/*停止PWM输出*/
HAL_StatusTypeDef HAL_TIM_PWM_Stop(TIM_HandleTypeDef *htim, uint32_t Channel)
/*以中断方式启动定时器*/
HAL_StatusTypeDef HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim)
/*以中断方式停止定时器*/
HAL_StatusTypeDef HAL_TIM_Base_Stop_IT(TIM_HandleTypeDef *htim)
/*以中断方式启动PWM输出*/
HAL_StatusTypeDef HAL_TIM_PWM_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel)
/*以中断方式停止PWM输出*/
HAL_StatusTypeDef HAL_TIM_PWM_Stop_IT(TIM_HandleTypeDef *htim, uint32_t Channel)
/*PWM输出完毕回调函数*/
void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim)
/*设置PWM占空比函数*/
__HAL_TIM_SET_COMPARE(__HANDLE__, __CHANNEL__, __COMPARE__)
5、烧录验证
烧录程序,会发现开发板上电后四个LED灯亮度由最暗到最亮然后从最亮再到最暗循环往复,实现呼吸灯的效果
使用逻辑分析仪监测TIM4的四个通道输出引脚状态,可以看出TIM4的四个通道输出的PWM波型周期均为20ms,并且占空比不断地在发生变化
6、注释详解
注释1:图片来源 STM32Cube高效开发教程(基础篇) 9.1小节
注释2:这里的周期设置为20ms,也即频率为50Hz,人眼睛对于80Hz以上刷新频率完全没有闪烁感,因此如果你实现LED呼吸灯效果有闪烁情况的话,频率不能设置的太低