这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » Let'sdo2026年第2期—基于FRDM-MCXA153的简易超声波测距仪

共1条 1/1 1 跳转至页

Let'sdo2026年第2期—基于FRDM-MCXA153的简易超声波测距仪

工程师
2026-10-07 22:54:50     打赏

在Let'sdo2026年第2期—开箱与硬件连接-电子产品世界论坛帖子中我介绍了开发板与HC-SR04超声波模块以及0.91寸OLED屏幕连接方式,在Let'sdo2026年第2期—OLED驱动-电子产品世界论坛帖子中我介绍了驱动0.91寸OLED屏幕的方法

在VS Code中,可以安装MCUXpresso for VS Code实现VS Code中的NXP MCU开发,对于FRDM-MCXA153开发板,可以设置相关内容如下

image.png

接着在MCUXpresso Config Tools中设置相关引脚定义

image.png

在上一篇帖子中,我已经介绍了OLED屏幕的驱动方案,接下来我将介绍一下HC-SR04超声波模块的驱动方案

计算从 startTicks 到当前时刻经过的 tick 数。SysTick 是向下递减计数器,所以用 (startTicks - 当前值)& SysTick_LOAD_RELOAD_Msk 处理计数器回绕(24 位溢出),保证结果落在有效范围内。

static uint32_t SR04_ElapsedTicks(uint32_t startTicks)
{
    return (startTicks - SysTick->VAL) & SysTick_LOAD_RELOAD_Msk;
}

对于 Echo 引脚,循环中不断检测该引脚,一旦达到目标电平返回 true;如果超过 timeoutTicks 仍没等到,返回 false(超时保护,防止死循环)。

static bool SR04_WaitForEcho(uint32_t level, uint32_t timeoutTicks)
{
    uint32_t startTicks = SysTick->VAL;

    while (GPIO_PinRead(SR04_GPIO, SR04_ECHO_PIN) != level)
    {
        if (SR04_ElapsedTicks(startTicks) >= timeoutTicks)
        {
            return false;
        }
    }
    return true;
}

SR04初始化,其流程如下

1. Trig 引脚配置为数字输出(初始低电平),Echo 引脚配置为数字输入。

2. 配置 SysTick:停止计数器 → 装载最大重装值(24 位满量程,得到最长计时窗口)→ 清当前值 → 启用并以处理器时钟(CLKSOURCE=1)开始运行。

void SR04_Init(void)
{
    const gpio_pin_config_t triggerConfig = {kGPIO_DigitalOutput, 0U};
    const gpio_pin_config_t echoConfig = {kGPIO_DigitalInput, 0U};

    GPIO_PinInit(SR04_GPIO, SR04_TRIGGER_PIN, &triggerConfig);
    GPIO_PinInit(SR04_GPIO, SR04_ECHO_PIN, &echoConfig);

    SysTick->CTRL = 0U;
    SysTick->LOAD = SysTick_LOAD_RELOAD_Msk;
    SysTick->VAL = 0U;
    SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk;
}

执行一次完整测距,其流程如下:

1. 计算 30ms 超时对应的 tick 数。

2. 空指针检查,参数无效直接返回 false。

3. 触发时序:Trig 拉低 2µs → 拉高 10µs → 拉低,产生超声波触发脉冲。

4. SR04_WaitForEcho(1) 等待 Echo 上升沿(模块发出超声波)。

5. 记录 pulseStart,再 SR04_WaitForEcho(0) 等待 Echo 下降沿(收到回波)。

6. 计算高电平脉宽 tick 数 pulseTicks。

7. 距离换算:distance = pulseTicks × 声速(343000 mm/s) / (2 × SystemCoreClock)。除以 2 是因为声波往返,乘 64 位避免溢出。结果单位为毫米,成功返回 true。

bool SR04_MeasureMillimeters(uint32_t *distanceMillimeters)
{
    uint32_t timeoutTicks = (SystemCoreClock / 1000000U) * SR04_TIMEOUT_US;
    uint32_t pulseStart;
    uint32_t pulseTicks;

    if (distanceMillimeters == NULL)
    {
        return false;
    }

    GPIO_PinWrite(SR04_GPIO, SR04_TRIGGER_PIN, 0U);
    SDK_DelayAtLeastUs(2U, SystemCoreClock);
    GPIO_PinWrite(SR04_GPIO, SR04_TRIGGER_PIN, 1U);
    SDK_DelayAtLeastUs(10U, SystemCoreClock);
    GPIO_PinWrite(SR04_GPIO, SR04_TRIGGER_PIN, 0U);

    if (!SR04_WaitForEcho(1U, timeoutTicks))
    {
        return false;
    }

    pulseStart = SysTick->VAL;
    if (!SR04_WaitForEcho(0U, timeoutTicks))
    {
        return false;
    }
    pulseTicks = SR04_ElapsedTicks(pulseStart);

    *distanceMillimeters = (uint32_t)(((uint64_t)pulseTicks * SR04_SOUND_MM_S) /
                                      (2ULL * SystemCoreClock));
    return true;
}

基于以上SR04驱动和上一篇帖子中OLED屏幕驱动,在主程序中,只需完成初始化,将SR04得到的距离信息显示到OLED屏幕上即可,同时我还增加了串口功能,实现了将距离信息输出到串口

主程序如下

int main(void)
{
    char displayText[24];
    char uartText[40];
    uint32_t distanceMillimeters;
    bool oledReady;
    bool uartReady;

    BOARD_InitHardware();
    uartReady = InitUart();
    SR04_Init();
    oledReady = SSD1306_Init();

    while (1)
    {
        if (SR04_MeasureMillimeters(&distanceMillimeters))
        {
            (void)snprintf(displayText, sizeof(displayText), "Distance:%lu.%lu cm",
                           (unsigned long)(distanceMillimeters / 10U),
                           (unsigned long)(distanceMillimeters % 10U));
            (void)snprintf(uartText, sizeof(uartText), "Distance: %lu.%lu cm\r\n",
                           (unsigned long)(distanceMillimeters / 10U),
                           (unsigned long)(distanceMillimeters % 10U));
        }
        else
        {
            (void)strcpy(displayText, "Out of range");
            (void)strcpy(uartText, "Distance: out of range\r\n");
        }

        if (oledReady)
        {
            SSD1306_Clear(false);
            SSD1306_DrawString(0U, 12U, displayText, true, false);
            oledReady = SSD1306_Update();
        }
        if (uartReady)
        {
            uartReady = LPUART_WriteBlocking(LPUART0, (const uint8_t *)uartText, strlen(uartText)) == kStatus_Success;
        }
        SDK_DelayAtLeastUs(1000000U, SystemCoreClock);
    }
}

实现效果如下

7aefdd3af40073fe1e71dc958f98f707.gif

工程代码如下

lcd.zip




关键词: 简易超声波测距仪     FRDM-MCXA153     超声波    

共1条 1/1 1 跳转至页

回复

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