☰
基于STM32和超声波的车位检测系统设计与实现
2026/10/28 17:51:49 网站建设 项目流程

简介:一套基于STM32的智能停车场车位检测系统开发资料,面向嵌入式、电子信息、物联网等方向的毕业设计与课程实践。系统采用模块化设计,包含数据采集、通信传输和状态显示模块,通过传感器网络与主控单元协同,实现车位状态的智能识别与实时采集,适合需要完整技术实现路径的初学者进阶参考。压缩包共1027个文件,约32.34MB,以C源文件、头文件、备份文件为主,同时包含Keil工程配置文件、原理图/PCB设计文档、日志及库文件等,源码与硬件设计配套齐全,便于直接查看或二次开发。已有53人学习下载。资料内含核心控制器程序、硬件设计文档及实施指导手册,评审成绩95分,功能经过系统化测试;读者可依据模块接口进行功能扩展,或作为学术研究与工程实训的参考案例。

1. 智能停车场车位检测到底怎么做:超声波方案为什么比摄像头更早交付

很多人一听到“智能停车场车位检测”,第一反应是用摄像头加深度学习模型做视觉识别。但真正落到工程交付时,我手上做的最快的方案却是 STM32 加超声波探头:一个 HC-SR04 模块不到十块钱,识别精度在固定车位场景下能做到 1cm 以内,不受光照和阴影影响,一晚上就能把单探头的完整链路跑通。这个系统解决的核心问题很朴素——每个车位上方装一个探头,周期性测量探头到车顶或地面的距离,距离明显变小就判定“有车”,否则就是“空闲”,再把状态汇聚到一个 STM32 上统一上报。对于露天停车场、地下车库、机械式立体车库的存量改造,超声波方案比视觉方案便宜一个数量级,也比地磁方案少一次破坏路面的施工。这篇文章就按我实际交付过的做法,把传感器选型、STM32 工程搭建、测距驱动代码、多车位轮询调度、常见坑和进阶验证一次讲透,新手可以直接照着复现,老手可以重点看第五章的边界条件和踩坑记录。

2. 车位检测器选型与系统架构:为什么超声波是改造项目的默认选项

2.1 四种主流车位检测方案的对比与选型理由

做车位检测,行业内能用的传感器不外乎四类:地磁、红外对射、超声波、摄像头视觉。我接过的改造项目里,业主要求最多的是“别破坏地面、别大改线路、当天能试运行”,这一条直接就把地磁方案淘汰了。地磁探头要埋进车位地面下,施工要切缝、要浇胶、要等固化,一个车位折腾半小时以上,而且后期电池更换要把地砖撬开,维护成本很高。红外对射的方案便宜,但红外光对灰尘和遮挡极其敏感,地下车库的扬尘环境下漂移严重,户外还会被太阳光里的红外分量干扰。

摄像头视觉方案这几年热度很高,但它的问题在于:固定车位场景下,一辆白车停进去和一面白墙在灰度图上差别不大,靠颜色分割根本不可靠,必须上深度学习模型;模型要标注数据、要训练、要部署,夜间还要补光灯,单个车位的综合成本轻松超过超声波方案五倍以上。更要命的是,视觉方案有一个“换场景就必须重新调模型”的毛病,同一个停车场不同楼层光照不同,效果就飘忽不定。超声波方案则完全没有这些问题:它主动发射超声波并接收回波,不依赖环境光,灰尘和水雾对 40kHz 超声波的衰减远小于对红外光的衰减,而且探头的安装位置是车位正上方,物理安装简单,用膨胀螺丝固定支架就行。

判断一个方案值不值得做,还要看误报率和可维护性。超声波测距精度在 1cm 级别,车位占用和空闲的距离差通常在 30cm 以上(轿车顶部到地面的高度差),这个信号余量非常大。多数停车场对车位检测的准确率要求是 99% 以上,超声波方案只要做好防串扰和温度补偿,达到这个指标并不难。我最常给的配置是:每车位一个 HC-SR04 模块,一块 STM32F103C8T6 最小系统板管理 8 个探头,电源用 12V 转 5V 的 DC-DC 模块。整套物料成本控制在 150 元以内,比一个工业级地磁探头的单价还低。

