当前位置: 首页 > news >正文

STM32超声波测距实战:从硬件连接到OLED显示(附完整代码)

STM32超声波测距实战:从硬件连接到OLED显示(附完整代码)

超声波测距技术因其成本低、精度适中、实现简单等优势,在智能小车避障、工业测距、智能家居等领域广泛应用。本文将手把手带你完成基于STM32的超声波测距系统开发,涵盖硬件连接、代码实现到OLED显示的全流程。不同于简单的代码搬运,我们会深入探讨温度补偿、误差处理等实际开发中必须面对的细节问题。

1. 硬件设计与连接

1.1 超声波模块选型与原理

市面上常见的HC-SR04超声波模块工作电压为5V,测距范围2cm-400cm,满足大多数场景需求。其核心工作原理如下:

  1. 触发阶段:给Trig引脚至少10μs的高电平脉冲
  2. 发射阶段:模块自动发送8个40kHz的超声波脉冲
  3. 回波检测:模块通过Echo引脚输出高电平,持续时间与距离成正比

距离计算公式为:

距离(cm) = 高电平时间(μs) / 58

注意:声速受温度影响显著,15℃时为340m/s,温度每变化1℃,声速变化约0.6m/s。高精度应用需增加温度传感器进行补偿。

1.2 硬件连接示意图

STM32引脚超声波模块OLED显示屏
PB11Trig-
PB10Echo-
PB6-SCL
PB7-SDA
3.3VVCCVCC
GNDGNDGND

关键细节

  • 超声波模块最好单独供电,避免电机等大电流设备干扰
  • Echo引脚建议串联200Ω电阻保护IO口
  • OLED显示模块选择I2C接口版本,节省IO资源

2. 软件架构设计

2.1 核心代码结构

/* 文件结构 */ ├── Drivers │ ├── STM32F1xx_HAL_Driver │ └── CMSIS ├── Inc │ ├── hcsr04.h │ ├── oled.h │ └── main.h └── Src ├── hcsr04.c // 超声波驱动 ├── oled.c // 显示驱动 └── main.c // 主逻辑

2.2 定时器配置关键代码

使用TIM2进行高精度时间测量:

void MX_TIM2_Init(void) { TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; htim2.Instance = TIM2; htim2.Init.Prescaler = 72-1; // 1MHz计数频率 htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 0xFFFFFFFF; // 最大计数值 htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(&htim2); sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig); sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig); }

3. 核心算法实现

3.1 带温度补偿的距离计算

float Get_Distance(float temperature) { uint32_t pulse_width = 0; float sound_speed = 331.4 + 0.6 * temperature; // m/s float distance_cm = 0; // 触发测量 HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET); delay_us(15); HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET); // 等待回波 while(!HAL_GPIO_ReadPin(ECHO_GPIO_Port, ECHO_Pin)); HAL_TIM_Base_Start(&htim2); while(HAL_GPIO_ReadPin(ECHO_GPIO_Port, ECHO_Pin)); HAL_TIM_Base_Stop(&htim2); pulse_width = __HAL_TIM_GET_COUNTER(&htim2); // 获取计数值 distance_cm = (pulse_width * sound_speed) / 20000.0; // 往返距离 return distance_cm; }

3.2 数字滤波处理

针对超声波测距常见的随机误差,采用移动平均滤波:

#define FILTER_SIZE 5 float Moving_Average_Filter(float new_data) { static float buffer[FILTER_SIZE] = {0}; static uint8_t index = 0; float sum = 0; buffer[index] = new_data; index = (index + 1) % FILTER_SIZE; for(int i=0; i<FILTER_SIZE; i++){ sum += buffer[i]; } return sum / FILTER_SIZE; }

4. OLED显示优化

4.1 多级菜单实现

通过按键切换显示模式:

typedef enum { DISPLAY_MODE_NORMAL, DISPLAY_MODE_HISTORY, DISPLAY_MODE_SETTING } DisplayMode_t; void Update_Display(DisplayMode_t mode) { switch(mode){ case DISPLAY_MODE_NORMAL: OLED_ShowString(0, 0, "Distance:"); OLED_ShowFloat(2, 0, current_distance, 1, 1); OLED_ShowString(4, 0, "cm"); break; case DISPLAY_MODE_HISTORY: // 显示历史数据统计 break; case DISPLAY_MODE_SETTING: // 显示参数设置界面 break; } }

4.2 可视化效果增强

添加距离柱状图显示:

void Draw_Distance_Bar(float distance) { uint8_t bar_length = (uint8_t)(distance / 400.0 * 128); // 满量程400cm对应128像素 OLED_DrawRectangle(0, 6, bar_length, 8, 1); OLED_Refresh(); }

5. 常见问题排查

5.1 典型故障现象及解决方法

故障现象可能原因解决方案
测量值固定为0Echo引脚未连接检查硬件连接
测量值波动大电源干扰增加滤波电容
测量值偏大温度补偿未启用启用温度补偿算法
OLED显示乱码I2C地址不匹配确认OLED模块的I2C地址

5.2 性能优化技巧

  • 降低功耗:间隔测量替代连续测量
  • 提高响应速度:使用DMA传输OLED数据
  • 增强鲁棒性:添加超时判断防止死等回波
// 带超时的回波检测 uint32_t timeout = 100000; // 100ms超时 while(!HAL_GPIO_ReadPin(ECHO_GPIO_Port, ECHO_Pin) && timeout--); if(timeout == 0) return -1; // 超时错误

6. 项目扩展方向

6.1 多传感器融合

结合红外传感器提升测距可靠性:

#define ULTRASONIC_WEIGHT 0.7 #define IR_WEIGHT 0.3 float Fused_Distance(float ultrasonic_dist, float ir_dist) { return ULTRASONIC_WEIGHT * ultrasonic_dist + IR_WEIGHT * ir_dist; }

6.2 无线数据传输

通过蓝牙模块将数据发送到手机APP:

void Bluetooth_Send(float distance) { char buffer[20]; sprintf(buffer, "DIST:%.1fcm\n", distance); HAL_UART_Transmit(&huart1, (uint8_t*)buffer, strlen(buffer), 100); }

在完成基础功能后,尝试添加以下高级功能:

  • 自动校准功能
  • 测量数据SD卡存储
  • 通过PWM控制蜂鸣器报警
http://www.jsqmd.com/news/621186/

相关文章:

  • EByte E220 LoRa模块硬件原理与低功耗工程实践
  • UE5 C++ 两种枚举
  • 2026年正规的东莞公司注册行业榜单 - 品牌宣传支持者
  • SenseBoxBLE库详解:phyphox协议下的Arduino BLE透传实践
  • Windows Server 操作主机管理实验文档
  • 【MySQL】MySQL安装保姆级教程:MySQL8数据库使用指南(2026版)
  • OpenClaw 集成至多用户 Web 应用的可行性分析
  • 同一网段通信:从原理到实践的深度解析
  • emGUI:嵌入式轻量级Widget GUI框架解析
  • 2026南京:南京精装改造全屋定制/南京美式风全屋定制/南京芦花全屋定制工厂/南京门墙柜一体全屋定制工厂/南京高性价比全屋定制工厂/选择指南 - 优质品牌商家
  • 别再踩坑了!在Rancher里用Deployment部署Redis集群,Pod重启IP变动的终极解决方案
  • 终极指南:使用OpenCore Legacy Patcher免费升级老旧Mac到最新macOS
  • PingCraft:从需求文档到可追踪工作项的 Agent 实践之路寻
  • EasyDriver步进电机驱动库stepper深度解析与工程实践
  • SpringCloud进阶--Sentinel 流量防卫兵衅
  • wso~.升级到.需要更新的数据表戳
  • 一天浪费3小时?OPC最常见的5个“业务流程税”陷阱
  • Windows Server 多域间访问实施文档
  • 东南亚电商支付方式有哪些?2026最新整
  • 16.Flask入门
  • 2026年蓝牙耳机推荐:8款200-500元机型参数拆解与硬核选型
  • CMake变量实战:从基础引用到高级构建控制
  • 【技术深潜】MODA数据集与OSSDet模型:如何破解无人机多光谱目标检测的‘数据荒’与‘融合难’?
  • 解决Maven插件依赖缺失:以maven-resources-plugin为例的实战指南
  • LwJSON:嵌入式轻量级JSON解析器深度解析
  • M95系列SPI EEPROM嵌入式驱动库详解与工业级应用
  • USB HID设备开发避坑指南:基于STM32F4的鼠标键盘事件回调详解
  • Sourcetree实战指南:从零上手代码克隆、高效合并与冲突化解
  • 4月初AI观察:AI正在慢慢走向实际
  • Android10剪贴板限制下的高效适配策略与实践