【瑞萨BLE/WI-FI模块测评】超声波双通路(一)——板子怎么插、超声波怎么测

2026.10.02 | 焜财商富 | 31138次围观

拿到这套瑞萨生态工作室的板子和两个无线模组之后,我想做个稍微完整一点的东西:一个超声波近场测距终端,距离数据同时通过WiFi推到网页、通过BLE透传到手机,哪边方便看哪边。

这是三篇里的第一篇,先把硬件和最底层的测距逻辑讲清楚。WiFi网页和BLE手机端分别放在后两篇。

我的板子和套件

主控是生态工作室的RA4M2 v2.0开发板,芯片R7FA4M2AD,Cortex-M33内核跑100MHz。板上自带三个LED、两个触摸按键TS1/TS2,还有一个板载USB转串口接SCI9,烧录走J-Link SWD。

无线部分用了两个Digilent标准PMOD:

DA16200 Wi-Fi PMOD:插右侧PMOD2,走SCI0(UART),负责连路由器、做TCP客户端

DA14531 BLE PMOD:插左侧PMOD1,走SCI4(另一路UART),CodeLess固件透传

外加一个最常见的HC-SR04超声波模块,四根杜邦线引出来。

wKgZPGq48gSAABdKAAC6eD6nQgI992.png

硬件全景

整个系统长这样——中间RA4M2,左右两个PMOD板插在标准座子上,HC-SR04用线引到板子左上角。USB线插板载口供电,同时出来调试日志。

引脚怎么分配的

PMOD座子占用的脚是固定的,我没动:

功能 MCU脚 说明
WiFi UART TX/RX P411/P410 PMOD2,115200
WiFi RESET/LPR P608/P609 控制脚
BLE UART TX/RX P205/P206 PMOD1,115200
BLE RESET/LPR P403/P402 控制脚
调试串口 P109/P110 SCI9,CH340

HC-SR04是新加的,选脚的时候特意避开了所有PMOD占用的位置,最后定在:

VCC → 3V3(这个模块是3.3V兼容版,千万别接5V)

GND → GND

TRIG → P103(MCU输出,给10us触发脉冲)

ECHO → P104(MCU输入,读回响脉宽)

接线其实很简单,四根线。我手放在超声波前面比划的时候,板子上两个蓝灯已经亮了,说明WiFi和TCP都连上了。

硬件介绍

HC-SR04到底怎么测距的

这个模块用的人太多了,但我还是想把时序和原理掰开讲一下,因为代码里计时那部分是自己写的,不是用定时器输入捕获。

模块上电后处于静默状态。MCU给TRIG脚一个至少10us的高电平脉冲,模块内部就会自动发出8个40kHz的超声波脉冲串,同时把ECHO脚拉高。超声波碰到障碍物反射回来,模块收到回波后立刻把ECHO拉低。

所以ECHO高电平的持续时间,就是声波"去+回"的飞行时间。

wKgZO2q47suAD0PcAAC9aar4BCQ845.png

HC-SR04时序

换算关系很直接:声速按340m/s算,距离 = 声速 × 时间 / 2。工程上大家都用一个近似公式:

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

这个58怎么来的?声速340m/s = 0.034cm/μs,往返除以2就是0.017cm/μs,反过来1cm对应约58.8μs。模块手册直接取58,够用了。

为什么用DWT计时而不是定时器

ECHO脉宽可能从几百μs到30ms不等(对应约2cm到5m)。最常规的做法是用定时器输入捕获,硬件自动记录上升沿和下降沿的计数值。但我这边RA4M2的定时器资源已经被AGT占了一个做软件时基,再配输入捕获有点绕。

CM33内核自带DWT(Data Watchpoint and Trace)单元,里面有个CYCCNT计数器,每个CPU周期加1。RA4M2跑100MHz,就是10ns加一次——分辨率比绝大多数定时器都高。

初始化就三行:

CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;  // 使能跟踪
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;             // 启动周期计数

然后测ECHO上升沿到下降沿之间的cycle数,除以系统时钟频率(100000000),乘1000000就得到微秒数。代码里做了个30ms超时保护,测不到回波就直接返回timeout,不会卡死在循环里。

