在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开发板,可以设置相关内容如下

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

在上一篇帖子中,我已经介绍了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);
}
}实现效果如下

工程代码如下
我要赚赏金
