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

共1条 1/1 1 跳转至页

【let'sdo|2026年第2期】简易超声波测距仪实践【成果篇】

菜鸟
2026-10-09 15:10:01     打赏

开箱贴之后拖了好一阵子,中间被几个坑卡住,终于把这个超声波测距仪跑通了。这篇帖子记录一下实际的实现过程、遇到的问题,以及最终效果。

先放结果:测距范围实测约 4cm ~ 180cm,精度在 ±1cm 以内,LCD 每 200ms 刷新一次。距离值稳定,没有明显的跳变。

image.png


接线情况:

模块引脚FRDM-MCXA153备注
HC-SR04VCC5V(Arduino 排针)模块需 5V 供电
HC-SR04TrigP2_33.3V 可直接触发
HC-SR04EchoP2_4经电阻分压(1kΩ + 2kΩ)
LCDVSS / KGND
LCDVDD / A5V背光串 100Ω 限流
LCDV010kΩ 电位器中点调对比度
LCDRSP2_5
LCDRWGND只写模式
LCDEP2_6
LCDD4~D7P2_7、P3_0、P3_1、P3_24-bit 模式

Echo 的分压是必须的。HC-SR04 输出 5V 电平,MCXA153 的 GPIO 耐压是 3.3V。1kΩ 串在 Echo 和 GPIO 之间,2kΩ 下拉到地,分压后约 3.33V,刚好在安全范围内。

超声波测距

HC-SR04 的时序很简单:Trig 拉高至少 10µs 触发,然后 Echo 输出高电平,持续时间就是声波往返时间。距离换算用 距离(cm) = Echo高电平时间(µs) / 58。

计时方案用 CTimer。MCXA153 没有 MRT 外设,但 CTimer 完全可以胜任微秒级计时。SDK 里有现成的 ctimer 示例可以参考。我开了 CTimer 的输入捕获通道,捕获 Echo 的上升沿和下降沿,两个时间戳相减就是高电平持续时间。不过实际调试时发现输入捕获的配置有点绕,后来简化成了 GPIO 中断 + CTimer 读计数值的方式,更直观也好调试。

测距周期用了 200ms。HC-SR04 官方建议测量周期不低于 60ms,避免上一次的回波干扰下一次触发。200ms 留了足够余量,LCD 刷新也不会闪。

LCD 驱动

NHD-0116AZ 用的是 ST7066U 控制器,兼容 HD44780 指令集,4-bit 模式只需要 6 根信号线(RS、E、D4-D7),RW 接地。4-bit 模式下每个字节要发两次:先高 4 位,再低 4 位,每次都要给 E 一个脉冲。

初始化序列是第一个坑。HD44780 上电后默认是 8-bit 模式,要切到 4-bit 必须按特定顺序发送命令,而且对延时敏感。我一开始没严格按手册的延时来,LCD 直接没反应。后来老老实实加了 40ms 上电延时,然后按 0x33 → 0x32 → 0x28 → 0x0C → 0x06 → 0x01 的顺序初始化,一次就亮了。

显示内容很简单,就一行:DIST: 123.4 cm。超过量程时显示 OVER RANGE,无回波显示 NO ECHO。

下面是主程序:


int main(void) {
    BOARD_InitBootPins();
    BOARD_InitBootClocks();
    
    CTimer_Init();          // 微秒计时
    LCD_Init();             // 4-bit 模式初始化
    Ultrasonic_Init();      // Trig 输出、Echo 中断
    
    LCD_Print("DIST: ---.- cm");
    
    while (1) {
        uint32_t pulse = Ultrasonic_Measure();  // 返回高电平 µs
        
        if (pulse == 0) {
            LCD_Print("NO ECHO        ");
        } else if (pulse > 12000) {  // 约 200cm
            LCD_Print("OVER RANGE     ");
        } else {
            float dist = pulse / 58.0f;
            char buf[17];
            snprintf(buf, sizeof(buf), "DIST: %5.1f cm", dist);
            LCD_Print(buf);
        }
        
        SDK_DelayAtLeastUs(200000, 96000000);  // 200ms
    }
}

Ultrasonic_Measure 里:Trig 拉高 10µs 再拉低,然后等 Echo 中断更新脉冲宽度,超时(约 30ms 无回波)就返回 0

static void i2c_start(void)
{
    sda_high(); scl_high(); i2c_delay();
    sda_low();  i2c_delay();
    scl_low();  i2c_delay();
}
static uint8_t i2c_write_byte(uint8_t data)
{
    for (uint8_t i = 0; i < 8; i++) {
        scl_low();
        if (data & 0x80) sda_high(); else sda_low();
        data <<= 1;
        i2c_delay();
        scl_high();
        i2c_delay();
    }
    scl_low();
    sda_dir_input();
    i2c_delay();
    scl_high();
    i2c_delay();
    uint8_t ack = sda_read();
    scl_low();
    sda_dir_output();
    i2c_delay();
    return ack;  
}

FRDM-MCXA153 做这个项目挺顺手的。CTimer 的微秒计时精度够用,Arduino 排针引出 5V 和 GPIO 很方便。板子自带的 MCU-Link 调试器省了外接调试器,VS Code 里直接断点单步,调时序问题的时候帮了大忙。

这次超声波测距仪算是把 GPIO、定时器、LCD 驱动串了一遍,后面打算把板载的 P3T1755 温度传感器也用上,做一个“距离 + 温度”双显示的小工具,毕竟声速也受温度影响,理论上可以做温度补偿。





共1条 1/1 1 跳转至页

回复

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