STM32F1 系列中,除了一些特殊的型号,大部分F1有8 个定时器,分为基本定时器,通用定时器和高级定时器。
基本定时器TIM6 和TIM7 是一个16 位的只能向上计数的定时器,只能定时,没有外部IO。
通用定时器TIM2/3/4/5 是一个16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,每个定时器有四个外部IO。
高级定时器TIM1/8 是一个16 位的可以向上/下计数的定时器,可以定时,可以输出比较,可以输入捕捉,还可以有三相电机互补输出信号,每个定时器有8 个外部IO。
定时器 | 计数器 | 计数器类型 | 预分频系数 | 产生DMA | 捕获/比较通道 | 互补通道 | |
---|---|---|---|---|---|---|---|
高级定时器 | TIM1 | 16位 | 向上/向下 | 1 ~ 65535 | 可以 | 4 | 有 |
高级定时器 | TIM8 | 16位 | 向上/向下 | 1 ~ 65535 | 可以 | 4 | 有 |
通用定时器 | TIM2 | 16位 | 向上/向下 | 1 ~ 65535 | 可以 | 4 | 没有 |
通用定时器 | TIM3 | 16位 | 向上/向下 | 1 ~ 65535 | 可以 | 4 | 没有 |
通用定时器 | TIM4 | 16位 | 向上/向下 | 1 ~ 65535 | 可以 | 4 | 没有 |
通用定时器 | TIM5 | 16位 | 向上/向下 | 1 ~ 65535 | 可以 | 4 | 没有 |
基本定时器 | TIM6 | 16位 | 向上 | 1 ~ 65535 | 可以 | 0 | 没有 |
基本定时器 | TIM7 | 16位 | 向上 | 1 ~ 65535 | 可以 | 0 | 没有 |
定时器时钟TIMxCLK,即内部时钟CK_INT,经APB1 预分频器后分频提供,如果APB1 预分频系数等于1,则频率不变,否则频率乘以2,库函数中APB1 预分频的系数是2,即PCLK1=36M,所以定时器时钟TIMxCLK=36*2=72M。
定时器时钟经过PSC 预分频器之后,即计数器时钟CK_CNT,用来驱动计数器计数。PSC 是一个16 位的预分频器,可以对定时器时钟TIMxCLK 进行1~65536 之间的任何一个数进行分频。具体计算方式为:CK_CNT=TIMxCLK/(PSC+1)。
计数器CNT 是一个16 位的计数器,只能往上计数,最大计数值为65535。当计数达到自动重装载寄存器的时候产生更新事件,并清零从头开始计数。
自动重装载寄存器ARR 是一个16 位的寄存器,这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。
定时器的定时时间等于计数器的中断周期乘以中断的次数。计数器在CK_CNT 的驱动下,计一个数的时间则是CK_CNT 的倒数,等于:1/(TIMxCLK/(PSC+1)),产生一次中断的时间则等于:(1/CK_CNT) * (ARR+1)。如果在中断服务程序里面设置一个变量time,用来记录中
断的次数,那么就可以计算出我们需要的定时时间等于:(1/CK_CNT) * (ARR+1) *(PSC+1)。
Time = (ARR+1) * (PSC+1) / Tclk
ARR为自动装载值
PSC:预分频系数
Tclk:定时器的APB时钟,通常等于系统时钟
例如:
Tclk为72M、PSC(预分频系数)为7199、ARR(自动重装载值)为9999
Time = (ARR+1) * (PSC+1) / Tclk = (9999+1) * (7199+1) / 72 000 000 = 1s
向上计数
计数器从0向上计数(递增)到自动装载值,然后再次回到0开始计数,并产生一个计数溢出事件
向下计数
计数器从自动装载值向下计数(递减)到0,然后再次回到自动装载值开始计数,并产生一个计数器向下溢出事件
中央对齐模式(向上/向下计数)
计数器从0开始计数到自动装载值-1,并产生一个计数器溢出事件,然后再向下计数到0+1,并产生一个计数溢出事件,然后再向上计数。
基本的STM32Cube MX的配置可以参考这篇博客:STM32 CubeMx教程 – 基础知识及配置使用教程
配置RCC 时钟,配置为外部晶振模式
配置SYS Debug 设置为 Serial Wire
配置一个串口,用来输出调试信息
配置 TIM2 ,TIM2是通用定时器,配置时钟源为内部时钟 其余设置目前用不到,暂时不配置
Slave Mode:从模式选择。
对应从模式控制寄存器(TIMx_SMCR)中的SMS[2:0]位。所有TIMx定时器在内部相连,用于定时器同步或链接。当一个定时器处于主模式时,可以对另一个处于从模式的定时器的计数器进行复位、启动、停止或提供时钟等操作。
000 - 关闭从模式,预分频器直接由内部时钟驱动。
001/010/011-编码器模式。
100 - 复位模式,选中的触发输入(TRGI)的上升沿重新初始化计数器,并产生一个更新寄存器的信号。
101 - 门控模式,当触发输入(TRGI)为高时,计数器的时钟开启;一旦触发输入变为低,则计数器停止(但不复位)。计数器的启动和停止受触发输入信号控制。
110 - 触发模式,计数器在触发输入(TRGI)的上升沿启动(但不复位),只有计数器的启动是受控的。
111 - 外部时钟模式1,选中的触发输入(TRGI)的上升沿驱动计数器。
Trigger Source:从模式触发选择。
对应从模式控制寄存器(TIMx_SMCR)中的TS[2:0]位。用于选择同步计数器的触发输入。
000 - 内部触发0(ITR0),TIM1
001 - 内部触发1(ITR1),TIM2
010 - 内部触发2(ITR2),TIM3
011 - 内部触发3(ITR3),TIM4
100 - TI1的边沿检测器(TI1F_ED)
101 - 滤波后的定时器输入1(TI1FP1)
110 - 滤波后的定时器输入2(TI2FP2)
111 - 外部触发输入(ETRF)
Clock Source:外部时钟源。
对应从模式控制寄存器(TIMx_SMCR)中的ECE位。Internal Clock 内部时钟 、ETR2 外部触发输入(ETR)(仅适用TIM2,3,4)
Channel1 ~ Channel4:输出比较 1 ~ 4 模式设置。
对应捕获/比较模式寄存器1和2中的)OCxM[2:0]位。包含输入捕获、输出比较、PWM生成、强制输出等。
Combined Channels:组合通道模式。
编码器模式下需要进行配置。
Use ETR as Clearing Source:输出比较清零使能。
对应捕获/比较模式寄存器1和2中的OCxCE位。一旦检测到ETR电平为高,清除OCxREF。
XOR activation:输入异或模式。 只在输入时有效。
One Pulse Mode:单脉冲模式。 对应控制寄存器1中的OPM位
配置TIM2 里面的详细参数,预分频系数设置为7199,重装载值设置为9999,使能自动重装载,从属模式基本不用,所以下面的参数默认就行;
定时时间: Time = (ARR+1) * (PSC+1) / Tclk = (重装载值+1)(预分频系数+1)/ 时钟频率 = (7199+1) (9999+1)/ 72 000 000 = 1s
设定定时器的定时时间为1s
Prescaler:预分频系数;
对应预分频器(TIMx_PSC)的PSC[15:0]位。设置预分频器的值。
Counter Mode:计数模式;
对应控制寄存器1(TIMx_CR1)中的DIR位。up 向上、down 向下、Center Aligned mode 中心对齐模式
Counter Period:重装载值;
对应自动重装载寄存器(TIMx_ARR)中的ARR[15:0]。存储将要传送至实际的自动重装载寄存器的数值。
Internal Clock Division:内部时钟分频;
对应控制寄存器1(TIMx_CR1)中的CKD[1:0]位。时钟分频因子。定义在定时器时钟频率与数字滤波器使用的采样频率之间的分频比例。
auto-reload preload:自动重装载;
对应控制寄存器1(TIMx_CR1)中的ARPE位。自动重装载预装载允许位。定义在TIMx_ARR和实际的自动重装载寄存器之间是否设置缓冲器。
Master/Slave Mode: 对应从模式控制寄存器(TIMx_SMCR)中的MSM位。
Trigger Event Selection: 对应控制寄存器2(TIMx_CR2)中的MMS[2:0]位。用于选择在主模式下送到从定时器的同步信息(TRGO)。
配置中断
配置时钟树
如果使用串口发送信息,需要串口重定向,STM32 HAL库 使用printf函数 Use MicroLIB配置,在usart.c 里面进行串口重定向
HAL_TIM_Base_Start_IT(&htim2); //开启中断
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim); //中断回调函数
代码示例:
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM2_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2); //开启定时器中断,在main函数里面初始化
/* USER CODE END 2 */
/* USER CODE BEGIN 4 */
/* 在main.c 或者在 tim.c 里面都可以写 */
/* 定时器中断回调函数,达到定时器所设定的时间以后,进入中断 */
/* 在退出中断的时候就会调用中断回调函数 */
/* 一般在这里写要执行的操作 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance == htim2.Instance)
{
HAL_GPIO_TogglePin(GPIOA ,GPIO_PIN_8); //翻转电平,LED翻转
printf("Enter TIM interrupt \r\n"); //输出执行信息
}
}
/* USER CODE END 4 */
本文中所使用的程序:STM32 HAL库 定时器外部中断