2.2 系统架构与 STM32F103C8T6 的资源分配

整个系统的数据流是:超声波探头测量到车顶的距离,STM32 通过 GPIO 触发和回波脉宽测量计算出距离值,软件判定车位状态(占用/空闲/故障),最后通过串口或无线模块上报到上位机。每个探头占用两个 GPIO,一个输出触发脉冲,一个输入回波信号。8 个车位就是 16 个 GPIO,STM32F103C8T6 有 37 个 GPIO 引脚,完全够用,还能留出串口、LED 指示灯和温度传感器的引脚。

主控芯片选 STM32F103C8T6 的原因很实际:这颗芯片是 Arm Cortex-M3 内核,主频最高 72MHz,Flash 64KB,RAM 20KB,价格在十元上下,资料和例程是全网最多的一档。开发工具链成熟,不管是用 STM32CubeMX 生成 HAL 库工程,还是用标准外设库,都能很快上手。在资源占用上,管理 8 个超声波探头并做 200ms 周期轮询,CPU 占用率不超过 10%,剩余算力足够跑一个简单的 MQTT 协议栈或者 Modbus 从站。如果项目要求一路接入 IoT 云平台上报状态并发微信告警,这颗芯片也能通过串口外挂 ESP8266 完成。

系统还有一个容易被忽略的部分:电源。超声波探头的驱动瞬间电流接近 30mA,8 个探头同时工作的峰值接近 240mA,如果直接用 STM32 开发板上的 3.3V LDO 供电,电压跌落会导致测距异常甚至芯片复位。我一般的做法是单独用 5V/3A 的电源模块给探头供电,STM32 再通过自己板载的 LDO 从 5V 取电,两块供电网络在单点地汇合。这个细节看起来小,但它直接决定了系统在真实停车场环境里能不能稳定跑一个月。

3. 硬件接线与 STM32 最小工程搭建:从 CubeMX 到点灯只用半小时

3.1 HC-SR04 接线与电平转换的必做处理

HC-SR04 有四个引脚:VCC、GND、Trig(触发)、Echo(回波)。VCC 接 5V,GND 接电源地,Trig 接 STM32 的某个 GPIO 输出,Echo 接 STM32 的 GPIO 输入。接线表如下:

HC-SR04 引脚接 STM32F103C8T6说明
VCC5V 电源正极探头供电,要求 5V,不能接 3.3V
GND电源地与 STM32 共地,防止信号参考电位漂移
TrigPA0GPIO 输出,拉高至少 10us 触发测距
EchoPA1(经分压后)GPIO 输入,回波脉宽信号

Echo 引脚是这里唯一的“坑”。HC-SR04 的 Echo 输出高电平幅度是 5V,而 STM32F103C8T6 的 GPIO 耐压范围是 -0.3V 到 3.6V,直接把 5V 信号接进去,短时间内可能不烧芯片,但长期工作会导致引脚内部保护二极管导通,轻则测距数据异常,重则整个引脚位损坏。标准做法是串两个电阻分压:在 Echo 和 PA1 之间串联 1k 电阻,PA1 对地接 2k 电阻,这样 PA1 处的高电平电压约为 5V × 2/(1+2) = 3.33V,刚好落在安全范围。更稳妥的方案是加一个 BAT54S 肖特基二极管做钳位,但我交付的多数项目用电阻分压就足够了,成本不到一分钱。

3.2 用 STM32CubeMX 生成 HAL 工程:时钟、GPIO、定时器与串口

