PWM呼吸灯
- 前言
- 通用定时器
- 材料
- PWM
- PWM简介
- PWM输出主要HAL库函数
- 工程配置
- 定时器界面功能简介及配置
- 输入捕获模式
- 输出比较模式
- PWM模式
- 强迫输出模式
- 单脉冲输出模式
- 计数器参数配置
- PWM参数配置
- 进入代码
- 下载验证
- 申明
- 结语
前言
在上一章《STM32CubeMX实战教程(四)——基本定时器(还是点灯)》中,已经介绍过基本定时器的功能及用法,在这一章中,我讲主要介绍一下通用定时器的相关功能以及配置方法,废话不多,直接进入主题。
通用定时器
在STM32F4中,TIM2到TIM5为通用定时器,主要特性如下:
- 16 位(TIM3 和 TIM4)或 32 位(TIM2 和 TIM5)递增、递减和递增/递减自动重载计数器
- 16 位可编程预分频器,用于对计数器时钟频率进行分频 (即运行时修改),分频系数介于 1 到 65536 之间
- 多达 4 个独立通道,可用于:
- 输入捕获
- 输出比较
- PWM 生成(边沿和中心对齐模式)
- 单脉冲模式输出
- 使用外部信号控制定时器且可实现多个定时器互连的同步电路
- 发生如下事件时生成中断/DMA 请求:
- 更新:计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发)
- 触发事件(计数器启动、停止、初始化或通过内部/外部触发计数)
- 输入捕获
- 输出比较
- 支持定位用增量(正交)编码器和霍尔传感器电路
- 外部时钟触发输入或逐周期电流管理
TIM9到TIM14也属于通用定时器,但这几个定时器的具体功能每一个都有些许不同,可以在STM32CubeMX中查看,这里不多解释。
材料
- 正点原子探索者开发板,芯片为STM32F407GZT6
- 开发板的原理图
- STM32F4系列HAL库开发手册
- STM32CubeMX
- keil5
PWM
PWM简介
脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调试。是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术。广泛应用在从测量、通信到功率控制与变换的许多领域中。
例如上图中,图b)是微处理输出的数字信号,实际上他接到电机等功率设备上时,效果相当于图a)。这就是PWM调制。例如输出占空比为50%,频率为10Hz的脉冲,高电平为3.3V.则其输出的模拟效果相当于输出一个1.65V的高电平。脉冲调制有两个重要的参数,第一个就是输出频率,频率越高,则模拟的效果越好。第二个就是占空比。占空比就是改变输出模拟效果的电压大小。占空比越大则模拟出的电压越大。
PWM输出主要HAL库函数
看到我们HAL库开发手册定时器章节的PWM这一块,可以看到已经给我们提供了很多的API接口,下面我将对每个函数稍加介绍。
前四个函数是对PWM的初始化和禁用,这几个函数STM32CubeMX会自动帮我们配置并调用的,基本不需理会。
后面六个函数是开启或关闭PWM,有 IT 后缀的函数在开启或关闭的同时使能或关闭PWM中断,有DMA后缀的函数在开启或关闭PWM的同时使能或关闭DMA
工程配置
根据原理图,板子上只有一个可配置成定时器输出的灯,并且为TIM14,那么接下来我就以TIM14为例进行PWM输出的配置,其他定时器道理大同小异
RCC时钟源选择外部晶振
然后依旧是将主频配置为168MHz,这里再次说明在STM32F4中,TIM2-7和TIM12-14是挂载在APB1时钟线上的,而TIM1和TIM8-11则是挂载在APB2时钟线上,我们这里用到了TIM6,所以应该是APB1,经过分频后我在APB1上得到了一个84MHz的时钟源。
定时器界面功能简介及配置
以TIM14为例,进入配置界面后,我们需要使能TIM14,并且注意TIM14是只有一个通道的,而另一些通用定时器最多可以达到四通道输出,这也是STM32单片机的强大之处。
使能之后可以选择六种定时器模式,分别是:
- 输入捕获模式
- 输出比较模式,无输出
- 输出比较模式,通道一输出
- PWM通用模式,无输出
- PWM通用模式,通道一输出
- 强制输出模式
另外还可以使能单脉冲输出模式
这里我们选择的是PWM模式,通道一输出,并不使能单脉冲模式。
输入捕获模式
在输入捕获模式下,当相应的 ICx 信号检测到跳变沿后,将使用捕获/比较寄存器 (TIMx_CCRx) 来锁存计数器的值。发生捕获事件时,会将相应CCXIF 标志(TIMx_SR 寄存器)置 1,并 可发送中断或 DMA 请求(如果已使能)。如果发生捕获事件时 CCxIF 标志已处于高位,则会将重复捕获标志 CCxOF(TIMx_SR 寄存器)置 1。可通过软件向 CCxIF 写入 0 来给 CCxIF 清零,或读取存储在 TIMx_CCRx 寄存器中的已捕获数据。向 CCxOF 写入“0”后会将其清 零。
简单来说,捕获模式可以检测输入信号的脉宽
输出比较模式
当捕获/比较寄存器与计数器之间相匹配时,输出比较功能:
1.将为相应的输出引脚分配一个可编程值,该值由输出比较模式(TIMx_CCMRx 寄存器中 的 OCxM 位)和输出极性(TIMx_CCER 寄存器中的 CCxP 位)定义。匹配时,输出引脚既可保持其电(OCXM=“000”),也可设置为有效电平(OCxM=“001”)、无效电平(OCxM=“010”)或进行翻转(OCxM=“011”)。
2.将中断状态寄存器中的标志置 1(TIMx_SR 寄存器中的 CCxIF 位)。
3 如果相应中断使能位(TIMx_DIER 寄存器中的 CCXIE 位)置 1,将生成中断。
也就是检测引脚的电平持续时间并和设定的值进行比较,匹配后可以进行IO控制,中断响应等操作
PWM模式
在PWM简介中已经说明,这里不再重复
强迫输出模式
在输出模式(TIMx_CCMRx 寄存器中的 CCxS 位 =“00”)下,可直接由软件将每个输出比 较信号(OCxREF 和 OCx)强制设置为有效电平或无效电平,而无需考虑输出比较寄存器和 计数器之间的任何比较结果。
单脉冲输出模式
单脉冲输出模式是特殊的PWM模式,它可以在一个激励信号的作用下触发,并产生一个可编程的脉冲。
计数器参数配置
根据我们上面时钟树配置后得到的84MHz时钟源,进行计数器参数配置:
- 预分频(84-1,也就得到1MHz的时钟频率作为定时器的时钟源)
- 向上计数模式(从0开始向上计数至初值并发生上溢事件)
- 计数器重装值(500-1,每计数500次发生溢出,最终PWM频率为1M/500=2kHz)
- 内部时钟分频(可以理解为在预分频的基础上再进行一次分频,但只能2或4分频,这里不需要)
- 计数器自动重装载使能
PWM参数配置
下面是PWM的参数配置:
- PWM模式(PWM模式1)
- 有效电平时间(根据计数器的重装值,500为最大,所以这里取值为500-1,我们这里是呼吸灯,所以先选择0,并程序中进行实时修改)
- 输出比较预加载(也就是在定时器工作时是否能修改有效电平时间,如果禁用的话是要等到更新事件到来的时候才能进行修改,所以这里使能)
- 快速模式(单脉冲输出下可选,这里作用不大)
- 输出极性(低)
在这里,我特别解释一下输出极性和PWM模式之间的关联。
在PWM模式1下,向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为有效电平,否则为无效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。
在PWM模式2下,在向上计数时,一旦TIMx_CNT<TIMx_CCR1时通道1为无效电平,否则为有效电平;在向下计数时,一旦TIMx_CNT>TIMx_CCR1时通道1为有效电平,否则为无效电平。
注:TIMx_CNT为计数寄存器,用于计数器计数;TIMx_CCR1为比较寄存器,用户设置,即上面的Pulse值,用于与计数寄存器进行比较
进入代码
生成工程编译通过后直接进入main函数进行代码的添加
int main(void)
{
/* USER CODE BEGIN 1 */
uint8_t dir=1;
uint16_t led0pwmval=0;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM14_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim14,TIM_CHANNEL_1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_Delay(10);
if(dir)led0pwmval++; //dir==1 led0pwmval递增
else led0pwmval--; //dir==0 led0pwmval递减
if(led0pwmval>300)dir=0; //led0pwmval到达300后,方向为递减
if(led0pwmval==0)dir=1; //led0pwmval递减到0后,方向改为递增
__HAL_TIM_SetCompare(&htim14,TIM_CHANNEL_1,led0pwmval);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
第一步,在定时器初始化之后,我们调用HAL_TIM_PWM_Start来开启PWM的输出
第二步就是要制造出呼吸灯的效果,while循环里面几行代码的意思是,取两个变量,一个作为标志位(dir),用于判断是缓慢变量还是缓慢变暗;另一个用于有效电平的改变(led0pwmval),也就是改变PWM的占空比,最后调用 __HAL_TIM_SetCompare 实现占空比的改变。
这里稍微介绍一下 __HAL_TIM_SetCompare这个函数,每次调用它的时候就可以更新一次捕获比较寄存器的数据,从而更新占空比,当然,也可以直接操作寄存器的方法,在这里也就是等效于TIM14->CCR1=led0pwmval。
当然,根据我们上面分析的led0pwmval这个变量的值完全是可以取0~(500-1)中任意整数的,这里我只取到300,单纯是让呼吸灯亮暗交替快一些
所以效果就是,每10ms使PWM占空比增加或减少一点来实现LED灯变亮或暗一些。
下载验证
具体下载方法这里不再重复,可查看《STM32CubeMX实战教程(一)——软件入门》,工程源文件我已经上传,在《通用定时器实验(PWM输出)》非常抱歉由于CSDN官网上传的资源必须要设定积分,否则几乎无法通过审核,这里就没有办法免费开发给大家,不过源码在教程里已经非常详细了。
申明
本文到这里就告一段落,这边我进行一个申明,如果你是第一次学习STM32单片机,或者是没有接触过STM32定时器的小白,即便我已经讲解得很详细,但是光靠这篇文章精通STM32定时器几乎是不太可能,因为STM32的定时器系统实在是太过庞大和复杂。那么我这里还是推荐你去下载官方的参考手册,如果觉得自己英文功底还可以的,可以直接下载英文版本,方法也很简单。在STM32CubeMX软件中,选择任意一个外设,将鼠标放置在上面不要点击,就会弹出相应外设的简介,点击details and documentation,就会弹出外设相关的详细介绍,并且附带两个下载链接,直接点击便可立即下载。
- 芯片手册(有关芯片性能及其他基本信息)
- 参考手册(外设相关寄存器及外设的配置方法)
在此提醒这两个都是全英的,四六级没过的小朋友慎重考虑,想要中文版本的话只能去ST官网慢慢找了
结语
非常感谢大家的阅读,如有不当或者错误的地方,欢迎指正,谢谢支持。
一个字一个字敲出来不容易,如果觉得有帮助,点个赞再走呗~
祝大家事业蒸蒸日上!
奥里给~