简介
对于STM32F407有10个通用定时器,TIM2 ~ TIM5 和 TIM9 ~ TIM14。
主要特性:
- 16位递增、递减、中心对齐计数器(计数值:0~65535)
- 16位预分频器(分频系数:1~65536)
- 可用于触发DAC、ADC
- 在更新事件、触发事件、输入捕获、输出比较时,会产生中断/DMA请求
- 4个独立通道,可用于:输入捕获、输出比较、输出PWM、单脉冲模式
- 使用外部信号控制定时器且可实现多个定时器互连的同步电路
- 支持编码器和霍尔传感器电路等
定时器框图
- 时钟源
通用定时器有4种时钟源
①内部时钟(CK_INT)
②外部时钟模式1:外部输入引脚(TIx),x=1,2(即只能来自于通道 1 或者通道 2)
③外部时钟模式2:外部触发输入(ETR)
④内部触发时钟:使用一个定时器作为另一定时器的预分频器 - 控制器
控制器包括:从模式控制器、编码器接口和触发控制器(TRGO)。从模式控制器可以控制计数器复位、启动、递增/递减、计数。编码器接口针对编码器计数。触发控制器用来提供触发信号给别的外设,比如为其它定时器提供时钟或者为 DAC/ADC 的触发转换提供信号。 - 时基单元
时基单元包括:计数器寄存器(TIMx_CNT)、预分频器寄存器(TIMx_PSC)、自动重载寄存器(TIMx_ARR)。这部分内容和基本定时器基本一样的。
不同点是:通用定时器的计数模式有三种:递增计数模式、递减计数模式和中心对齐模式 - 输入捕获
一般应用是要和第⑤部分一起完成测量功能。
TIMx_CH1~ TIMx_CH4 表示定时器的 4 个通道,这 4 个通道都是可以独立工作的。IO 端口通过复用功能与这些通道相连。配置好 IO 端口的复用功能后,将需要测量的信号输入到相应的IO 端口,输入捕获部分可以对输入的信号的上升沿,下降沿或者双边沿进行捕获,常见的测量有:测量输入信号的脉冲宽度、测量 PWM 输入信号的频率和占空比等。 - 输入捕获和输出比较公用部分
该部分需要结合第④部分或者第⑥部分共同完成相应功能。 - 输出比较
一般应用是要和第⑤部分一起完成定时器输出功能。
TIMx_CH1~ TIMx_CH4 表示定时器的 4 个通道,这 4 个通道都是可以独立工作的。IO 端口通过复用功能与这些通道相连。
时钟源
计数器时钟源寄存器设置方法
内部时钟(CK_INT)
STM32F4 系列的定时器 TIM2/TIM3/TIM4/TIM5/ TIM6/TIM7/ TIM12/ TIM13/ TIM14 都是挂载在 APB1 总线上,当预分频系数≥2时,时钟频率为84Mhz,APB2 总线上挂载的通用定时器 TIM9/TIM10/TIM11,以及高级定时器 TIM1 和 TIM8,同理一般为168Mhz。
外部时钟模式1(TI1\TI2)
TI1F_ED 表示来自于 CH1,并且没有经过边沿检测器过滤的信号,所以它是 CH1 的双边沿信号,即上升沿或者下降沿都是有效的。TI1FP1 表示来自 CH1 并经过边沿检测器后的信号,可以是上升沿或者下降沿。TI2FP2 表示来自 CH2 并经过边沿检测器后的信号,可以是上升沿或者下降沿。
外部时钟模式2(ETR)
定时器时钟信号首先从 ETR 引脚进来。
接着经过外部触发极性选择器,由 ETP 位来设置上升沿有效还是下降沿有效,选择下降沿有效的话,信号会经过反相器。
然后经过外部触发预分频器,由 ETPS[1:0]位来设置预分频系数,系数范围:1、2、4、8。
紧接着经过滤波器器,由 ETF[3:0]位来设置滤波方式,也可以设置不使用滤波器。fDTS 由TIMx_CR1 寄存器的 CKD 位设置。
内部触发输入(ITRx)
内部触发输入是使用一个定时器作为另一个定时器的预分频器,即实现定时器的级联。上图中表示的是TIM1作为TIM2的预分频器。
需要完成以下配置:
- TIM1_CR2 寄存器的 MMS[2:0]位设置为 010,即 TIM1 的主模式选择为更新(选择更新事件作为触发输出 (TRGO))。
- TIM2_SMCR 寄存器的 TS[2:0]位设置为 000,即使用 ITR1 作为内部触发。TS[2:0]位用于配置触发选择,除了 ITR1,还有其他的选择。
- TIM2_SMCR 寄存器的 SMS[2:0]位设置为 111,即从模式控制器选择外部时钟模式 1。
- TIM1 和 TIM2 的 CEN 位都要置 1,即启动计数器。
基本定时器中断实验
实验采用通用计时器TIM3,LE0红灯200ms翻转表示程序正在进行,定时器中断中500ms翻转一次。
- gtim.h
#define GTIM_TIMX_INT TIM3
#define GTIM_TIMX_INT_IRQn TIM3_IRQn
#define GTIM_TIMX_INT_IRQHandler TIM3_IRQHandler
#define GTIM_TIMX_INT_CLK_ENABLE() do{ __HAL_RCC_TIM3_CLK_ENABLE(); }while(0) /* TIM3 时钟使能 */
/****************************************************************************************************/
void gtim_timx_int_init(uint16_t arr, uint16_t psc); /* 通用定时器 定时中断初始化函数 */
- gtim.c
/* 定时器配置句柄 定义 */
TIM_HandleTypeDef g_timx_handle; /* 定时器x句柄 */
/**
* @brief 通用定时器TIMX定时中断初始化函数
* @note
* 通用定时器的时钟来自APB1,当PPRE1 ≥ 2分频的时候
* 通用定时器的时钟为APB1时钟的2倍, 而APB1为42M, 所以定时器时钟 = 84Mhz
* 定时器溢出时间计算方法: Tout = ((arr + 1) * (psc + 1)) / Ft us.
* Ft=定时器工作频率,单位:Mhz
*
* @param arr: 自动重装值
* @param psc: 预分频系数
* @retval 无
*/
void gtim_timx_int_init(uint16_t arr, uint16_t psc)
{
GTIM_TIMX_INT_CLK_ENABLE(); /* 使能TIMx时钟 */
g_timx_handle.Instance = GTIM_TIMX_INT; /* 通用定时器x */
g_timx_handle.Init.Prescaler = psc; /* 预分频系数 */
g_timx_handle.Init.CounterMode = TIM_COUNTERMODE_UP; /* 递增计数模式 */
g_timx_handle.Init.Period = arr; /* 自动装载值 */
HAL_TIM_Base_Init(&g_timx_handle);
HAL_NVIC_SetPriority(GTIM_TIMX_INT_IRQn, 1, 3); /* 设置中断优先级,抢占优先级1,子优先级3 */
HAL_NVIC_EnableIRQ(GTIM_TIMX_INT_IRQn); /* 开启ITMx中断 */
HAL_TIM_Base_Start_IT(&g_timx_handle); /* 使能定时器x和定时器x更新中断 */
}
/**
* @brief 定时器中断服务函数
* @param 无
* @retval 无
*/
void GTIM_TIMX_INT_IRQHandler(void)
{
/* 以下代码没有使用定时器HAL库共用处理函数来处理,而是直接通过判断中断标志位的方式 */
if(__HAL_TIM_GET_FLAG(&g_timx_handle, TIM_FLAG_UPDATE) != RESET)
{
LED1_TOGGLE();
__HAL_TIM_CLEAR_IT(&g_timx_handle, TIM_IT_UPDATE); /* 清除定时器溢出中断标志位 */
}
}
- main.c
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟,168Mhz */
delay_init(168); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
gtim_timx_int_init(5000 - 1, 8400 - 1); /* 84 000 000 / 84 00 = 10 000 10Khz的计数频率,计数5K次为500ms */
while(1)
{
LED0_TOGGLE(); /* LED0(红灯) 翻转 */
delay_ms(200);
}
}