mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3mobile wallpaper 4
967 字
3 分钟
STM32-08:TIM定时器-输入捕获模式
2026-07-25
2026-07-27

在输入捕获模式下,当边沿来临时,可以将计数器的数值记录到捕获寄存器当中,记录边沿的发生时刻。


输入捕获模式#

输入捕获模式下,输入通道会经过一个预分频器后连接到捕获寄存器上。当定时器输入通道检测到上升沿(或下降沿)时,立即将此时计数器的数值记录到捕获寄存器中。若为此捕获开启了中断,则还会触发输入捕获中断

但是,此处的边沿检测器只能检测上边沿或者下边沿,不能双边沿检测。但是,借助输入捕获的直接模式间接模式,我们可以实现记录一条信号线上的上升沿与下降沿:

  • TI1从边沿检测器会输出TI1FP1TI1FP2,其中TI1FP1连接到捕获寄存器1,而TI1FP2连接到捕获寄存器2
  • TI2从边沿检测器会输出TI2FP1TI2FP2,同样地TI2FP1连接到捕获寄存器1TI2FP2连接到捕获寄存器2

TI1在自己的捕获寄存器1上进行输入捕获就是直接模式,而在捕获寄存器2上进行输入捕获就是间接模式
借助直接模式间接模式,我们就可以实现一个GPIO口的信号在两个端口进行捕获,间接地实现了双边沿检测。

当然,除了TI1和TI2这一对输入信号可以互相借用对方的捕获寄存器,TI3和TI4也有相同的机制。


芯片配置#

本文章中使用HC-SR04超声波模块,最终显示超声波测距的结果。

分析:HC-SR04在接收到电平脉冲后会发送超声波,然后检测反射回来的超声波。发射超声波时会将输出电平信号拉高,而接收到超声波时会将输出电平信号拉低,因此只要通过定时器的输入捕获模式,得知拉高和拉低的时间戳,再通过简单的计算,便可得到距离。

  1. Clock Configuration中将HCLK改为72MHz;
  2. 在CubeMX左侧Timers中点开TIM1,选择Internal Clock,并将Channel3设置为Input Capture direct mode(输入捕获直接模式),Channel 4设置为Input Capture indirect mode(输入捕获间接模式)。;
  3. 在下方的设置中,将Prescaler设置为72-1,即每1微秒,计数器+1;
  4. 在更下方的Input Capture Channel 4中,需要将Polarity Selection更改为Falling Edge,用于在下降沿时记录计数器的值;
  5. 此外,还需要用到中断用于获取数据信息,因此在NVIC中将TIM1 capture compare interrupt启用;
  6. 最后,再单独设置一个GPIO口为GPIO_Output用于发送脉冲启动HC-SR04模块。

代码配置#

函数HAL_TIM_IC_StartHAL_TIM_IC_Start_IT用于启用输入捕获:

HAL_TIM_Base_Start(&htim1);
HAL_TIM_IC_Start(&htim1, TIM_CHANNEL_3);
HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_4);

其中HAL_TIM_IC_Start(&htim1, TIM_CHANNEL_3)

  • &htim1:启用的定时器的句柄;
  • TIM_CHANNEL_3:启用的定时器的通道。

捕获中断回调函数是HAL_TIM_IC_CaptureCallback,我们将其重定义,用于对数据进行处理:

#define SPEED 0.34
bool is_mesuring = false;
int up_edge_timestamp=0,down_edge_timestamp=0;
struct{
int integer;
int floating;
}distance={
.integer=0,
.floating=0
};
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim){
if((htim==&htim1) && ((htim->Channel)==HAL_TIM_ACTIVE_CHANNEL_4)){
up_edge_timestamp=HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_3);
down_edge_timestamp=HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_4);
distance.integer=(int)(((down_edge_timestamp-up_edge_timestamp)*SPEED)/2.0);
distance.floating=(int)(((((down_edge_timestamp-up_edge_timestamp)*SPEED)/2.0)-distance.integer)*100);//保留两位小数
is_mesuring=false;
return;
}
}

在死循环中实现向HC-SR04发送脉冲以测距,以及将测距结果显示在OLED屏幕上:

char sendBuffer[20]="";
while (1)
{
if (is_mesuring==false){
HAL_GPIO_WritePin(Trigger_GPIO_Port, Trigger_Pin, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(Trigger_GPIO_Port, Trigger_Pin, GPIO_PIN_RESET);
__HAL_TIM_SET_COUNTER(&htim1, 0);
is_mesuring=true;
}
OLED_NewFrame();
sprintf(sendBuffer,"distance:%d.%d",distance.integer,distance.floating);
OLED_PrintString(0, 0, sendBuffer, &font16x16, OLED_COLOR_NORMAL);
OLED_ShowFrame();
}
TIP

在发送脉冲后,使用__HAL_TIM_SET_COUNTER(&htim1, 0);立即将计数器归零,可以防止下降沿数值比上升沿数值小。


总结#

相关函数#

HAL_TIM_IC_Start(TIM_HandleTypeDef *htim, uint32_t Channel);//输入捕获模式启动
HAL_TIM_IC_Start_IT(TIM_HandleTypeDef *htim, uint32_t Channel);//输入捕获模式启动(中断模式)
HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim);//输入捕获中断回调函数

输入捕获模式#

在输入捕获模式下,当边沿来临时,可以将计数器的数值记录到捕获寄存器当中,记录边沿的发生时刻。

STM32-08:TIM定时器-输入捕获模式
https://nf3eb.github.io/posts/stm32/stm32-08/
作者
NF3eb
发布于
2026-07-25
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时

目录