一、通用定时器基本原理
1-1 三种定时器区别
1.三种STM32定时器区别
定时器种类 | 位数 | 计数器模式 | 产生DMA请求 | 捕获/比较通道 | 互补输出 | 特殊应用场景 |
---|
高级定时器(TIM1,TIM8) | 16 | 向上,向下,向上/下 | 可以 | 4 | 有 | 带死区控制盒紧急刹车,可应用于PWM电机控制 | 通用定时器(TIM2~TIM5) | 16 | 向上,向下,向上/下 | 可以 | 4 | 无 | 通用。定时计数,PWM输出,输入捕获,输出比较 | 基本定时器(TIM6,TIM7) | 16 | 向上,向下,向上/下 | 可以 | 0 | 无 | 主要应用于驱动DAC |
2.通用定时器功能特点描述
- 位于低速的APB1总线上
- 16位向上、向下、向下/上(中心对齐)计数模式,自动重装载计数器(TIMx_CNT)
- 16位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系数为1~65535之间的任意数值。
- 4个独立通道(TIMx_CH1~4),这些通道可以用来作为
①输入捕获 ②输出比较 ③PWM生成(边缘或中间对齐模式) ④单脉冲模式输出 - 可使用外部信号(TIMx_ETR)控制定时器和定时器互连(可以用一个定时器控制另外一个定时器)的同步电路
- 如下事件发生时可产生中断/DMA(6个独立的IRQ/DMA请求生成器)
①更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发) ②触发事件(计数器启动、停止、初始化或者由内部/外部触发计数) ③输入捕获 ④输出比较 ⑤支持针对定位的增量(正交)编码器和霍尔传感器电路触发输入作为外部时钟或者按周期的电流管理 - STM32的通用定时器可以被用于:测量输入信号的脉冲长度(输入捕获)或者产生输出波形(输出比较和 PWM)等。
- 使用定时器预分频器和RCC时钟控制器预分频器,脉冲长度和波形周期可以在几个微秒到几个毫秒间调整。STM32的每个通用定时器都是完全独立的,没有互相共享的任何资源。
3.计数器模式
- 向上计数模式:计数器从0计数到自动加载值(TIMx_ARR),然后重新从0开始计数并且产生一个计数器溢出事件。
- 向下计数模式:计数器从自动装入的值(TIMx_ARR)开始向下计数到0,然后从自动装入的值重新开始,并产生一个计数器向下溢出事件。
- 中央对齐模式(向上/向下计数):计数器从0开始计数到自动装入的值-1,产生一个计数器溢出事件,然后向下计数到1并且产生一个计数器溢出事件;然后再从0开始重新计数。
4.通用定时器工作过程 计数器时钟可以由下列时钟源提供: ①内部时钟(CK_INT) 默认调用Systemlnit函数情况下: SYSCLK=72M AHB时钟=72M APB1时钟=36M 所以APB1的分频系数=AHB/APB1时钟=2。所以,通用定时器时钟CK_INT=2*36M=72M ②外部时钟模式1:外部输入脚(TIx) ③外部时钟模式2:外部触发输入(ETR) ④内部触发输入(ITRx):使用一个定时器作为另一个定时器的预分频器,如可以配置一个定时器Timer1而作为另一个定时器Timer2的预分频器。 5.定时器中断实验相关寄存器
6.常用库函数
void TIMx_TimeBaseInit(TIM_TypeDef*TIMx,TIMx_TimeBaseInitTypeDef*TIMx_TimeBaseInitStruct);
typedef struct
{
uint16_t TIM_Prescaler;
uint16_t TIM_CounterMode;
uint16_t TIM_Period;
uint16_t TIM_ClockDivision;
uint8_t TIM_RepetitionCounter;
} TIM_TimeBaseInitTypeDef;
void TIM_Cmd(TIM_TypeDef*TIMx,FunctionalState NewState);
void TIM_ITConfig(TIM_TypeDef*TIMx,unit_16 TIM_IT,FunctionalState NewState);
TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);
7.定时器中断实现步骤
RCC_APB1PeiphClockCmd();
TIM_TimeBaseInit();
void TIM_ITConfig();
NVIC_Init();
TIM_Cmd();
TIMx_IRQHandler();
二、通用定时器PWM概述
1.STM32 PWM工作过程
在输出模式下,TIMx_CCRx寄存器的值与CNT的值比较,若CCRx的值大于CNT的值,则产生高电平,反之则为低电平,故通过修改这个寄存器的值,就可以控制 PWM 的输出脉宽。 以通道1为例: CCR1:捕获比较(值)寄存器(x=1,2,3,4):设置比较值。CCMR1:OC1M[2:0]位: 对于PWM方式下,用于设置PWM模式1【110】或者PWM模式2【111】
CCER:CC1P位:输入/捕获1输出极性。0:高电平有效,1:低电平有效。 CCER:CC1E位:输入/捕获1输出使能。0:关闭,1:打开。
2.相关寄存器
PWM模式:脉冲宽度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号。
在TIMx_CCRx寄存器中的OCxM位写入’110’(PWM模式1)或’111’(PWM模式2),能够独立地设置每个OCx输出通道产生一路PWM。必须设置TIMx_CCMRx寄存器OCxPE位以使能相应的预装载寄存器,最后还要设置TIMx_CR1寄存器的ARPE位,(在向上计数或中心对称模式中)使能自动重装载的预装载寄存器。 void TIM_OC2PreloadConfig(TIM_TypeDefTIMx,uint16_t TIM_OCPreload); void TIM_ARRPreloadConfig(TIM_TypeDefTIMx,FunctionalState NewState); TIMx_CR1寄存器的ARPE位1时,ARR立即生效,APRE=0时,ARR下个比较周期生效。 3.STM32定时器3输出通道引脚
复用功能 | TIM3_REMAP[1:0]=00(没有重映像) | TIM3_REMAP[1:0]=10(部分重映像) | TIM3_REMAP[1:0]=11(完全重映像) |
---|
TIM3_CH1 | PA6 | PB4 | PC6 | TIM3_CH2 | PA7 | PB5 | PC7 | TIM3_CH3 | PB0 | PB0 | PC8 | TIM3_CH4 | PB1 | PB1 | PC9 |
(其他定时器的引脚通过查找Datasheet表格可知) 4.PWM输出库函数
void TIM_OCxInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
typedef struct
{
uint16_t TIM_OCMode;
uint16_t TIM_OutputState;
uint16_t TIM_OutputNState;
uint16_t TIM_Pulse;
uint16_t TIM_OCPolarity;
uint16_t TIM_OCNPolarity;
uint16_t TIM_OCIdleState;
uint16_t TIM_OCNIdleState;
} TIM_OCInitTypeDef;
void TIM_SetCompareX(TIM_TypeDef*TIMx,uint16_t Compare2);
5.PWM输出配置步骤
- 使能定时器3和相关IO口时钟。
使能定时器3时钟:RCC_APB1PeriphClockCmd(); 使能IO口时钟:RCC_APB2PeriphClockCmd(); - 初始化IO口为复用功能输出。函数:GPIO_Init();
GPIO_InitStructure GPIO_Mode=GPIO_Mode_AF_PP; - 这里我们是要把PB5用作定时器的PWM输出引脚,所以要重映射配置,所以需要开启AFIO时钟。同时设置重映射。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_PinRemapConfig(GPIO_PartiaRemap_TIM3,ENABLE); - 初始化定时器:ARR,PSC等:TIM_TimeBaseInit();
- 初始化输出比较参数:TIM_OC2Init();
- 使能预装载寄存器:TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);
- 使能定时器。TIM_Cmd();
- 不断改变比较值CCRx,达到不同的占空比效果:TIM_SetCompare2();
三、输入捕获实验
3-1 输入捕获工作过程
一句话总结工作过程:通过检测TIMx_CHx上的边沿信号,在边沿信号发生跳变(比如上升浴下降沿)的时候,将当前太时器的值(TIMx_CNT)存放到对应的捕获/比较寄存器 (TIMxCCRx)里面,完成一次捕获 1.设置输入捕获滤波器 输入捕获 1 滤波器 IC1F[3:0],这个用来设置输入采样频率和数字滤波器长度。其中,
f
C
L
K
_
I
N
T
f_{CLK\_INT}
fCLK_INT?是定时器的输入频率(TIMxCLK),一般为 72Mhz,而
f
D
T
S
f_{DTS}
fDTS?则是根据 TIMx_CR1 的 CKD[1:0]的设置来定的,如果 CKD[1:0]设置为 00,那么
f
D
T
S
=
f
C
L
K
_
I
N
T
f_{DTS}=f_{CLK\_INT}
fDTS?=fCLK_INT?。N 值就是滤波长度,举个简单的例子:假设 IC1F[3:0]=0011,并设置 IC1 映射到通道 1 上,且为上升沿触发,那么在捕获到上升沿的时候,再以
f
C
L
K
_
I
N
T
f_{CLK\_INT}
fCLK_INT?的频率,连续采样到 8 次通道 1 的电平,如果都是高电平,则说明却是一个有效的触发,就会触发输入捕获中断(如果开启了的话)。这样可以滤除那些高电平脉宽低于 8 个采样周期的脉冲信号,从而达到滤波的效果。 2.设置输入捕获极性(通道1为例) CCER寄存器的位1 3.设置输入捕获映射通道(通道1为例) CCMR1寄存器的位[1:0] 一般情况下通道1就映射到IC1,通道2映射到IC2。 4.设置输入捕获分频器(通道1为例) 5.捕获到有效信号可以开启中断
3-2 输入捕获关键库函数
1.输入捕获通道初始化函数
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);
typedef struct
{
uint16_t TIM_Channel;
uint16_t TIM_ICPolarity;
uint16_t TIM_ICSelection;
uint16_t TIM_ICPrescaler;
uint16_t TIM_ICFilter;
} TIM_ICInitTypeDef;
2.通道极性设置独立函数
void TIM_OCxPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);
跟上面初始化函数中设置通道极性有什么区别呢? 3.获取通道捕获值
uint16_t TIM_GetCapture1(TIM_TypeDef* TIMx);
4.输入捕获配置的一般步骤 ①初始化定时器和通道对应IO的时钟 ②初始化IO口,模式为输入:GPIO_Init(); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPD;//PA0输入 ③初始化定时器ARR,PSC TIM_TimeBaseInit(); ④初始化输入捕获通道 TIM_ICInit(); ⑤如果要开启捕获中断 TIM_ITConfig(); NVC_Init(); ⑥使能定时器:TIM_Cmd(); ⑦编写中断服务函数:TIMx_IRQHandler();
考虑溢出
|