
这一章我们来学习如何使用通用定时器产生 PWM 输出。本章要实现的功能是:通过 TIM3 的通道 1 输出 PWM 信号,控制 D7 指示灯的亮度。 PWM 简介 PWM 是 Pulse Width Modulation 的缩写,中文意思就是脉冲宽度调制,简称脉宽调制。它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,其控制简单、灵活和动态响应好等优点而成为电力电子技术最广泛应用的控制方式,其应用领域包括测量,通信,功率控制与变换,电动机控制、伺服控制、调光、开关电源,甚至某些音频放大器,因此学习 PWM 具有十分重要的现实意义。 其实我们也可以这样理解,PWM 是一种对模拟信号电平进行数字编码的方法。通过高分辨率计数器的使用,方波的占空比被调制用来对一个具体模拟信号的电平进行编码。PWM 信号仍然是数字的,因为在给定的任何时刻,满幅值的直流供电要么完全有(ON),要么完全无(OFF)。电压或电流源是以一种通(ON)或断(OFF)的重复脉冲序列被加到模拟负载上去的。通的时候即是直流供电被加到负载上的时候,断的时候即是供电被断开的时候。只要带宽足够,任何模拟值都可以使用 PWM 进行编码。PWM 对应模拟信号的等效图,如下图。 ![]() 1 i! M- _. D5 g8 R 从图中可以看到,上图 a 是一个正弦波即模拟信号,b 是一个数字脉冲波形即数字信号。我们知道在计算机系统中只能识别是 1 和 0,对于STM32F1芯片,要么输出高电平(3.3V),要么输出低电平(0),假如要输出 1.5V 的电压,那么就必须通过相应的处理,比如本章所要讲解的 PWM 输出,其实从上图也可以看到,只要保证数字信号脉宽足够就可以使用 PWM 进行编码,从而输出 1.5V 的电压。
STM32F1 除了基本定时器 TIM6 和 TIM7,其他定时器都可以产生 PWM 输出。 其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达 4 路的 PWM 输出,这些在定时器中断章节中已经介绍过。 PWM 的输出其实就是对外输出脉宽可调(即占空比调节)的方波信号,信号频率是由自动重装寄存器 ARR 的值决定,占空比由比较寄存器 CCR 的值决定。其示意图如图所示: ![]() 从上图中可以看到,PWM 输出频率是不变的,改变的是 CCR 寄存器内 的值,此值的改变将导致 PWM 输出信号占空比的改变。占空比其实就是一个周期内高电平时间与周期的比值。 PWM 输出比较模式总共有8种,具体由寄存器 CCMRx 的位 OCxM[2:0]配置。我们这里只讲解最常用的两种 PWM 输出模式:PWM1 和 PWM2,其他几种模式可以参考《STM32F10x 中文参考手册》13、14 定时器章节。 PWM1 和 PWM2 这两种模式用法差不多,区别之处就是输出电平的极性不同。如下图所示: 2 a; f, j0 b0 e ![]() PWM 模式根据计数器CNT计数方式,可分为边沿对齐模式和中心对齐模式。 (1)PWM 边沿对齐模式 当 TIMx_CR1 寄存器中的 DIR 位为低时执行递增计数, 计数器 CNT从 0 计数到自动重载值(TIMx_ARR 寄存器的内容),然后重新从 0 开始计数并生成计数器上溢事件。 以 PWM 模式 1 为例。只要 TIMx_CNT < TIMx_CCRx, PWM 参考信号 OCxREF便为有效的高电平,否则为无效的低电平。如果 TIMx_CCRx 中的比较值大于自动重载值 (TIMx_ARR 中) , 则 OCxREF 保持为 “ 1” 。如果比较值为 0,则 OCxREF保持为“ 0”。如下图所示: / W; `) e8 m# C- ?( I( e ![]() 当 TIMx_CR1 寄存器中的 DIR 位为高时执行递减计数,计数器 CNT 从自动重载值(TIMx_ARR 寄存器的内容)递减计数到 0,然后重新从 TIMx_ARR值开始计数并生成计数器下溢事件。 以 PWM 模式 1 为例。只要TIMx_CNT >TIMx_CCRx, PWM 参考信号 OCxREF便为无效的低电平,否则为有效的高电平。如果 TIMx_CCRx 中的比较值大于自动重载值(TIMx_ARR 中),则 OCxREF 保持为“ 1”。此模式下不能产生0%的PWM 波形。 (2)PWM 中心对齐模式 在中心对齐模式下,计数器 CNT 是工作在递增/递减模式下。开始的时候,计数器 CNT 从 0 开始计数到自动重载值减 1(ARR-1),生成计数器上溢事件;然后从自动重载值开始向下计数到 1 并生成计数器下溢事件。之后从 0 开始重新计数。如下图所示: ![]() 我们以 ARR=8,CCRx=4 为例进行介绍。第一阶段计数器 CNT 工作在递增计数方式,从 0 开始计数,当 TIMx_CNT < TIMx_CCRx 时,PWM 参考信号 OCxREF 为有效的高电平,当 TIMx_CNT >= TIMx_CCRx 时,PWM 参考信号 OCxREF 为无效的低电平。第二阶段计数器 CNT 工作在递减计数方式,从 ARR 开始递减计数,当TIMx_CNT > TIMx_CCRx 时,PWM 参考信号 OCxREF 为无效的低电平,当 TIMx_CNT<= TIMx_CCRx 时,PWM 参考信号 OCxREF 为有效的高电平。 中心对齐模式又分为中心对齐模式 1/2/3 三种,具体由寄存器 CR1 位 CMS[1:0]配置。具体的区别就是比较中断标志位 CCxIF 在何时置 1:中心模式 1在 CNT 递减计数的时候置 1,中心对齐模式 2 在 CNT 递增计数时置 1,中心模式 3 在 CNT 递增和递减计数时都置 1。 通用定时器 PWM 输出配置步骤 接下来我们介绍下如何使用库函数对通用定时器的 PWM 输出进行配置。这个也是在编写程序中必须要了解的。其实 PWM 输出和上一章一样也是通用定时器的一个功能,因此还是要用到定时器的相关配置函数,具体步骤如下:(定时器相关库函数在 stm32f10x_tim.c和stm32f10x_tim.h 文件中) (1)使能定时器及端口时钟,并设置引脚复用器映射 因为 PWM 输出也是通用定时器的一个功能,所以需要使能相应定时器时钟。由于 PWM 输出通道是对应着 STM32F1 芯片的 IO 口,所以需要使能对应的端口时钟,并将对应 IO 口配置为复用输出功能。例如本章 PWM 呼吸灯实验,我们使用的是 TIM3 的 CH1 通道输出PWM信号,因此需要使能 TIM3 时钟,调用的库函数如下:
而 TIM3 的 CH1 通道对应的管脚是 PA6,但是我们开发板上的 LED 灯并没有接在PA6引脚上, 如果要让这个通道映射到LED所接的IO口上, 则需要使用GPIO的复用功能重映射, 在 《STM32F1xx 中文参考手册》 -8 通用和复用功能 I/O(GPIO和 AFIO)-8.3.7 定时器复用功能重映射章节都有介绍如下: & k2 X: O! S1 O5 F ![]() LED模块电路的8个小灯, 其中D7就是连接在PC6口的, 所以可以将TIM3_CH1配置为完全重映像即可映射到 PC6 脚,这样 PC6 就可以输出 PWM了。使用到外设的复用功能重映射就需要开启 AFIO 时钟,所以开启 AFIO 时钟函数如下:
从图中可以看到,TIM3_CH1 有部分重映像和完全重映像选择,那么就需要调用引脚复用映射功能函数: 第二个参数很好理解,用来使能还是失能;第一个参数是选择是部分重映射还是完全重映射,这个参数也很好选择,因为可选的参数在 stm32f10x_gpio.h都已经列出来非常详细,如下: ( I1 Q; F8 P& h! o* g ![]() 这 里 我 们 使 用 的 是 TIM3_CH1 完 全 重 映 射 , 所 以 参 数 为 GPIO_FullRemap_TIM3。调用函数如下:
最后还要记得将 PF9管脚模式配置为复用推挽输出。
(2)初始化定时器参数,包含自动重装值,分频系数,计数方式等要使用定时器功能,必须对定时器内相关参数初始化,其库函数如下:
这个在定时器中断章节就已经介绍。 (3)初始化 PWM 输出参数,包含 PWM 模式、输出极性,使能等 初始化定时器后,需要设置对应通道 PWM 的输出参数,比如 PWM模式、输出极性、是否使能 PWM 输出等。PWM 通道设置函数如下,
我们知道每个通用定时器有多达 4 路 PWM 输出通道, 所以 TIM_OCxInit函数名中的x 值可以为 1/2/3/4。函数的第一个参数相信大家一看就清楚,是用来选择定时器的。第二个参数是一个结构体指针变量,同样我们看下这个结构体TIM_OCInitTypeDef 成员变量:
! A% w# I+ l1 M8 u 这里我们就讲解下比较常用的 PWM 模式所需的成员变量: TIM_OCMode:比较输出模式选择,总共有 8 种,最常用的是PWM1和PWM2。 TIM_OutputState:比较输出使能,用来使能 PWM 输出到 IO口。 TIM_OCPolarity:输出极性,用来设定输出通道电平的极性,是高电平还是 低电平。 结 构 体 内 其 他 的 成 员 变 量 TIM_OutputNState , TIM_OCNPolarity ,TIM_OCIdleState 和 TIM_OCNIdleState 是高级定时器才用到的。如大家使用到高级定时器,可以查看中文参考手册高级定时器章节。 所以如果我们要配置TIM3的 CH1 为 PWM1 模式,输出极性为低电平,并且使能 PWM输出,可以如下配置:
2 v- E% N2 w. ~8 u) s (4)开启定时器 前面几个步骤已经将定时器及 PWM 配置好,但 PWM 还不能正常使用,只有开启定时器了才能让它正常工作,开启定时器的库函数如下:
第一个参数是用来选择定时器。 第二个参数是用来使能或者失能定时器,也就是开启或者关闭定时器功能。同样可以选择 ENABLE 和 DISABLE。例如我们要开启 TIM3,那么调用此函数如下:
(5)修改 TIMx_CCRx的值控制占空比 其实经过前面几个步骤的配置,PWM 已经开始输出了,只是占空比和频率是固定的,例如本章要实现呼吸灯效果,那么就需要调节 TIM3 通道 1的占空比,通过修改 TIM3_CCR1 值控制。调节占空比函数是:
对于其他通道,分别有对应的函数名,函数格式是 TIM_SetComparex (x=1/2/3/4)。 (6)使能 TIMx 在 CCRx上的预装载寄存器 使能输出比较预装载库函数是:
第一个参数用于选择定时器, 第二个参数用于选择使能还是失能输出比较预装载寄存器,可选择为 TIM_OCPreload_Enable、TIM_OCPreload_Disable。 (7)使能 TIMx 在 ARR 上的预装载寄存器允许位 使能 TIMx 在 ARR 上的预装载寄存器允许位库函数是:
第一个参数用于选择定时器,第二个参数用于选择使能还是失能。 将以上几步全部配置好后,我们就可以控制通用定时器相应的通道输出PWM波形了,这里要特别提醒下,虽然高级定时器和通用定时器类似,但是高级定时器要想输出 PWM 波形,必须要设置一个 MOE 位(TIMx_BDTR 的第 15 位),以使能主输出,否则不会输出 PWM。库函数设置的函数为:
|
【2025·STM32峰会】GUI解决方案实训分享1-对LVGL咖啡机例程的牛刀小试以及问题排查
OpenBLT移植到STM32F405开发板
为什么要先开启STM32外设时钟?
【STM32MP157】从ST官方例程中分析RPMsg-TTY/SDB核间通信的使用方法
【经验分享】STM32实例-RTC实时时钟实验④-获取RTC时间函数与中断服务函数
STM32 以太网 MAC Loopback 的实现
STM32功能安全设计包,助力产品功能安全认证
基于STM32启动过程startup_xxxx.s文件经验分享
HRTIM 指南
ST 微控制器电磁兼容性 (EMC) 设计指南