STM32通用定时器学习
写于 2024/8/16 下午
文章目录
1. 通用定时器简介
TIM2/TIM3 /TIM4 /TIM5为F1系列的通用定时器。
- 16位递增、递减、中心对齐计数器(计数值:0~65535)
- 16位预分频器(分频系数:1~65536)
- 可用于触发DAC、ADC
- 在更新事件、触发事件、输入捕获、输出比较时,会产生中断/DMA请求4个独立通道,可用于:输入捕获、输出比较、输出PWM、单脉冲模式使用外部信号控制定时器且可实现多个定时器互连的同步电路支持编码器和霍尔传感器电路等
2. 基本框图
可以看到,在通用定时器内一共由6部分组成,分别为
- 时钟源
- 控制器
- 时基单元
- 输入捕获
- 输入捕获和输出比较公用部分
- 输出比较
通用定时器包含基本定时器的所有功能
2.1 时钟源
通用定时器时钟可以选择下面四类时钟源之一:
- 内部时钟(CK_INT)
- 外部时钟模式 1:外部输入引脚(TIx),x=1,2(即只能来自于通道 1 或者通道 2)
- 外部时钟模式 2:外部触发输入(ETR)
- 内部触发输入(ITRx):使用一个定时器作为另一定时器的预分频器
2.1.1 内部时钟(CK_INT)
相似的,跟基本定时器一样,通用定时器TIM2/TIM3 /TIM4 /TIM5和基本定时器TIM6/TIM7都挂载在APB1总线上,虽然APB1的频率最高为36Mhz,但经过倍频后最大可以达到72Mhz
2.1.2 外部时钟模式 1(TI1、TI2)
外部时钟模式1的输入信号来自定时器的通道1与通道2,通道3与通道4不能作为外部时钟模式的输入信号。时钟源进入定时器的流程如下:外部时钟源信号→IO→TIMx_CH1(或者 TIMx_CH2)。从 IO到 TIMx_CH1(或者 TIMx_CH2),就需要我们配置 IO 的复用功能,才能使 IO 和定时器通道相连通。
信号从TIMx_CH2进入后,通过滤波器整形,由 **ICF[3:0]**位来设置滤波方式
,然后抵达边沿检测器。边沿检测器可以选择上边沿检测或者下边沿检测,使用TIMx_CCER中的CC2P位来设置。
然后经过触发输入选择器,由 TIMx_SMCR的**TS[2:0]**位来选择 TRGI(触发输入信号)的来源。可以看到图 21.1.2 中框出了 TI1F_ED、TI1FP1 和 TI2FP2 三个触发输入信号(TRGI)。TI1F_ED 表示来自于 CH1,并且没有经过边沿检测器过滤的信号,所以它是 CH1 的双边沿信号,即上升沿或者下降沿都是有效的。TI1FP1 表示来自 CH1 并经过边沿检测器后的信号,可以是上升沿或者下降沿。TI2FP2 表示来自 CH2 并经过边沿检测器后的信号,可以是上升沿或者下降沿。
最后经过从模式选择器,由TIMx_SMCR的 ECE 位和 **SMS[2:0]**位来选择定时器的时钟源。这里我们介绍的是外部时钟模式 1,所以 ECE 位置 0,SMS[2:0] = 111 即可。CK_PSC 需要经过定时器的预分频器分频后,最终就能到达计数器进行计数了。
2.1.3 外部时钟模式2(ETR)
外部时钟模式 2,时钟源进入定时器的流程如下:外部时钟源信号→IO→TIMx_ETR。从 IO 到 TIMx_ETR,就需要我们配置 IO 的复用功能,才能使IO 和定时器相连通。
定时器时钟信号首先从 ETR 引脚进来。接着经过外部触发极性选择器,由 ETP 位来设置上升沿有效还是下降沿有效,选择下降沿有效的话,信号会经过反相器。
然后经过外部触发预分频器,由 **ETPS[1:0]**位来设置预分频系数,系数范围:1、2、4、8。
紧接着经过滤波器器,由 **ETF[3:0]**位来设置滤波方式,也可以设置不使用滤波器。fDTS 由TIMx_CR1 寄存器的 CKD 位设置。
最后经过从模式选择器,由 ECE 位和 **SMS[2:0]**位来选择定时器的时钟源。这里我们介绍的是外部时钟模式 2,直接把 ECE 位置 1 即可。CK_PSC 需要经过定时器的预分频器分频后,最终就能到达计数器进行计数了。
2.1.4 内部触发输入(ITRx)
内部触发输入是使用一个定时器作为另一个定时器的预分频器,即实现定时器的级联。下面以 TIM1 作为 TIM2 的预分频器为例。
上图中,TIM1 作为 TIM2 的预分频器,需要完成的配置步骤如下:
1,TIM1_CR2 寄存器的 MMS[2:0]位设置为 010,即 TIM1 的主模式选择为更新(选择更新事件作为触发输(TRGO))。
2,TIM2_SMCR 寄存器的 TS[2:0]位设置为 000,即使用 ITR0 作为内部触发。TS[2:0]位用于配置触发选择,除了 ITR0,还有其他的选择,详细描述如下图所示:
上图中的触发选择中,我们在讲解外部时钟模式 1 的时候说过 TI1F_ED、TI1FP1 和 TI2FP2,以及外部时钟模式 2 讲的 ETRF,它们都是属于外部的,其余的都是内部触发了。
在步骤 2 中,TS[2:0]位设置为 000,使用 ITR0作为内部触发,这个 ITR0 什么意思?由表21.1.3 可以知道,当从模式定时器为 TIM2 时,ITR0 表示主模式定时器就是 TIM1。这里只是TIM2~5 的内部触发连接情况,其他定时器请查看参考手册的相应章节。
3,TIM2_SMCR 寄存器的 SMS[2:0]位设置为 111,即从模式控制器选择外部时钟模式 1。
4,TIM1 和 TIM2 的 CEN 位都要置 1,即启动计数器。
2.2 控制器
控制器包括:从模式控制器、编码器接口和触发控制器(TRGO)。从模式控制器可以控制计数器复位、启动、递增/递减、计数。编码器接口针对编码器计数。触发控制器用来提供触发信号给别的外设,比如为其它定时器提供时钟或者为 DAC/ADC 的触发转换提供信号。
2.3 时基单元
时基单元包括:计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)、自动重载寄存器(TIMx_ARR)。这部分内容和基本定时器基本一样的,不同点在于通用定时器的计数模式有三种:递增计数模式、递减计数模式和中心对齐模式。
2.4 输入捕获
这里是以通道 1 输入捕获为例进行介绍,其他通道同理。待测量信号到达 TIMx_CH1 后,那么这里我们把这个待测量信号用 TI1 表示
TI1 首先经过一个滤波器,由 ICF[3:0]位来设置滤波方式,也可以设置不使用滤波器。fDTS由 TIMx_CR1 寄存器的 CKD 位设置。
接着经过边沿检测器,由 CC1P 位来设置检测的边沿,可以上升沿或者下降沿检测。CC1NP是配置互补通道的边沿检测的,在高级定时器才有,通用定时器没有。
然后经过输入捕获映射选择器,由 CC1S[1:0]位来选择把 IC1 映射到 TI1、TI2 还是 TRC。这里我们的待测量信号从通道 1 进来,所以选择 IC1 映射到 TI1 上即可。
紧接着经过输入捕获 1 预分频器,由 ICPS[1:0]位来设置预分频系数,范围:1、2、4、8。
最后需要把 CC1E 位置 1,使能输入捕获,IC1PS 就是分频后的捕获信号。这个信号将会到达输入捕获和输出比较公用部分
2.4.1 输入捕获测量脉冲宽度
通用定时器输入捕获实验配置步骤
- 配置定时器基础工作参数:
HAL_TIM_IC_Init()
- 定时器输入捕获MSP初始化:
HAL_TIM_IC_MspInit()
配置NVIC、CLOCK、GPIO等 - 配置输入通道映射、捕获边沿等:
HAL_TIM_IC_ConfigChannel()
- 设置优先级,使能中断:
HAL_NVIC_SetPriority()
、HAL_NVIC_EnableIRQ()
- 使能定时器更新中断:
__HAL_TIM_ENABLE_IT()
- 使能捕获、捕获中断及计数器:
HAL_TIM_IC_Start_IT()
- 编写中断服务函数:
TIMx_IRQHandler()
HAL_TIM_IRQHandler()
- 编写更新中断和捕获回调函数:
HAL_TIM_PeriodElapsedCallback()
HAL_TIM_IC_CaptureCallback()
函数 | 主要寄存器 | 主要功能 |
---|---|---|
HAL_TIM_IC_Init() | CR1、ARR、PSC | 初始化定时器基础参数 |
HAL_TIM_IC_MspInit() | 无 | 存放NVIC、CLOCK、GPIO初始化代码 |
HAL_TIM_IC_ConfigChannel() | CCMRx、CCER | 配置通道映射、捕获边沿、分频、滤波等 |
__HAL_TIM_ENABLE_IT() | DIER | 使能更新中断等 |
HAL_TIM_IC_Start_IT() | CCER、DIER、CR1 | 使能输入捕获、捕获中断并启动计数器 |
HAL_TIM_IRQHandler() | SR | 定时器中断处理公用函数,处理各种中断 |
HAL_TIM_PeriodElapsedCallback() | 无 | 定时器更新中断回调函数,由用户重定义 |
HAL_TIM_IC_CaptureCallback() | 无 | 定时器输入捕获回调函数,由用户重定义 |
关键结构体介绍
typedef struct
{
uint32_t ICPolarity; /* 输入捕获触发方式选择,比如上升、下降沿捕获 */
uint32_t ICSelection; /* 输入捕获选择,用于设置映射关系 */
uint32_t ICPrescaler; /* 输入捕获分频系数 */
uint32_t ICFilter; /* 输入捕获滤波器设置 */
} TIM_IC_InitTypeDef;
具体实现源码
timer.c
#include "./BSP/TIMER/timer.h"
TIM_HandleTypeDef g_timer_handle;
void timer_init(