mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
1827 字
5 分钟
STM32-07:TIM定时器-外部时钟和从模式
2026-07-23
2026-07-24

定时器除了使用内部时钟线(APB1/APB2)的电平信号进行计数,还能通过GPIO口引入外部信号,通过外设输出的电平信号进行计数。
本文中,采用TCRT5000(红外反射光电开关),作为外部信号的输入。


外部输入信号线#

ETR(外部触发器)经过极性选择边沿检测预分频输入滤波

  • 极性选择:可将上升沿下降沿互换;
  • 边沿检测:只能进行上升沿检测,但可以搭配极性选择实现下降沿检测;
  • 预分频:降低ETR的频率;
  • 输入滤波:过滤抖动信号,在CubeMX设置的Trigger Filter即是在设置此功能。

之后分为两支:

  • ETR2:直接抵达触发控制器,属于外部时钟模式2,作为外部时钟源
  • ETR1:连接到触发器后经过选择再连接到从模式控制器,属于外部时钟模式1,作为从模式的一种输入信号。

以STM32F103为例,每个定时器有四个输入信号,TI1TI4(TIM Input),其中TI1TI2与触发控制器有关;
每条TI信号线会依次经过输入滤波器边沿检测器

  • 输入滤波器:过滤抖动信号;
  • 边沿检测器:可设置为上升沿触发或者下降沿触发,此外还能设置为双边沿触发,检测到上升沿/下降沿时输出一个脉冲信号。

之后会继续分出TI1FP1TI1FP2TI2FP1TI2FP2,以及TI1_ED
其中TI1FP1TI2FP2TI1_EDETR1共同接入到一个触发器,并选择其中一个信号接入到触发控制器中的从模式控制器,作为输入信号。
其中,TI1_ED固定只能为双边触发


模式选择#

在左侧Timers中选择TIM2,在右侧Mode中对模式进行配置:

外部时钟#

  • 外部时钟模式2:从GPIO口中获取外设发出的高低电平信号,并将其用于控制计数器。

从模式#

Slave Mode中选择不同的模式:

  • 外部时钟模式1(External Clock Mode 1):与外部时钟模式2基本一致;
  • 复位模式(Reset Mode):输入信号上升沿/下降沿时对计数器的寄存器进行复位,并触发定时器更新中断(在中断模式下);
  • 门模式(Gated Mode):出现上升沿时开始计数,出现下降沿时停止计数,即仅在高电平时进行计数,若启用下降沿触发则反之:仅在低电平时进行计数;
  • 触发模式(Trigger Mode):当输入信号为高电平时,开始计数;但由于无法主动停止计数,因此通常搭配单脉冲模式(One Pulse Mode)使用:启用后,在重装载后会停止计时;

Trigger Source中可选择不同的外部输入信号线。

更多设置#

  • Trigger Polarity:设置上升沿触发/下降沿触发/双边沿触发;
  • Trigger Filter:脉冲滤波设置,建议设置为15。

中断回调与寄存器#

自动重装载寄存器或者从模式控制器触发定时器更新中断时,会将状态寄存器中更新中断标志位置1,而从模式控制器接收到触发信号后,还会将触发器中断标志位(TIM_FLAG_TRIGGER) 置1;
借由此,我们可以判断是自动重装载寄存器导致的复位,还是从模式控制器导致的复位,进而做出不同的反应。


代码配置#

基础计数#

目的:TCTR5000每次检测到变化时,将其存入定时器TIM2的计数器并通过串口发送回上位机。

在CubeMX中,为Clock Source选择ETR2,或者Slave Mode选择External Clock Mode1并在Trigger Source中选择ETR1TI1_EDTI1FP1TI2FP2Prescaler则设置为0Trigger Filter设置为15
通过宏函数__HAL_TIM_GET_COUNTER直接读取计数器寄存器中的数值,若产生变化,则通过USRT2串口将其返回上位机:

HAL_TIM_Base_Start(&htim2);
int counter=0,counter_temp=-1;
char message[20]="";
while (1)
{
/*Counter*/
counter=__HAL_TIM_GET_COUNTER(&htim2);
if(counter!=counter_temp){
counter_temp=counter;
sprintf(message, "counter:%d",counter);
HAL_UART_Transmit_IT(&huart2, message, strlen(message));
}
}

将手指反复扫过TCTR5000,可以在串口助手中看到counter数值的递增:

从模式-复位模式#

目的:定时器连接内部时钟正常计时,TCTR5000每次检测到变化时,将计数器重置。

在CubeMX中,为Slave Mode选择Reset Mode
在死循环中写入以下代码块,以显示counter计数:

while(1)
{
/*Reset Mode*/
counter=__HAL_TIM_GET_COUNTER(&htim2);
sprintf(message, "counter:%d",counter);
HAL_UART_Transmit_IT(&huart2, (uint8_t*)message, strlen(message));
HAL_Delay(500);
}

