不用输入捕获也能玩转HC-SR04?STM32F103C8T6通用定时器+外部中断实现超声波测距

张开发
2026/4/7 14:05:19 15 分钟阅读

分享文章

不用输入捕获也能玩转HC-SR04?STM32F103C8T6通用定时器+外部中断实现超声波测距
STM32F103C8T6通用定时器外部中断实现HC-SR04超声波测距的替代方案在嵌入式开发中HC-SR04超声波测距模块因其低成本和高可靠性被广泛应用。传统方案多采用定时器的输入捕获功能来测量Echo引脚的高电平时间但当定时器通道资源紧张时这种方案就显得捉襟见肘。本文将介绍一种基于通用定时器和外部中断的替代实现方案为开发者提供更多选择。1. 方案对比输入捕获 vs 外部中断定时器1.1 输入捕获方案的特点输入捕获是STM32定时器提供的一种专门用于测量脉冲宽度或频率的功能。其优势在于硬件自动记录当指定边沿触发时硬件自动记录当前定时器计数值高精度直接读取定时器计数器理论精度可达1微秒72MHz主频下双通道模式可配置一个通道捕获上升沿另一个通道捕获下降沿但这种方法也存在明显局限占用定时器资源需要至少两个输入捕获通道配置复杂需要处理定时器溢出、滤波等细节灵活性低当定时器通道已被其他功能占用时无法使用1.2 外部中断定时器方案的优势本方案采用GPIO外部中断检测Echo信号边沿配合通用定时器计时具有以下特点特性外部中断定时器方案输入捕获方案定时器要求任意通用定时器需支持输入捕获通道占用不占用定时器通道占用1-2个通道实现复杂度中等较高适用场景定时器资源紧张定时器资源充足理论精度1微秒1微秒关键优势在于仅需一个未被占用的通用定时器在资源受限情况下特别有价值。2. 硬件设计与配置2.1 HC-SR04模块基础HC-SR04模块有4个引脚VCC5V电源输入GND地线Trig触发信号输入至少10μs高电平Echo回响信号输出高电平持续时间与距离成正比测量原理向Trig发送至少10μs的高电平脉冲模块自动发送8个40kHz超声波脉冲模块检测回波并通过Echo输出高电平高电平持续时间tμs与距离dcm关系d t × 0.0172.2 STM32F103C8T6连接方案典型连接方式// 引脚定义 #define TRIG_PIN GPIO_PIN_7 #define TRIG_PORT GPIOA #define ECHO_PIN GPIO_PIN_0 #define ECHO_PORT GPIOB // 定时器选择任意通用定时器 #define MEASURE_TIM TIM2Trig引脚配置为推挽输出Echo引脚配置为浮空输入并启用外部中断。3. 软件实现详解3.1 初始化配置首先需要初始化相关外设void Ultrasonic_Init(void) { // 1. Trig引脚初始化推挽输出 GPIO_InitTypeDef GPIO_InitStruct {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin TRIG_PIN; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(TRIG_PORT, GPIO_InitStruct); // 2. Echo引脚初始化外部中断 __HAL_RCC_GPIOB_CLK_ENABLE(); GPIO_InitStruct.Pin ECHO_PIN; GPIO_InitStruct.Mode GPIO_MODE_IT_RISING_FALLING; GPIO_InitStruct.Pull GPIO_NOPULL; HAL_GPIO_Init(ECHO_PORT, GPIO_InitStruct); // 3. 配置外部中断 HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI0_IRQn); // 4. 定时器初始化1MHz计数频率 __HAL_RCC_TIM2_CLK_ENABLE(); TIM_HandleTypeDef htim2; htim2.Instance MEASURE_TIM; htim2.Init.Prescaler 72-1; // 72MHz/72 1MHz htim2.Init.CounterMode TIM_COUNTERMODE_UP; htim2.Init.Period 0xFFFFFFFF; htim2.Init.ClockDivision TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(htim2); HAL_TIM_Base_Start(htim2); }3.2 测量流程实现完整的距离测量包含以下步骤发送触发脉冲void Send_Trigger_Pulse(void) { HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_SET); Delay_us(20); // 20μs触发脉冲 HAL_GPIO_WritePin(TRIG_PORT, TRIG_PIN, GPIO_PIN_RESET); }外部中断处理volatile uint32_t rise_time 0, fall_time 0; volatile uint8_t measure_done 0; void EXTI0_IRQHandler(void) { if(__HAL_GPIO_EXTI_GET_IT(ECHO_PIN) ! RESET) { if(HAL_GPIO_ReadPin(ECHO_PORT, ECHO_PIN) GPIO_PIN_SET) { // 上升沿 rise_time __HAL_TIM_GET_COUNTER(htim2); // 改为下降沿触发 EXTI-FTSR | ECHO_PIN; EXTI-RTSR ~ECHO_PIN; } else { // 下降沿 fall_time __HAL_TIM_GET_COUNTER(htim2); measure_done 1; // 恢复为上升沿触发 EXTI-RTSR | ECHO_PIN; EXTI-FTSR ~ECHO_PIN; } __HAL_GPIO_EXTI_CLEAR_IT(ECHO_PIN); } }距离计算float Get_Distance(void) { Send_Trigger_Pulse(); // 等待测量完成超时处理 uint32_t timeout HAL_GetTick() 100; while(!measure_done HAL_GetTick() timeout); if(measure_done) { measure_done 0; uint32_t pulse_width (fall_time rise_time) ? (fall_time - rise_time) : (0xFFFFFFFF - rise_time fall_time); return pulse_width * 0.017f; // 单位cm } return -1; // 测量失败 }3.3 关键点解析定时器溢出处理 由于使用32位定时器在72MHz主频下需要约59.6秒才会溢出远大于HC-SR04的最大测量周期约33ms因此无需特别处理溢出情况。若使用16位定时器则需要记录溢出次数。中断响应时间影响 外部中断的响应时间会引入少量误差通常1μs对于超声波测距cm级精度可以忽略。滤波处理 Echo信号可能包含毛刺可通过以下方式增强稳定性硬件滤波在Echo引脚添加100nF电容软件滤波连续测量多次取中值4. 性能优化与实践建议4.1 精度提升技巧定时器时钟源使用内部时钟HSI而非外部晶振HSE可避免晶振漂移影响中断优先级提高EXTI中断优先级减少其他中断的干扰温度补偿声速随温度变化可加入温度传感器进行补偿4.2 常见问题排查测量值不稳定检查电源是否稳定推荐5V线性稳压确保测量表面平整且面积足够添加适当的测量间隔建议≥60ms无返回信号确认Trig脉冲宽度足够10-50μs检查Echo引脚连接和外部中断配置测试模块是否正常工作直接给Trig发脉冲观察Echo响应4.3 扩展应用本方案稍作修改即可用于其他脉冲宽度测量场景如红外测距传感器舵机PWM信号解析旋转编码器信号处理通过灵活组合外部中断和定时器开发者可以在资源受限情况下实现多种测量功能。

更多文章