STM32 工程的搭建我统一走 STM32CubeMX 生成 HAL 库工程,生成的代码可以直接在 Keil、IAR 或 VS Code + CMake 里编译。CubeMX 里的关键配置项如下:

  • RCC 时钟:HSE 选择 Crystal/Ceramic Resonator,HCLK 设置为 72MHz(PLL 倍频到 9 倍)。
  • SYS:Debug 选择 Serial Wire,这样才能用 ST-Link 烧录和调试。
  • GPIO:PA0 设为 GPIO_Output,初始电平 Low;PA1 设为 GPIO_EXTI1(外部中断),触发模式设为 Both Edge(上升沿和下降沿都触发)。
  • TIM3:选择 Internal Clock,Prescaler 设为 71,Counter Period 设为 65535,这样 TIM3 的计数频率是 72MHz/(71+1) = 1MHz,即计数值每增加 1 代表 1us。
  • USART1:Mode 设为 Asynchronous,波特率 115200,8 位数据,无校验,1 位停止位。
  • 如果要多车位,继续在 GPIO 里加 PA2、PA3、PA4 等作为额外的 Trig 和 Echo 引脚。

这些配置里最关键的是 TIM3 的 Prescaler 参数。STM32F103 的 APB1 定时器时钟是 72MHz,把 Prescaler 设成 71 后,计数器每计数一次的时间正好是 1us,这样我们用定时器计算时间差时,差值直接就是微秒数,不需要任何换算。CubeMX 生成工程后,在 main.c 里补充定时器启动代码和中断处理函数。

3.3 在 VS Code 里编译与烧录的快速上手

CubeMX 生成工程后,有人会用 Keil,但我更习惯用 VS Code 配 arm-none-eabi-gcc 工具链,理由是开源、免授权、支持 CMake 管理,团队协作时构建配置可以直接进 Git。输入命令如下:

# 在工程根目录下,CubeMX 生成的 Makefile 工程用以下命令编译 make -j4 # 连接 ST-Link,用 OpenOCD 烧录生成的 bin 文件 openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c "program build/stm32_ultrasonic.bin 0x08000000 verify reset exit"

第一行 make 命令把源码编译成二进制文件,-j4 表示四核并行编译,能把编译时间压缩到十几秒。第二行的 OpenOCD 命令是烧录动作:interface/stlink-v2.cfg 指定烧录器类型,target/stm32f1x.cfg 指定目标芯片是 STM32F1 系列,program 后面的第一个参数是编译产物路径,0x08000000 是 STM32F103 内部 Flash 的首地址,verify 参数会在烧录后校验数据,reset 让芯片自动复位运行。

第一次上手时如果 OpenOCD 提示找不到设备,多半是 ST-Link 驱动没装,或者板子上 BOOT0 引脚被拉高进入了 ISP 模式。把 BOOT0 跳线帽拨回低电平,再检查设备管理器里有没有识别到 ST-Link,基本就能解决。烧录成功后,我习惯先在 main 函数里点一个 LED 灯验证最小系统是活的,再跑串口打印“hello from stm32”,最后才接超声波探头。分层验证的好处是出问题时能快速定位是硬件还是软件。

4. 超声波测距驱动与多车位调度:核心代码直接落地

4.1 用定时器加外部中断测量回波脉宽的原理

超声波的测距原理一句话就能说清:TRIG 引脚给一个大于 10us 的高电平脉冲,模块内部发射 40kHz 超声波;超声波碰到障碍物反射回来,模块把回波放大整形后从 ECHO 引脚输出一个高电平脉冲,这个高电平持续的时间就是超声波从发射到返回的往返时间。距离等于声速乘以时间再除以 2。

测 Echo 高电平持续时间有两种常见做法:第一种是定时器输入捕获模式,硬件自动记录上升沿和下降沿的计数器值,优点是 CPU 开销最小,但配置复杂,还要处理计数器溢出;第二种是外部中断加自由运行定时器,上升沿中断时记录 start_us,下降沿中断时记录 end_us,两者相减得到脉宽。我更喜欢第二种,因为代码更直观,排查问题时只需要看两个全局变量的值。时间基准就用第 3 章配置的 TIM3 自由运行计数器,计数频率 1MHz,对应的最大可测时间是 65535us,按声速 340m/s 算,最远可测距离约 11 米,远超市面上 HC-SR04 标称的 4 米量程。

