这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【2026 Let's do 第2期】简易超声波测距仪实践成果帖 -- 超声波测

共1条 1/1 1 跳转至

【2026 Let's do 第2期】简易超声波测距仪实践成果帖 -- 超声波测距仪

助工
2026-09-14 21:04:38     打赏

一、项目介绍

        本项目使用 NXP FRDM-MCXA153 开发板连接 HC-SR04 超声波模块,实现 周期测距、两级整数滤波、带回差和连续样本确认的近距离报警、传感器 故障恢复、双串口输出和板载 LED 状态指示。软件按采集、处理、输出 三个独立任务分层,利用消息队列按值传递数据,避免慢速串口阻塞采集。


1.1 硬件介绍

信号HC-SR04 端FRDM-MCXA153 端约束

电源VCC3.3 V使用稳定 3.3 V 供电
GNDGND传感器、开发板、外部串口接收端共地
触发TRIGArduino D15 / P1_9开发板输出 3.3 V,需确认模块可识别
回波ECHOArduino D14 / P1_8如果是 5 V 供电必须降至 3.3 V
调试串口LPUART0,P0_2/P0_3,J15板级 console,115200 8N1
结果串口LPUART2,P3_14/P3_15,mikroBUS115200 8N1
状态灯DT_ALIAS(led0)板载红色 LED,逻辑极性由 DTS 描述


1.2 功能概览

  • 默认每 200 ms 启动一次测量,允许 Kconfig 范围为 60~1000 ms。

  • TRIG 高电平 10 us,ECHO 等待上限 30 ms。

  • 原始距离有效范围为 20~4000 mm。

  • 使用当前最多 5 个有效样本的中值,再进行 alpha=0.25 的整数 EMA。

  • 距离连续 3 次不大于 200 mm 后报警;连续 3 次不小于 230 mm 后解除。

  • 连续 3 次无效进入故障;故障中连续 2 次有效后恢复。

  • LED:初始化快速闪烁、正常 500 ms 心跳、报警常亮、故障快速双闪。

  • LPUART0 输出详细调试信息;LPUART2 输出短格式结果。


1.3 设计思路

        硬件连接由 Devicetree (设备树) 描述,策略参数由 Kconfig 管理,C17 源码只通过 Zephyr GPIO、UART、消息队列、信号量和延迟工作 API 实现行为。软件 不直接操作寄存器,不使用动态内存,也不启用浮点 printf。

        队列生产者使用 K_NO_WAIT。队列满时先删除最旧数据,再写入最新 数据,因此输出端暂时变慢不会反向阻塞采集线程。每条消息按值复制, 不传递线程栈地址或临时缓冲区指针。


二、功能实现

2.1 软件流程图

mermaid-diagram-2026-09-14-200014.png


2.1.1 任务职责任务输入处理输出禁止事项

acquisition_task周期时基、HC-SR04触发、等待、脉宽及原始距离计算raw_msgq滤波、报警、LED、UART
processing_taskraw_msgq范围检查、滤波、报警、故障恢复LED 状态、processed_msgqHC-SR04、UART
output_taskprocessed_msgq格式化LPUART0、LPUART2传感器、滤波、报警状态修改


2.2 GPIO 双边沿测量原理

        采集线程在确认 ECHO 为低电平后清空完成信号量,在关中断保护下将 状态设为“等待上升沿”,随后输出 10 us TRIG 脉冲。GPIO 配置为双边沿 中断:

  1. 上升沿读取 k_cycle_get_32(),保存为 rise_cycle

  2. 下降沿再次读取 cycle counter,保存为 fall_cycle,结束本轮测量并 释放信号量。

  3. 线程最多等待 CONFIG_APP_HCSR04_ECHO_TIMEOUT_MS,默认 30 ms; 超时清除活动状态并返回 -ETIMEDOUT

  4. 以无符号减法 fall_cycle - rise_cycle 处理一次 32 位计数器回绕。

  5. 使用 k_cyc_to_us_floor64() 转为微秒。

        ISR 不打印日志、不访问 UART、不休眠、不滤波、不报警、不执行浮点 运算,也不等待消息队列。GPIO 回调和 cycle 转换 API 与用户真实 Zephyr checkout 的最终匹配为 [待用户验证]。