复位模式会使用定时器更新中断回调函数,因此我们对其进行重定义,并且使用宏函数__HAL_TIM_GET_FLAG来确定是自动重装载寄存器还是从模式控制器导致的复位:

/*Reset Mode*/
static const char *message_reload_auto="Reloaded(Auto).\n";
static const char *message_reload_manual="Reloaded(Manual).\n";
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if(htim==&htim2){
if(__HAL_TIM_GET_FLAG(htim,TIM_FLAG_TRIGGER)==SET){
__HAL_TIM_CLEAR_FLAG(htim, TIM_FLAG_TRIGGER);
HAL_UART_Transmit_IT(&huart2, (uint8_t*)message_reload_manual,strlen(message_reload_manual));
return;
}else{
HAL_UART_Transmit_IT(&huart2, (uint8_t*)message_reload_auto,strlen(message_reload_auto));
return;
}
}
}

TIM_FLAG_TRIGGER并不会自动清零,因此在__HAL_TIM_GET_FLAG之后需要立刻将其清零,以防止之后误判。

从模式-门模式#

目的:仅当TCTR5000输出高电平时计时,否则停止计数。

在CubeMX中,为Slave Mode选择Gated Mode
门模式下,出现上升沿和下降沿均会将触发器中断标志置1,而并不会触发定时器更新中断,因此在定时器更新中断中对TIM_FLAG_TRIGGER操作毫无意义,将此段逻辑移动至while(1)中:

while (1)
{
/* Gated Mode */
const char *message_gate="Gated Mode triggered.\n";
if(__HAL_TIM_GET_FLAG(&htim2,TIM_FLAG_TRIGGER)==1){
__HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_TRIGGER);
HAL_UART_Transmit_IT(&huart2, (uint8_t*)message_gate, strlen(message_gate));
}
counter=__HAL_TIM_GET_COUNTER(&htim2);
sprintf(message, "counter:%d",counter);
HAL_UART_Transmit_IT(&huart2, (uint8_t*)message, strlen(message));
HAL_Delay(500);
}

并删除定时器更新中断中的多余内容:

/* Gated Mode/Trigger Mode */
static const char *message_reload_auto="Reloaded(Auto).\n";
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim){
if(htim==&htim2){
HAL_UART_Transmit_IT(&huart2, (uint8_t*)message_reload_auto,strlen(message_reload_auto));
return;
}
}

从模式-触发模式#

目的:TCTR5000输出高电平时开始计时,计时达到自动重装载寄存器后归零并停止,等待下一次TCTR5000输出高电平。

在CubeMX中,为Slave Mode选择Trigger Mode,并为One Pulse Mode打勾,这样计数器在归零后会自动停止;
代码与门模式基本相同:

while (1)
{
/* Trigger Mode */
const char *message_trigger="Trigger Mode triggered.\n";
if(__HAL_TIM_GET_FLAG(&htim2,TIM_FLAG_TRIGGER)==1){
__HAL_TIM_CLEAR_FLAG(&htim2,TIM_FLAG_TRIGGER);
HAL_UART_Transmit_IT(&huart2, (uint8_t*)message_trigger, strlen(message_trigger));
}
counter=__HAL_TIM_GET_COUNTER(&htim2);
sprintf(sendBuffer, "counter:%d",counter);
HAL_UART_Transmit_IT(&huart2, (uint8_t*)sendBuffer, strlen(sendBuffer));
HAL_Delay(500);
}

总结#

相关函数#

__HAL_TIM_GET_FLAG(__HANDLE__, __FLAG__);//读取触发器中断标志位
__HAL_TIM_CLEAR_FLAG(__HANDLE__, __FLAG__);//清除触发器中断标志位

外部时钟模式#

  • 外部时钟模式2:从GPIO口中获取外设发出的高低电平信号,并将其用于控制计数器。

从模式#

  • 外部时钟模式1(External Clock Mode 1):与外部时钟模式2基本一致;
  • 复位模式(Reset Mode):输入信号上升沿/下降沿时对计数器的寄存器进行复位,并触发定时器更新中断(在中断模式下);
  • 门模式(Gated Mode):出现上升沿时开始计数,出现下降沿时停止计数,即仅在高电平时进行计数,若启用下降沿触发则反之:仅在低电平时进行计数;
  • 触发模式(Trigger Mode):当输入信号为高电平时,开始计数;但由于无法主动停止计数,因此通常搭配单脉冲模式(One Pulse Mode)使用:启用后,在重装载后会停止计时;
STM32-07:TIM定时器-外部时钟和从模式
https://nf3eb.github.io/posts/stm32/stm32-07/
作者
NF3eb
发布于
2026-07-23
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录