4.2 完整驱动代码:单探头测距带温度补偿

下面是单探头的完整驱动代码,我按 HAL 库风格写的,可以直接嵌入 CubeMX 生成的工程里。先是定时器时间基准部分:

// main.c 中用户代码区域 __IO uint32_t timer_us = 0; // 全局微秒计数器,溢出后由中断维护 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM3) { timer_us += 65536; // 每次溢出说明计数器从 65535 归零,时间基准加 65536us } }

这段代码解决的是计数器溢出问题。TIM3 的计数器是 16 位,最大计到 65535 就会溢出回到 0,如果不记录溢出次数,一次超过 65ms 的测距就会得到错误结果。这里每溢出一次给 timer_us 加 65536,相当于把时间基准扩展成了 32 位,最长能记录约 49 天,对车位检测场景来说足够了。启动 TIM3 的代码是HAL_TIM_Base_Start_IT(&htim3),必须在主循环前调用。

然后是超声波触发和距离计算:

// 变量定义 volatile uint32_t echo_start_us = 0; // 回波上升沿时刻 volatile uint32_t echo_end_us = 0; // 回波下降沿时刻 volatile uint8_t echo_complete = 0; // 一次测量完成标志 void ultrasonic_trigger(void) { HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_SET); // 触发脉冲至少保持 10us,这里给 15us 留足裕量 delay_us(15); HAL_GPIO_WritePin(TRIG_GPIO_Port, TRIG_Pin, GPIO_PIN_RESET); } float ultrasonic_calc_distance(void) { float distance_cm = 0.0f; uint32_t duration_us = 0; // 等待测量完成,超过 30ms 视为超时,返回 0 表示无有效回波 uint32_t timeout = 30000; while (!echo_complete && timeout--) { delay_us(1); } if (echo_complete) { duration_us = echo_end_us - echo_start_us; // 声速随温度变化,25 度时约 346m/s,每升高 1 度增加 0.6m/s // 温度传感器返回的 temp_c 由 DS18B20 等读取,此处直接代入 float sound_speed = 331.4f + 0.607f * temp_c; distance_cm = (float)duration_us * sound_speed / 10000.0f / 2.0f; // 超过量程的距离按无遮挡处理 if (distance_cm > 400.0f) { distance_cm = 0.0f; } } echo_complete = 0; return distance_cm; } // 外部中断回调:上升沿记录开始时间,下降沿记录结束时间 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == ECHO_Pin) { if (HAL_GPIO_ReadPin(ECHO_GPIO_Port, ECHO_Pin) == GPIO_PIN_SET) { echo_start_us = timer_us + __HAL_TIM_GET_COUNTER(&htim3); } else { echo_end_us = timer_us + __HAL_TIM_GET_COUNTER(&htim3); echo_complete = 1; } } }

distance_cm 的计算公式要仔细看:声速的单位是 m/s,需要换算成 cm/us,除以 10000 是“米每秒到厘米每微秒”的单位换算,再除以 2 是因为测到的是往返时间。25°C 时的声速是 346m/s,但很多教程直接用 340 算,夏天气温到 35°C 时误差会到 1.5% 左右,对应 3 米距离误差约 4.5cm。车位判断的阈值通常设在 0.8 米附近,低温场景误判风险很高,所以我从第一版交付就加上了 DS18B20 温度传感器做补偿。timer_us + __HAL_TIM_GET_COUNTER(&htim3)这个表达式把溢出累计值和当前计数值相加,得到精确到微秒的绝对时间戳,两个时间戳相减就是脉宽。

注意:如果探头前方没有障碍物,或者探头安装角度朝上对着空旷区域,Echo 可能长时间保持高电平。上面的超时等待循环会把 CPU 卡住最多 30ms,主循环轮询周期设计时要把这个时间算进去。

4.3 多车位轮询与状态判定:防串扰和防抖都在这

