STM32CubeMX教程6 TIM 通用定时器 - 生成PWM波
1、准备材料
开发板(STM32F407G-DISC1)
ST-LINK/V2驱动
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波
在“GPIO输出-点亮LED灯”小节我们介绍了如何使用GPIO输出点亮开发板上的LED灯,从而知道了开发板上控制LED灯的四个引脚分别为PD12、PD13、PD14和PD15,这四个引脚刚好可以配置为通用定时器TIM4的四个输出通道,因此接下来我们将配置这四个引脚为通用定时器TIM4的4个通道的PWM输出引脚
3.1、CubeMX相关配置
请先阅读“STM32CubeMX STM32F4 HAL库 工程建立”实验3.4.1小节配置RCC和SYS
3.1.1、时钟树配置
系统时钟树配置与上一实验一致,均设置为STM32F407总线能达到的最高时钟频率,具体如下图所示

3.1.2、外设参数配置
在Pinout & Configuration页面右边芯片引脚预览Pinout view中找到LED灯的四个控制引脚PD12、PD13、PD14和PD15,依次左键单击并配置其功能为TIM4_CHx
然后在页面左侧功能分类栏目中点开Timers栏目,单击栏目下的TIM4,并将其Channel1~4全部配置为PWM Generation CHx
具体配置如下图所示

然后对启用的TIM4定时器的四个通道参数进行设置,下面对重要参数简单介绍
①PSC:该参数为时钟源预分频系数,由于TIM4时钟来源为APB1 Timer clocks (MHz),笔者这里为84MHz,因此经过8399+1=8400分频后的频率为10KHz;
②计数模式:可以选择向上、向下、中心对齐等计数方式;
③ARR:该参数决定了生成PWM的周期,这里设置为199,表示周期为20ms,注意这里周期不能太长(注释2);
④预装载自动重装:设置为Enable后,当修改ARR的值时会在下一个UEV事件生效,否则表示不适用预装载,修改其值会立即生效
⑤PWM模式选择:可以选择模式1/模式2,这两种模式区别为生成的PWM波形不一样,选择PWM模式1且向上计数时,当Pulse值<计数值ARR时此时通道输出有效状态,否则为无效状态,当选择PWM模式2时刚好与模式1相反。如下面两个PWM波形中,上图为采用PWM模式1,通道极性为高电平时产生的PWM波,下图为采用PWM模式2,通道极性为高时产生的PWM波;
⑥Pulse值:即捕获/比较寄存器CRR的值,通过设置该参数可以决定PWM的脉冲宽度,这里设置为0,因为程序中可以动态修改该参数

⑦输出比较预装载:设置为Enable后,当修改Pulse的值时会在下一个UEV事件生效,否则会立即生效
⑧通道极性:设置通道有效状态
如下图所示为具体参数设置

3.1.3、外设中断配置
在Pinout & Configuration页面左边System Core/NVIC中勾选TIM4全局中断,然后选择合适的中断优先级即可

3.2、生成代码
请先阅读“STM32CubeMX STM32F4 HAL库 工程建立”实验3.4.3小节配置Project Manager
单击页面右上角GENERATE CODE生成工程
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、烧录验证
5.1、具体步骤
“设置TIM4的4个通道为PWM输出 -> 配置TIM4基本参数及4个PWM通道参数 -> NVIC中勾选TIM4全局中断并设置合适中断优先级 -> 在生成的工程tim.c文件中重新实现PWM脉宽调制完成回调函数void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) -> 在回调函数中利用__HAL_TIM_SET_COMPARE(HANDLE, CHANNEL, COMPARE)宏定义设置4个通道PWM的占空比 -> 在主函数中使用HAL_TIM_Base_Start_IT(&htim4)启动定时器TIM4 -> 然后使用HAL_TIM_PWM_Start_IT(&htim4, TIM_CHANNEL_x)函数开启四个通道PWM波的输出”
5.2、实验现象
烧录程序,会发现开发板上电后四个LED灯亮度由最暗到最亮然后从最亮再到最暗循环往复,实现呼吸灯的效果

使用逻辑分析仪监测TIM4的四个通道输出引脚状态,可以看出TIM4的四个通道输出的PWM波型周期均为20ms,并且占空比不断地在发生变化


