1. 项目背景与应用场景超声波测距系统在嵌入式开发中非常常见比如智能小车的避障、倒车雷达、自动门控制等场景都会用到。这个项目通过STM32微控制器将超声波测距模块、OLED显示屏和蜂鸣器报警功能集成在一起实现了一个完整的距离监测系统。当检测到物体距离小于设定阈值时系统会通过蜂鸣器发出警报同时在OLED上实时显示当前距离值。我最早接触这个项目是在做一个智能小车的时候当时需要让小车能够自动避开障碍物。超声波模块价格便宜、使用简单非常适合用来做距离检测。OLED屏幕则能直观显示数据省去了连接电脑调试的麻烦。蜂鸣器的加入让系统具备了声音提示功能这样即使不看屏幕也能知道是否接近障碍物。这个系统的核心在于三个模块的协同工作超声波模块负责采集距离数据STM32进行数据处理和逻辑判断OLED显示实时信息蜂鸣器提供声音反馈。整个过程涉及到硬件连接、驱动编写、数据处理等多个环节是一个很好的嵌入式开发实战案例。2. 硬件准备与连接2.1 所需硬件清单要完成这个项目你需要准备以下硬件组件STM32F103C8T6最小系统板蓝色小板子价格便宜又好用HC-SR04超声波测距模块市面上最常见的型号0.96寸OLED显示屏I2C接口的版本接线更简单有源蜂鸣器模块注意区分有源和无源杜邦线若干建议准备不同颜色的方便区分USB转TTL模块用于程序烧录面包板可选方便临时搭建电路我第一次做这个项目时因为没注意蜂鸣器类型买错了结果调试了半天才发现问题。有源蜂鸣器只需要给高电平就会响无源的则需要PWM驱动这点要特别注意。2.2 硬件连接示意图各模块与STM32的连接方式如下超声波模块VCC → 5VGND → GNDTrig → PB10Echo → PB11OLED显示屏VCC → 3.3VGND → GNDSCL → PB6SDA → PB7蜂鸣器VCC → 3.3VGND → GNDI/O → PB8实际接线时建议先用万用表检查线路是否连通。我曾经因为一根杜邦线内部断裂排查了好久才发现问题。另外OLED的电源最好接3.3V接5V虽然也能工作但长期使用可能会影响寿命。3. 软件开发环境搭建3.1 工具链安装开发这个项目需要准备以下软件工具Keil MDK-ARM建议使用5.23以上版本STM32CubeMX用于初始化代码生成ST-Link Utility用于程序烧录串口调试助手可选用于调试输出安装Keil时要注意安装对应的STM32F1xx设备支持包。我第一次使用时没注意这点编译时一直报错后来才发现是缺少设备支持包。另外建议安装ST-Link的驱动这样可以直接通过ST-Link烧录程序比串口烧录稳定得多。3.2 工程创建与配置使用STM32CubeMX创建工程可以省去很多初始化工作选择STM32F103C8Tx系列芯片配置时钟树将系统时钟设置为72MHz启用I2C1用于OLED配置PB8为GPIO输出蜂鸣器配置PB10为GPIO输出Trig配置PB11为GPIO输入Echo启用TIM2定时器用于超声波测距计时生成代码后记得在Keil中设置正确的编译器版本和优化等级。我习惯使用AC6编译器优化等级设为-O1这样既能保证性能又方便调试。4. 核心功能实现4.1 超声波测距模块驱动超声波测距的原理很简单发送一个10us的高电平脉冲触发模块然后检测回波信号的高电平持续时间。根据声速计算距离持续时间×声速/2。float Distance(void) { GPIO_ResetBits(GPIOB, GPIO_Pin_10); GPIO_SetBits(GPIOB, GPIO_Pin_10); delay_us(20); GPIO_ResetBits(GPIOB, GPIO_Pin_10); while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) 0); TIM2-CNT 0; while(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11) 1); uint32_t count TIM2-CNT; return (float)count / 58.5f; // 转换为厘米 }实际测试中发现超声波模块在不同温度下测距精度会有所变化。为了提高准确性可以加入温度补偿算法或者多次测量取平均值。4.2 OLED显示实现OLED显示使用SSD1306驱动芯片通过I2C接口通信。我们可以使用现成的驱动库来简化开发void OLED_ShowDistance(float distance) { char buf[16]; sprintf(buf, Dist: %.1fcm, distance); OLED_ShowString(0, 2, (uint8_t*)buf, 16); if(distance 20.0f) { OLED_ShowString(0, 4, (uint8_t*)WARNING!, 16); } else { OLED_ShowString(0, 4, (uint8_t*) , 16); } }显示内容可以根据需要自定义比如加入距离曲线图或者历史数据统计。我在实际项目中还添加了电池电量显示方便移动设备使用。4.3 蜂鸣器报警逻辑蜂鸣器控制相对简单当检测到距离小于阈值时触发报警#define ALARM_DISTANCE 20.0f // 20cm报警阈值 void CheckAlarm(float distance) { if(distance ALARM_DISTANCE distance 2.0f) { GPIO_SetBits(GPIOB, GPIO_Pin_8); HAL_Delay(100); GPIO_ResetBits(GPIOB, GPIO_Pin_8); } else { GPIO_ResetBits(GPIOB, GPIO_Pin_8); } }实际应用中可以根据距离远近改变报警频率距离越近报警声越急促。这样用户不用看屏幕就能判断障碍物的远近程度。5. 系统集成与优化5.1 主程序逻辑设计主循环中需要协调三个模块的工作int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_I2C1_Init(); MX_TIM2_Init(); OLED_Init(); My_CSB_Init(); while(1) { float dist Distance(); OLED_ShowDistance(dist); CheckAlarm(dist); HAL_Delay(100); } }这里需要注意采样间隔不能太短否则超声波模块可能来不及完成一次完整的测距过程。我测试发现100ms的间隔比较合适既能保证实时性又不会丢失数据。5.2 常见问题排查在调试过程中可能会遇到以下问题超声波模块无反应检查Trig和Echo线是否接反供电是否正常OLED不显示检查I2C地址是否正确通常是0x78或0x7A蜂鸣器不响确认是有源蜂鸣器且GPIO输出模式正确测距数据跳动大尝试多次测量取平均值或者检查环境是否有干扰我曾经遇到OLED显示乱码的问题后来发现是I2C时钟速度设置太快降低到100kHz就正常了。这种硬件问题往往需要耐心排查。5.3 性能优化建议系统稳定运行后可以考虑以下优化加入滑动平均滤波减少测距数据抖动实现低功耗模式当长时间无变化时降低采样频率添加校准功能允许用户设置报警阈值扩展串口通信可以将数据上传到上位机在智能小车项目中我还加入了多方向测距功能使用多个超声波模块实现全方位障碍物检测。这些扩展功能可以根据实际需求灵活添加。