一个车位一个探头,8 个探头接同一个 STM32。触发时会遇到一个超声波特有的问题:两个探头如果同时触发,探头 A 的超声波被障碍物反射后,可能被探头 B 接收,导致 B 测出错误的距离。解决办法是轮询时同一时刻只触发一个探头,并且两次触发之间留出至少 20ms 的时间间隔,让超声波充分衰减。我的调度代码是这样写的:

#define PARKING_SLOT_NUM 8 typedef struct { GPIO_TypeDef *trig_port; uint16_t trig_pin; GPIO_TypeDef *echo_port; uint16_t echo_pin; uint8_t is_occupied; // 当前判定状态 1占用 0空闲 float last_distance; // 最近一次距离 } parking_slot_t; // 假设 slot 数组在初始化时填充了 8 个车位的引脚信息 parking_slot_t slots[PARKING_SLOT_NUM]; void parking_scan_cycle(void) { for (int i = 0; i < PARKING_SLOT_NUM; i++) { // 切换当前探头的 Echo 引脚到外部中断 // 实现方式:重新配置 EXTI 线,或直接为每个探头配独立中断引脚 ultrasonic_trigger(); float dist = ultrasonic_calc_distance(); slots[i].last_distance = dist; // 判定逻辑:距离小于 80cm 且有有效回波,判定为占用 // 连续两次状态一致才更新,防止瞬时干扰造成状态抖动 uint8_t new_state = (dist > 0 && dist < 80) ? 1 : 0; if (new_state != slots[i].is_occupied) { // 第一次变化暂不确认,下一周期再次验证 slots[i].is_occupied = new_state; // 生产建议:用两个周期确认后再上报,这里简化为立即上报 // 上报代码见 4.4 节 } // 两次触发间隔 20ms,防止相邻超声波探头串扰 HAL_Delay(20); } }

轮询周期 8 个车位乘以每次约 30ms 加 20ms 等待,一个完整周期约 400ms,对车位检测这类状态变化频率很低的场景绰绰有余。threshold 的 80cm 是怎么定的?停车位上方安装探头时,探头到地面的距离一般是 2.5 米到 3 米,车顶到探头剩余 0.5 米到 1 米,轿车和 SUV 的顶面高度差约 30cm。把阈值设在 80cm,既能可靠识别各类轿车,又避免了地面灰尘堆积导致的误判。如果是机械立体车库的载车板,层高固定,阈值可以紧到 50cm。

4.4 数据上报:串口 JSON、蓝牙模块与 WiFi 云平台的三种出路

状态判定完成后,数据要送出去。最简单的是串口输出 JSON 格式数据,方便上位机和调试工具解析:

#include <stdio.h> #include <string.h> char report_buf[128]; void parking_report(void) { // 拼接 JSON 数据帧,供上位机或网关解析 for (int i = 0; i < PARKING_SLOT_NUM; i++) { memset(report_buf, 0, sizeof(report_buf)); snprintf(report_buf, sizeof(report_buf), "{\"slot\":%d,\"status\":%d,\"dist_cm\":%.1f}\r\n", i + 1, slots[i].is_occupied, slots[i].last_distance); HAL_UART_Transmit(&huart1, (uint8_t *)report_buf, strlen(report_buf), 100); } }

串口输出适合部署在本地网关的场景,接线简单,调试期看数据一目了然。如果项目要求手机端实时查看,我一般会在串口上接一个 HC-05 蓝牙模块,手机用串口调试助手就能订阅数据,距离短但零成本。要是客户要远程查看,就在预留的 UART2 上接 ESP8266 模块,让 STM32 通过 AT 指令把车位状态发布到巴法云这类物联网平台的 MQTT 主题里。常见的做法是给每个车位分配一个固定的主题,ESP8266 连接 WiFi 后作为 MQTT 客户端发布数据,云端再转发给小程序端展示。ESP8266 的 AT 指令透传和 MQTT 鉴权参数设置是这个链路里最容易翻车的地方,第五章会专门讲。

5. 车位检测系统避坑指南:五个坑我全都踩过

5.1 现象:每隔几秒距离突然跳变到十几厘米