整个read函数就是:拉低TRIG → 延时2us → 拉高TRIG 10us → 拉低 → 等ECHO上升沿开始计时 → 等ECHO下降沿结束计时 → 算距离。轮询读GPIO,没用中断,因为40ms才采一次,轮询完全来得及。

原始数据为什么不能直接用

HC-SR04有个老问题:近距离或者表面倾斜的物体,回波会有毛刺。有时候明明手放在30cm不动,读数会突然跳一下到15cm,下一拍又跳回来。直接拿去做报警判断肯定要误触发。

我的滤波链是这样的:

数据流水线

第一道:3点中值滤波。 取最近3次采样排序,取中间值。这种方法对"偶发跳一个点"的毛刺特别有效——三个数里哪怕一个是错的,排完序取中间就把它扔掉了。比滑动平均抗脉冲干扰强得多,因为平均会把毛刺的影响摊到后面好几拍。

第二道:2点滑动平均。 中值输出再过一个2窗口的均值,让数值看起来不那么一格一格跳。窗口只取2是因为响应速度优先——这是个近场报警,手伸进来要赶紧报出来,不能被滤波拖半秒。

第三道:跳变检测。 这是个特殊处理。如果新值和上次滤波结果差了8cm以上,说明不是毛刺而是真的有东西突然靠近/远离(手伸进来了),这时候直接把滤波器的缓冲区全部重置成新值,输出直接跳变。正常情况下中值+MA是慢慢收敛的,手一伸进来要等好几个周期才能跟上,跳变检测就是解决这个问题的。

三个参数都是在app_config.h里调的:中值窗口3、MA窗口2、跳变阈值8cm。采样周期40ms,也就是每秒25次。

报警为什么要带回滞

距离阈值默认30cm,低于这个数就报警。但如果就定在30cm一个点上,手在30cm附近抖一下,报警就会疯狂地开了关、关了开——LED闪个不停,网页上红色界面来回切,BLE也一顿一顿地发。

标准解法是加回滞(hysteresis):

wKgZO2q47suAPMWZAAFPJYeuRpY928.png

报警状态机

距离 ≤ 30cm → 触发报警

距离 > 33cm → 解除报警

30~33cm之间 → 保持当前状态不变

这样手要先越过30cm才报警,然后必须退到33cm以外才解除,中间3cm的"死区"把临界点的抖动吃掉了。代码里就是两个判断:

clear_level = threshold + hysteresis;  // 33cm
if (dist <= threshold)       alarm = true;
else if (dist > clear_level) alarm = false;
// else: deadband, 什么都不做

除了自动报警,还有个手动消警的概念。报警响了之后可以点网页上的"消警"按钮、BLE发个ACK、或者触摸板上的TS2,LED立刻灭。但这时候手如果还在30cm以内,MCU只是"假装没看见",不会重新报警——直到手退过33cm再伸进来才会重新触发。这个设计在实际用的时候挺合理的:比如人已经走到障碍物旁边知道有危险了,不想让LED一直闪,就手动按一下消掉。

固件长什么样

整个工程分四层,从下往上:

wKgZPGq47syAPyCoAAE_VPmZ-OE366.png

软件分层

最底下是瑞萨FSP包,SCI、IOPORT、CTSU触摸这些都由配置工具生成。往上是驱动层:hc_sr04.c管超声波计时,da16200_AT.c管WiFi模组的UART收发,ble_transport.c管BLE模组。再上面是业务逻辑:滤波、报警状态机、BLE ASCII协议解析。最顶层是主循环状态机,管采样调度、LED、触摸按键、命令分发。

wKgZO2q48gSAKKJWAADHwWL7Q3Q457.png

板卡LED

板子上电后,LED1(WiFi连接)和LED2(TCP连接)两个蓝灯亮起来,就说明链路通了。这时候用手在超声波前面晃,网页上的数字会跟着变——下一篇我就讲这个网页是怎么搭起来的。

下一篇预告:DA16200怎么用AT指令连路由器、怎么作为TCP客户端把JSON推到PC上,FastAPI桥和网页界面是怎么写的。

审核编辑 黄宇