6、注释详解
注释1:图片来源STM32Cube高效开发教程(基础篇)9.1小节
注释2:这里的周期设置为20ms,也即频率为50Hz,人眼睛对于80Hz以上刷新频率完全没有闪烁感,因此如果你实现LED呼吸灯效果有闪烁情况的话,频率不能设置的太低
更多内容请浏览 OSnotes的CSDN博客
STM32CubeMX教程6 TIM 通用定时器 - 生成PWM波的更多相关文章
- STM32F103定时器输出PWM波控制直流电机
这个暑假没有回家,在学校准备九月份的电子设计竞赛.今天想给大家分享一下STM32高级定时器输出PWM波驱动直流电机的问题.. 要想用定时器输出的PWM控制直流电机,,首先要理解“通道”的概念..一个定 ...
- TIM—高级定时器输出PWM
高级定时器输出PWM 主频144M,生成一个频率为1K,占空比为30%的PWM详细代码参考EVT例程PWM_Output 重要参数说明 TIM_TimeBaseInitStructure.TIM_Pe ...
- stm32cube--通用定时器--产生pwm波
看了通用定时器的资料,发现内容挺多,挺难看懂,现在还是先掌握使用方法,以后再多看几遍吧. ① ② ③生成mdk工程后,在main.c的while(1)前面加上HAL_TIM_PWM_Start(&am ...
- 案例 高级定时器和通用定时器产生pwm的区别 gd32和stm32
- 第32章 TIM—高级定时器—零死角玩转STM32-F429系列
第32章 TIM—高级定时器 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fire ...
- STM32通用定时器(转载)
STM32的定时器功能很强大,学习起来也很费劲儿. 其实手册讲的还是挺全面的,只是无奈TIMER的功能太复杂,所以显得手册很难懂,我就是通过这样看手册:while(!SUCCESS){看手册-}才搞明 ...
- (五)转载:通用定时器PWM输出
1. TIMER输出PWM基本概念 脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有 ...
- STM32(7)——通用定时器PWM输出
1.TIMER输出PWM基本概念 脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的数字输出来对模拟电路进行控制的一种 ...
- stm32之通用定时器TIM
STM32系列的CPU,有多达8个定时器: 1.其中TMI1和TIM8是能够产生三对PWM互补输出的高级定时器,常用于三相电机的驱动:它们的时钟有APB2的输出产生: 2.其它6个为普通定时器,时钟由 ...
- 第31章 TIM—基本定时器—零死角玩转STM32-F429系列
第31章 TIM—基本定时器 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fire ...
随机推荐
- RK3568开发笔记(十):开发板buildroot固件移植开发的应用Demo,启动全屏显示
前言 上一篇,移植应用前的通讯接口工作和全屏工作都已经完成了.本篇移植开发的商业应用. 交叉编译好应用 (略),参照<RK3568开发笔记(八):开发板烧写buildroot固件(支 ...
- Mysql高级11-后台进程
一.前言 MySQL的服务实现通过后台多个线程.内存池.文件交互来实现对外服务的,不同线程实现不同的资源操作,各个线程相互协助,共同来完成数据库的服务.MySQL常用的后台线程概括如下,分为Maste ...
- Solution Set -「CF 1514」
「CF 1514A」Perfectly Imperfect Array Link. 就看序列中是否存在不为平方数的元素即可. #include<bits/stdc++.h> using n ...
- python爬虫——爬虫伪装和反“反爬”
前言爬虫伪装和反"反爬"是在爬虫领域中非常重要的话题.伪装可以让你的爬虫看起来更像普通的浏览器或者应用程序,从而减少被服务器封禁的风险:反"反爬"则是应对服务器 ...
- SpringBoot2.7升级到3.0的实践分享
背景 最近把项目中的技术框架做一次升级,最重要的就是SpringBoot从2.7.x升级到3.0.x,当然还会有一些周边的框架也会连带着升级,比如Mybatis Plus,SpringCloud等,话 ...
- Python - 字典3
修改字典项 您可以通过引用其键名来更改特定项的值: 示例,将 "year" 更改为 2018: thisdict = { "brand": "Ford ...
- C、C++函数和类库详解(GCC版)(2014-4-23更新)
C.C++函数和类库详解(GCC版)(未完成) 整理者:高压锅 QQ:280604597 Email:280604597@qq.com 大家有什么不明白的地方,或者想要详细了解的地方可以联系我,我会认 ...
- Java面向对象(高级)
1.类变量 类变量是被类的所有实例共享的. 类变量具体放的位置在哪?在内存中的那个区域,这和jdk的版本是有关的 静态变量在类加载的时候就生成了,即使没有创建类实例也能访问,当然通过实例来实现 类变量 ...
- umich cv-5-2 神经网络训练2
这节课中介绍了训练神经网络的第二部分,包括学习率曲线,超参数优化,模型集成,迁移学习 训练神经网络2 学习率曲线 超参数优化 模型集成 迁移学习 学习率曲线 在训练神经网络时,一个常见的思路就是刚开始 ...
- CF1333A [Little Artem]
Problem 题目简述 给你一个 \(n \times m\) 的方格,构造一个方案,使得方案中 \(B = W + 1\). \(B\):相邻的格子有至少一个白色格子的黑色格子的个数. \(W\) ...