系统同时接多个探头后,单个车位在空闲状态下测出的距离会周期性出现一个明显偏小且数值稳定的突变,持续时间不到 100ms,看起来像有车停进去又开走了。原因是相邻探头的超声波串扰:探头 A 发射的超声波在空旷区域传得远,碰到附近支撑柱或墙壁后反射,被同一时刻处于接收状态的探头 B 收到,B 误以为回波来自自己正下方的障碍物。解决方法是把“逐探头顺序触发”严格落地,同一时刻只允许一个探头处于发射状态,并且两次测量之间的延时从 10ms 拉长到 20ms 以上。改了调度时序后,这个现象彻底消失。

5.2 现象:Echo 引脚直连 3.3V 单片机,跑两周后 GPIO 烧了

这是新手最容易犯的硬件错误。HC-SR04 模块工作在 5V 逻辑,Echo 输出的高电平是 5V,而 STM32F103 的 GPIO 最高只能承受 3.6V。直连的后果不是立刻烧毁,而是引脚内部保护二极管反复导通,电流灌入电源轨,长期工作最终导致引脚失效或者芯片发热异常。解决方法是 Echo 到 PA1 之间加 1k 串阻,PA1 到 GND 加 2k 下阻,把高电平电压钳到 3.33V。如果想更保险,可以用三极管或者光耦做级转换,但电阻分压对这个信号已经足够,我交付的项目里用了三年没有返修。

5.3 现象:程序卡死,Watchdog 频繁复位,串口打印乱码

程序跑起来后,如果探头正上方是空旷区域(比如立体车库最顶层上方没有遮蔽物),Echo 会一直维持高电平,我的代码里那个while (!echo_complete && timeout--)的循环最多卡 30ms,看似无害,但如果在中断里调用测距函数,或者把轮询周期压得太紧,这个 30ms 的阻塞会让整个调度卡顿。更隐蔽的是,如果多个车位同时超时,主循环卡死时长叠加,看门狗就触发了。解决方法是把测距函数改成非阻塞状态机:触发后立即返回,等待外部中断回调置位完成标志,主循环里检查标志再取结果。我后来重构的代码里,ultrasonic_calc_distance这个函数被彻底移除了等待循环,改成ultrasonic_start_measure和ultrasonic_get_result两个函数。

5.4 现象:冬天和夏天的同一辆车识别结果不一致

同一车位同一辆车,夏天测出的距离比冬天短约 3cm,如果阈值设在临界值,冬天就可能误判。原因是超声波的声速随温度变化明显:0°C 时约 331m/s,40°C 时约 355m/s,变化幅度接近 7%。距离计算如果固定用 340m/s,夏季误差约 2%,冬季误差约 1.3%,测 3 米距离就是 4cm 到 6cm 的偏差。解决方法是加温度补偿,用 DS18B20 或者板载温度传感器读取环境温度,代入公式声速 = 331.4 + 0.607 × T。我最初的第一版项目没有补偿,冬天连续误报,到了现场用红外温度计一测,环境温度零下,超声波声速慢了一大截,才明白问题根源。

5.5 现象:ESP8266 连接巴法云经常断线,数据上报不稳定

无线上报场景里最常见的问题:STM32 和 ESP8266 通过串口通信,但两边一个用 5V 供电一个用 3.3V,电平不匹配导致 AT 指令偶发错误;更隐蔽的是 ESP8266 在连接 WiFi 的瞬间电流会冲到 300mA,如果电源余量不足,电压跌落会导致 ESP8266 重启,然后又重连,如此反复。解决方法是:确认 ESP8266 模块的 TX、RX 是 3.3V 电平,RX 接收 STM32 的 3.3V 信号没问题,但 TX 输出到 STM32 的 RX 也要确认电平;电源上用单独的 AMS1117-3.3 给 ESP8266 供电,并且在模块电源引脚旁边并联 100uF 电解电容加 0.1uF 陶瓷电容。还有一个容易被忽略的问题:MQTT 的 Topic 和鉴权信息如果写错,模块会提示连接成功但收不到服务器订阅的数据,调试时要把 ESP8266 的串口日志打开,看 MQTT 的 CONNACK 返回码,0 才是成功。

