基于STM32F103c8T6 HAL库与定时器中断的HC-SR04超声波测距实战
1. 超声波测距原理与硬件选型第一次接触超声波测距时我和很多初学者一样好奇这个小模块怎么就能测出距离呢后来拆解了几个项目才明白HC-SR04的工作原理其实特别像蝙蝠的声波定位。模块的Trig引脚就像我们的嘴巴发出声音Echo引脚则是耳朵接收回音。当给Trig引脚一个10μs以上的高电平脉冲时模块内部会发射8个40kHz的超声波脉冲这个频率刚好是人耳听不到的超声波范围。实际项目中我对比过几款超声波模块发现HC-SR04有三大优势首先是价格亲民某宝上不到10元其次是测量范围2cm-400cm完全够用最后是精度误差能控制在3mm左右。不过要注意的是模块的测量角度是15度锥形区域这意味着如果被测物体表面不平整可能会影响测量结果。有次我在智能小车项目里就遇到过这个问题后来通过调整模块安装角度解决了。说到STM32F103C8T6的选择这块蓝色小板子堪称性价比之王。72MHz主频的Cortex-M3内核内置定时器资源丰富特别适合处理需要精确计时场景。记得当时为了选型我还特意对比了Arduino方案发现STM32的定时器中断响应速度比Arduino的微秒级延时更可靠尤其当测量距离超过2米时优势更加明显。2. 定时器中断的精准时间捕获定时器配置是超声波测距的核心难点这里我踩过不少坑。最初尝试用SysTick做计时发现误差能达到厘米级。后来改用TIM2定时器效果立竿见影。具体配置时要注意三个关键参数首先是预分频值(Prescaler)STM32的时钟树决定了APB1总线时钟是72MHz我们设置71的分频系数实际是72分频得到1MHz的计数频率每个计数正好对应1微秒。中断服务函数的编写也有讲究。第一次实现时我直接在回调函数里累加计数结果发现当测量距离超过65cm时就会出错。这是因为16位定时器的自动重载值(Period)最大只能设置65535对应65.535ms。解决方案是定义overcount变量记录溢出次数配合当前计数值就能实现32位时间测量。实测这个方案在4米量程内都能稳定工作。注意HAL库的中断回调函数需要放在stm32f1xx_it.c文件外定义否则会被默认的空函数覆盖。这个细节官方文档没强调我调试了整整一晚上才发现。3. 完整工程代码实现先来看硬件连接需要四根线VCC接3.3V或5V实测5V时测量距离更远GND接地Trig接PA6任意GPIO均可Echo接PA7需要支持外部中断的引脚关键代码分三个部分。首先是定时器初始化这里我优化了原始代码增加了错误检测void MX_TIM2_Init(void) { htim2.Instance TIM2; htim2.Init.Prescaler 71; htim2.Init.CounterMode TIM_COUNTERMODE_UP; htim2.Init.Period 999; // 1ms中断周期 if (HAL_TIM_Base_Init(htim2) ! HAL_OK) { Error_Handler(); } // 启用中断优先级配置 HAL_NVIC_SetPriority(TIM2_IRQn, 1, 0); HAL_NVIC_EnableIRQ(TIM2_IRQn); }测距函数我做了三点改进增加超时判断、添加温度补偿、优化滤波算法。比如这个带超时保护的版本float Get_Distance(void) { uint32_t timeout 100000; // 100ms超时 while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_7) SET timeout--); if(timeout 0) return -1; // 超时返回错误 float distance (__HAL_TIM_GET_COUNTER(htim2) overcount*1000)/58.0; // 温度补偿公式331.5 0.6*T ℃ distance * (331.5 0.6*25)/340; // 假设环境温度25℃ return median_filter(distance); // 中值滤波 }4. 测量精度优化技巧在实际环境测试时我发现三个常见干扰源电磁噪声、温度变化和多径反射。针对这些问题总结出以下解决方案电源滤波在模块VCC和GND之间并联100uF电解电容和0.1uF陶瓷电容实测可减少30%的跳变数据。有次在电机控制项目中没加电容导致测量值波动达±5cm加上后稳定在±0.3cm。动态温度补偿声速随温度变化明显0℃时331m/s30℃时349m/s。我在项目中接入DS18B20温度传感器实时修正计算公式float speed_of_sound 331.5 0.6 * temperature; distance (pulse_width * 1e-6) * speed_of_sound / 2;数字滤波三剑客中值滤波连续采样5次取中间值滑动平均保留最近10次测量值的平均值野值剔除当新数据偏离均值超过10%时丢弃在智能仓储机器人项目中综合使用这些技巧后测量稳定性从原来的±5cm提升到±2mm。特别提醒滤波算法会增加响应延迟在实时性要求高的场景要适当减少采样次数。5. 常见问题排查指南遇到问题不要慌根据我调试数十个项目的经验90%的问题都出在以下方面现象1始终返回最大距离检查Echo引脚是否接触不良用示波器观察Trig信号是否达到10μs确认定时器中断已正确启用__HAL_TIM_ENABLE_IT现象2测量值波动大检查被测物体表面是否吸音如绒毛材质尝试降低测量频率每次测量间隔至少60ms在代码中添加互斥锁避免中断冲突现象3短距离测量不准确保物体距离大于2cmHC-SR04的盲区调整模块安装角度避免声波直射反射面在代码中添加死区处理if(distance2) return 0有个特别隐蔽的bug我遇到过当系统中有其他高优先级中断时会导致Echo信号捕获不准确。解决方案是调整定时器中断优先级或者改用输入捕获模式。具体可以在CubeMX中配置TIM2的全局中断优先级高于其他外设中断。