## 一、HC-SR04工作原理与关键时序 HC-SR04采用IO触发-回波测量方式,内部集成超声波发射器、接收器和控制电路。其测距本质是测量超声波从发射到遇障碍物返回的时间差,再乘以声速除以2得到距离。 **核心时序要求:** - 触发信号:至少10μs的高电平脉冲(建议20μs确保稳定) - 回波信号:高电平持续时间与距离成正比 - 测量范围:2cm~400cm,精度理论可达3mm - 声速:常温(20℃)下约343m/s,实际受温度影响显著 距离计算公式: ```c distance_cm = (echo_time_us * 0.0343) / 2; // 简化:distance_cm = echo_time_us / 58.0; ``` ## 二、驱动电路与引脚连接 HC-SR04工作电压5V,但回波输出为5V电平,若MCU为3.3V系统(如STM32),需进行电平转换或分压,避免损坏IO口。 **典型连接(以STM32F103为例):** - VCC → 5V(注意电流约15mA) - GND → GND - Trig → PA0(推挽输出) - Echo → PA1(输入捕获或外部中断) **电平转换方案:** - 使用电阻分压(如1kΩ+2kΩ)将Echo降至3.3V - 或使用电平转换芯片(如TXS0108) ## 三、驱动代码实现(STM32 HAL库) ### 1. 使用输入捕获模式测量脉宽 ```c // 定时器配置:TIM2 CH1(PA0)输入捕获,上升沿+下降沿捕获 void MX_TIM2_Init(void) { TIM_IC_InitTypeDef sConfigIC = {0}; htim2.Instance = TIM2; htim2.Init.Prescaler = 72-1; // 1MHz计数频率,1us分辨率 htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 0xFFFF; // 最大65535us,约1.1m htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_IC_Init(&htim2); sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING; sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI; sConfigIC.ICPrescaler = TIM_ICPSC_DIV1; sConfigIC.ICFilter = 0; // 不滤波 HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1); HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1); __HAL_TIM_ENABLE_IT(&htim2, TIM_IT_CC1); } // 中断回调中测量脉宽 volatile uint32_t echo_start, echo_end, echo_width; volatile uint8_t echo_captured = 0; void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM2) { if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) { if (__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1)) { if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1) == GPIO_PIN_SET) { // 上升沿 echo_start = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_FALLING); } else { // 下降沿 echo_end = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); echo_width = echo_end > echo_start ? (echo_end - echo_start) : (0xFFFF - echo_start + echo_end); echo_captured = 1; __HAL_TIM_SET_CAPTUREPOLARITY(htim, TIM_CHANNEL_1, TIM_INPUTCHANNELPOLARITY_RISING); } } } } } // 触发一次测量 void HCSR04_Trigger(void) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET); delay_us(20); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET); } // 获取距离(单位cm) uint16_t HCSR04_GetDistance(void) { if (echo_captured) { echo_captured = 0; return (uint16_t)(echo_width / 58.0); } return 0xFFFF; // 超时或未捕获 } ``` ### 2. 使用外部中断+定时器计时(替代方案) ```c // 外部中断配置:Echo引脚上升沿触发,开启定时器;下降沿触发,读取定时器值 void EXTI1_IRQHandler(void) { if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_1)) { __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_1); if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1)) { __HAL_TIM_SET_COUNTER(&htim3, 0); HAL_TIM_Base_Start(&htim3); } else { HAL_TIM_Base_Stop(&htim3); echo_width = __HAL_TIM_GET_COUNTER(&htim3); echo_captured = 1; } } } ``` ## 四、精度优化策略 ### 1. 温度补偿 声速随温度变化明显:`v = 331.4 + 0.6 * T`(T为摄氏度)。若环境温度波动大,应使用温度传感器(如DS18B20)实时修正。 ```c float speed_of_sound(float temp_c) { return 331.4f + 0.6f * temp_c; // m/s } uint16_t HCSR04_GetDistanceCompensated(float temp_c) { if (echo_captured) { echo_captured = 0; float dist_m = (echo_width / 1e6f) * speed_of_sound(temp_c) / 2.0f; return (uint16_t)(dist_m * 100); // cm } return 0xFFFF; } ``` ### 2. 多次测量与滤波 单次测量易受噪声干扰,建议连续测量5~10次,去除最大值和最小值后取平均。 ```c #define SAMPLE_COUNT 5 uint16_t HCSR04_GetDistanceFiltered(void) { uint16_t samples[SAMPLE_COUNT]; for (int i = 0; i < SAMPLE_COUNT; i++) { HCSR04_Trigger(); while (!echo_captured); // 等待捕获 samples[i] = HCSR04_GetDistance(); delay_ms(50); // 间隔至少60ms避免余振 } // 冒泡排序去极值 for (int i = 0; i < SAMPLE_COUNT-1; i++) { for (int j = 0; j < SAMPLE_COUNT-i-1; j++) { if (samples[j] > samples[j+1]) { uint16_t tmp = samples[j]; samples[j] = samples[j+1]; samples[j+1] = tmp; } } } uint32_t sum = 0; for (int i = 1; i < SAMPLE_COUNT-1; i++) sum += samples[i]; return (uint16_t)(sum / (SAMPLE_COUNT-2)); } ``` ### 3. 触发间隔控制 超声波模块需要等待余波消散,两次触发间隔应大于60ms(对应最大量程4m的往返时间约23ms,留足余量)。若测量距离较近,可适当缩短,但建议不低于30ms。 ### 4. 测量角度与障碍物特性 - 超声波波束角约15°,障碍物表面应尽量垂直于波束方向,否则回波衰减严重。 - 软质材料(如海绵、布料)吸收超声波,导致测距失败,需考虑替代方案。 - 避免在强气流或风扇附近使用,气流会干扰声波传播。 ## 五、常见问题与注意事项 - **Echo悬空问题**:若未检测到回波,Echo引脚会保持低电平,但模块内部可能输出高电平持续一段时间,需设置超时机制(如200ms)避免程序卡死。 - **电源稳定性**:HC-SR04对电源纹波敏感,建议在VCC和GND之间加100μF电解电容和0.1μF陶瓷电容。 - **多模块干扰**:多个超声波模块同时工作会互相干扰,可采用分时触发或不同频率(但HC-SR04固定40kHz,只能分时)。 - **测量盲区**:2cm以内无法可靠测量,设计时需考虑安装位置。 - **定时器溢出**:若使用16位定时器且分频后计数频率为1MHz,最大测量时间65535μs,对应距离约1.1m,超过则需使用32位定时器或扩展计数。 ## 六、总结 HC-SR04虽然廉价易用,但要做到高精度测量,需从硬件电路、驱动时序、软件滤波和温度补偿等多方面综合优化。本文提供的代码框架可直接应用于STM32等主流MCU,通过输入捕获或外部中断实现精确脉宽测量。实际项目中,建议根据具体场景调整采样策略和滤波算法,并充分测试不同温度、角度下的表现。掌握这些要点,你就能在机器人避障、液位检测等应用中发挥HC-SR04的最大潜力。