6. 进阶:从串口调试到真机验证,三个让人少走弯路的实测方法

6.1 用逻辑分析仪验证测距时序是否规范

超声波测距的时序看着简单,但实际部署后经常出现模块没反应或者回波脉宽异常的情况。我每次调试新接线的探头时,都会用逻辑分析仪同时抓 Trig 和 Echo 两个通道的信号。正常的时序应该是:Trig 出现一个 10us 以上的高电平脉冲,之后经过约 200us 的模块内部处理,Echo 拉高,Echo 高电平持续时间对应目标距离。如果 Trig 脉冲宽度只有 5us,模块不会响应,Echo 一直保持低电平;如果 Echo 持续高电平超过 30ms,说明探头前方没有反射面。逻辑分析仪采样率设到 1MHz 就能清晰分辨,我用的是十几块钱的 8 通道逻辑分析仪,接入点选在 STM32 引脚焊盘,避开接插件接触不良的干扰。

时序验证表可以做成验收标准:

信号正常范围异常含义
Trig 高电平15us ± 2us小于 10us 模块不响应
Trig 到 Echo 上升沿200us 左右明显变长说明模块供电不足
Echo 高电平0.2ms 到 30ms超过 30ms 视为无目标
Echo 脉宽与距离换算20ms 对应约 3.4m与卷尺实测偏差应小于 2cm

6.2 低功耗实测:用万用表测出系统真实续航

露天停车场没有市电可取时,系统要用电池或太阳能供电,功耗就直接决定电池更换周期。超声波探头不能一直工作,我一般把每个探头的测量周期设为 1000ms,每次测量消耗约 20ms,探头占空比只有 2%。实测单个 HC-SR04 工作电流约 15mA,折算平均电流 0.3mA;STM32F103C8T6 运行在 72MHz 时电流约 40mA,这是主要功耗来源。如果电池供电,我会让 STM32 在不需要测量的时候进入 STOP 模式,用 RTC 闹钟每秒钟唤醒一次做一轮测量,唤醒时间只需 5us 左右,实测整机平均电流可以压到 3mA 以下。用一节 18650 电池(容量约 2500mAh)计算,理论续航约 800 小时,实际考虑升压损耗和温度影响,打五折也有 400 小时,约 16 天。

6.3 一套可靠的验收方法:配合卷尺和秒表实测精度

系统装完后,现场验收我有一套固定流程:探头正下方放一块硬纸板模拟车顶,分别放在 30cm、60cm、100cm、150cm、200cm 五个位置,每个位置记录 10 次测量值,取平均值与卷尺实测值对比,误差在 2cm 内且 10 次数据没有超过 1cm 的抖动就算合格。然后是动态测试:人从探头下方走过,观察状态从“占用”切到“空闲”再切回“占用”的响应时间,一个轮询周期 400ms,加上判定确认时间,总响应时间应该在 2 秒内,超过 3 秒说明轮询周期或者判定确认写得太保守。最后做连续通电测试,至少跑 48 小时,统计误报次数。我第一版项目没做连续通电,结果第三天就因探头供电不足偶发误报被现场抓包,这之后,“验收必须过夜”成了我给自己定的死规矩。

同步探头安装高度和阈值是最后一道工序。最好在白天光照充足和夜间各测一组数据,记录两种条件下测距值有没有系统性偏差。超声波不受光照影响,但温度昼夜变化会带来声速差异,夜间温度低,声速慢,测距值会偏大一点,如果阈值按白天数据设得靠近临界点,夜间就容易误判。我现在会在固件里直接读取 DS18B20 做实时补偿,温度对距离的影响幅度可以从毫米级偏差降到可以忽略的程度。这套系统从选型到验收,最让我意外的不是超声波本身,而是那些看似不起眼的细节——一个分压电阻、一次温度补偿、一次时序避让,每一个都在实际运行中真真切切地决定过系统会不会翻车。希望帮你避开我踩过的这些坑,一次把车场交付成。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询