一、通用定时器简介
STM32通用定时器由一个通过可编程预分频器驱动的16位自动重装载计数器组成,适用于多种应用场景,包括测量输入信号的脉冲长度(利用输入捕获功能)和生成输出波形(使用输出比较及PWM功能)。借助于定时器预分频器以及RCC时钟控制器提供的预分频能力,用户可以灵活调整脉冲长度和波形周期,范围可从几微秒至几毫秒不等。每个通用定时器都是完全独立的,不共享任何资源,这保证了它们可以在互不影响的情况下单独运行,同时也支持同步操作,以满足复杂的实时控制需求。
通用TIMx (TIM2、TIM3、TIM4和TIM5)定时器功能包括:
- 16位向上、向下、向上/向下自动装载计数器
- 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65536之间的任意数值
- 4个独立通道:
- 输入捕获
- 输出比较
- PWM生成(边缘或中间对齐模式)
- 单脉冲模式输出
- 使用外部信号控制定时器和定时器互连的同步电路
- 如下事件发生时产生中断/DMA:
- 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
- 触发事件(计数器启动、停止、初始化或者由内部/外部触发计数)
- 输入捕获
- 输出比较
- 支持针对定位的增量(正交)编码器和霍尔传感器电路
- 触发输入作为外部时钟或者按周期的电流管理
二、通用定时器内部结构
通用定时器的内部结构相较于基本定时器而言复杂得多,主要由以下几个关键部分组成:时基单元、时钟发生器、输入捕获以及输出比较等。
1. 时钟源
通用定时器提供了四种不同的时钟来源选项,具体选择可通过配置TIMx_SMCR寄存器的相关位来实现:
(1)内部时钟(CK_INT):这是最常见的时钟源选择,适用于大多数应用场景。
(2)外部时钟模式1:使用外部输入引脚TIx(x=1,2,3,4)作为时钟源,允许定时器根据外部信号进行计数。
(3)外部时钟模式2:通过外部触发输入ETR提供时钟信号,进一步扩展了定时器的应用范围。
(4)内部触发输入(ITRx,x=0,1,2,3):利用其他定时器或系统内部产生的触发信号作为时钟源。
在典型配置中,我们通常选择内部时钟(CK_INT)作为通用定时器的时钟来源,并且由于APB1的时钟分频系数不为1,通用定时器的时钟频率是APB1时钟的两倍,即72MHz。
2. 控制器
通用定时器的控制器部分集成了触发控制器、从模式控制器以及编码器接口,以支持广泛的应用需求。
触发控制器负责生成触发信号,可用于驱动片内外设的操作,如为其他定时器提供时钟或触发DAC和ADC转换,从而增强系统内不同模块间的同步与协调能力。
从模式控制器则管理计数器的各种操作状态,包括复位、启动、递增或递减计数,使得定时器能够适应复杂的计数模式和同步操作要求,满足多样化的实时控制需求。此外,专门设计的编码器接口用于处理来自旋转编码器的输入信号,通过准确解码位置信息调整计数器值,适用于需要精确位置反馈的应用场景。
3. 时基单元
通用定时器的时基单元由三个核心寄存器组成:计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)和自动重装载寄存器(TIMx_ARR)。在高级定时器中,还额外包含一个重复计数寄存器(TIMx_RCR),这一特性在通用和基本定时器中并不存在。
在时基单元内,预分频器寄存器(TIMx_PSC)用于对计数器时钟频率进行分频调整。通过设置寄存器内的相应位,可以将分频系数设定在1到65536之间,从而灵活控制计数器的工作频率。由于从模式控制寄存器具备缓冲功能,预分频器支持实时更改,新的分频比将在下一个更新事件发生时生效。
此外,时基单元中的计数器寄存器(TIMx_CNT)支持多种计数方式:
(1)向上计数
在向上(递增)计数模式下,计数器从0开始计数,每当接收到一个CK_CNT脉冲时,计数器的值增加1,直至达到自动重载寄存器(TIMx_ARR)中设定的值。此时,计数器会触发一次上溢事件,并重新从0开始计数。
(2)向下计数
在向下(递减)计数模式下,计数器从自动重载寄存器(TIMx_ARR)中设定的值开始递减计数,每接收到一个CK_CNT脉冲时,计数器的值减少1,直至计数至0。此时,计数器触发一次下溢事件,并重新从自动重载值开始新一轮计数。
(3)中央对齐计数
在中心对齐模式下,计数器的操作分为两个阶段:首先从0开始递增计数至自动重载寄存器(TIMx_ARR)中设定的值减1,此时生成计数器上溢事件;然后从自动重载值开始递减计数至1,并生成计数器下溢事件。
在时基单元中还有一个自动重载寄存器(TIMx_ARR),它用于存储与计数器(TIMx_CNT)进行比较的目标值。
4. 输入捕获单元
输入捕获单元主要由以下几部分组成:输入通道、输入滤波器和边沿检测器、输入捕获通道、预分频器以及捕获/比较寄存器。
在输入捕获模式下,当ICx输入信号检测到设定的跳变沿时,计数器的当前值会被锁存到捕获/比较寄存器(TIMx_CCRx)。每次捕获事件发生时,相应的捕获标志位CCxIF(位于TIMx_SR寄存器中)被置1,并可触发中断或DMA请求。
ICx输入信号经过预分频器处理,根据TIMx_CCMRx寄存器中的ICxPSC位设置预分频系数,决定每多少个事件进行一次捕获。若需捕获每个边沿,则预分频系数应设为1。首次捕获时,计数器CNT的值被锁存到CCR寄存器并产生中断,CCxIF标志被置位;若CCR已有值且CCxIF已置1,则发生第二次捕获时,捕获溢出标志位CCxOF会被置位,该标志只能通过软件写0清零。
5. 输出比较通道
通用定时器通常配备有多个输出通道(TIMx_CH1/2/3/4),这些通道对应于STM32微控制器上的物理引脚。每个输出通道可以独立配置为不同的功能,如输出比较、PWM生成等。
输出比较单元与输入捕获单元共享捕获/比较寄存器(TIMx_CCRx)。然而,在输出比较模式下,这些寄存器主要发挥其比较功能的作用。当计数器CNT的值与比较寄存器CCR的值相等时,输出参考信号OCxREF的极性会发生改变,并且会产生一个比较中断CCxI。此时,相应的标志位CCxIF(位于SR寄存器中)会被置位。
在发生比较匹配事件后,OCxREF信号经过一系列控制处理,最终转换为实际的输出信号OC1/2/3/4。这些输出信号会通过对应的管脚TIMx_CH1/2/3/4输出到外部设备。
三、PWM简介
什么是PWM?
PWM是 Pulse Width Modulation 的缩写,中文意思就是脉冲宽度调制,简称脉宽度调制,其核心思想是通过快速开关数字信号并改变其开启时间(脉宽)的比例来控制输送到负载的平均功率或电压,即控制占空比。
它是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,其控制简单、灵活和动态响应好等优点而成为电力电子技术最广泛应用的控制方式,其应用领域包括测量,通信,功率控制与变换,电动机控制、伺服控制、调光、开关电源,甚至某些音频放大器,因此学习PWM具有十分重要的现实意义。
- PWM 信号是一个周期性的方波(高电平-低电平交替)。
- 占空比 是一个周期内高电平(脉冲开启)时间占整个周期时间的百分比。
- 公式:占空比 = (脉冲开启时间 / 周期时间) × 100%
- 例如:一个周期为 10ms 的 PWM 信号,如果高电平持续 3ms,则占空比为 30%;如果高电平持续 7ms,则占空比为 70%。
与模拟控制的区别
- 传统的模拟控制(如使用可变电阻)是通过连续地改变电压或电流的大小来控制负载。
- PWM 控制是通过改变数字脉冲的宽度比例来达到类似的连续控制效果。它是数字式的开关控制,而非连续的模拟调节。
- PWM 控制本质上改变的是负载两端的 平均电压 和流经负载的 平均电流,而不是瞬时电压或电流的峰值
通用定时器的PWM模式
PWM(脉冲宽度调制)模式是输出比较模式的一种特例,专门用于生成具有特定频率和占空比的PWM波形。它可以配置为PWM1模式或PWM2模式,适用于电机控制、LED亮度调节等多种应用。
PWM1模式:当计数器CNT的值小于比较寄存器CCR的值时,输出高电平;反之,输出低电平。这使得输出信号的占空比由CCR值决定。
PWM2模式:与PWM1模式相反,当计数器CNT的值小于比较寄存器CCR的值时,输出低电平;反之,输出高电平。
通过调整计数器的自动重装载值(TIMx_ARR)和比较寄存器(TIMx_CCRx)的值,可以精确控制PWM信号的周期和占空比。
四、代码实现定时器输出PWM脉冲
本实验使用通用定时器TIM3的通道1来输出PWM脉冲,TIM3的输出通道1是映射在GPIO引脚PA6上,并在PA6引脚接一个LED灯。我们通过控制PWM占空比,实现呼吸灯的效果。(灯的亮度由亮到暗,再由暗到亮)
1.配置步骤
- 使能外设TIM3、GPIOA时钟
- 初始GPIO
- 初始化定时器,配置定时器的时基单元和输出通道部分
- 使能定时器
- 使能输出比较预装载寄存器
- 使能自动重装载预装载寄存器
- 设置比较寄存器的值
2.代码实现
编写tim_drv.c文件
#include "tim_drv.h"/*********************************************************************************** @brief : 定时器PWM输出配置函数* * @param : arr 自动重装载值* @param : psc 预分频系数* @retval : 无
**********************************************************************************/
void PWM_Config(uint16_t arr, uint16_t psc)
{//开启外设GPIO时钟 复用时钟AFIO 定时器TIM3时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//GPIO初始化GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6; //引脚6GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;//速率GPIO_Init(GPIOA,&GPIO_InitStruct);//初始化定时器TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分割TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式TIM_TimeBaseInitStruct.TIM_Period = arr; //自动重装载值TIM_TimeBaseInitStruct.TIM_Prescaler = psc; //预分频系数TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStruct);//输出比较通道参数初始化TIM_OCInitTypeDef TIM_OCInitStruct;TIM_OCInitStruct.TIM_OCMode = TIM_OCMode_PWM1; //PWM1模式TIM_OCInitStruct.TIM_OCPolarity = TIM_OCPolarity_Low; //有效电平为低电平TIM_OCInitStruct.TIM_OutputState = TIM_OutputState_Enable; //输出使能TIM_OCInitStruct.TIM_Pulse = 0; //初始占空比为0(整个计数周期PWM波形为高电平)TIM_OC1Init(TIM3,&TIM_OCInitStruct);//使能输出比较预装载寄存器TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);//使能自动重装载预装载寄存器TIM_ARRPreloadConfig(TIM3,ENABLE);//使能定时器TIM_Cmd(TIM3,ENABLE);
}
编写tim_drv.h文件
#ifndef __TIM_DRV_H__
#define __TIM_DRV_H__//头文件包含
#include "stm32f10x.h"//函数声明
void PWM_Config(uint16_t arr, uint16_t psc);#endif
编写main.c文件
#include "led_drv.h"
#include "systick.h"
#include "tim_drv.h"int main(void)
{uint8_t dir=0;uint16_t ccr = 0;SysTick_Init(72);//初始化systickPWM_Config(100-1,720-1);//初始化LEDwhile (1){if(!dir){ccr++;if(ccr >= 500)dir = 1;}else{ccr--;if(ccr <= 0)dir =0;}TIM_SetCompare1(TIM3,ccr);delay_ms(5);}
}