2.3 距离换算

声速按 343 m/s 取值,ECHO 是声波往返时间,因此:

distance_mm = echo_time_us × 343 / 2000

实现使用 64 位中间值:

distance_mm = (uint32_t)(((uint64_t)echo_time_us * 343U) / 2000U);

注:温度、湿度、目标材质、安装角度和换能器盲区都会产生误差,需通过标准距离实测确定是否需要标定。


2.4 中值和 EMA 滤波

        中值窗口最多保存 5 条有效距离。有效样本不足 5 条时对已有样本排序; 奇数条取中央值,偶数条取两个中央值的整数平均;5 条时取第三个值。 该级用于抑制偶发尖峰。

        第二级使用有符号 64 位中间量进行整数 EMA:

delta = median - filteredfiltered = filtered + delta / 4

        这样可避免无符号减法下溢。第一条有效数据直接初始化 EMA;无效数据 不更新滤波器;进入故障和故障恢复时执行重置,恢复样本重新初始化。


2.5 报警状态机

mermaid-diagram-2026-09-14-200621.png


        处于 200~229 mm 回差区间时保持当前报警状态并清除相反方向的连续 确认计数。故障状态优先级高于近距离报警;进入故障时清除近距离状态, 恢复后从 NORMAL 重新确认。


2.6 LED 状态

    processing_task 只提交逻辑状态。系统工作队列中的 k_work_delayable 负责实际闪烁,不在处理任务中 sleep:

状态LED 行为

初始化100 ms 翻转,快速闪烁
正常500 ms 翻转,心跳
近距离报警常亮
传感器故障亮 100 ms、灭 100 ms、亮 100 ms、灭 700 ms

        板载 LED 实际亮灭极性由 GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios) 处理,不在 C 代码中硬编码。[待用户验证]


2.7 LPUART0 和 LPUART2

        LPUART0 沿用板级 zephyr,console 和 P0_2/P0_3 pinctrl,通过 J15 以 115200 8N1 输出 Zephyr 延迟日志。应用 overlay 不重复配置该节点。

        LPUART2 在 overlay 中仅设置 status = "okay" 和 115200 波特率, 沿用板级 P3_14/P3_15 pinctrl。output_task 通过 Zephyr UART API 逐字节发送短数据包。默认单向使用只接 mikroBUS TX 和公共 GND

        协议定义示例(不是实测日志):

[DBG][seq=125] echo=1458 us raw=250 mm median=252 mm filtered=248 mm state=NORMAL err=0DIST,125,248,NORMALDIST,126,INVALID,TIMEOUT

        实际 LPUART0 前缀、调度时间、字符完整性和 LPUART2 波形均为 验证通过


三、功能展示

3.1 串口输出

2026-09-14-19-00-35.png


3.2 实测验证

        由于测试条件有限,这里只放了一把卷尺来作为测量结果的参照。需要更精确的测试结果需要制作成一个整体并尽量保证与被测物体的垂直。

20260914194745_6_319.jpg


四、总结

        这个项目虽小,但覆盖了嵌入式开发的完整链条:Devicetree 描述硬件、Kconfig 管理参数、RTOS 多任务与消息队列解耦、微秒级中断时序、数字滤波和状态机设计,全程零寄存器操作、零动态内存。

        最后,感谢电子产品世界联合得捷电子推出的这次活动,本次活动我接触到了 Zephyr 这个开源项目,并从中学到了 Zephyr 开发环境的搭建,基本外设的作用等知识。


五、传送门

【2026 Let's do 第2期】简易超声波测距仪实践开箱帖  

【2026 Let's do 第2期】简易超声波测距仪实践过程帖 


共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]