最近用 NXP 的 FRDM-MCXA153 开发板做了一个入门练习:驱动 HC-SR04 类超声波模块测距,再把结果实时显示到 16×1 字符液晶上,同时通过串口把数据传到 PC。整体目标很明确——每 500ms 采集一次距离,LCD 显示 Dist: 123.4 cm,串口同步输出。
硬件清单与连接
用到的器件不多:
FRDM-MCXA153 开发板(MCXA153,Cortex-M33)
超声波模块 3942(HC-SR04 兼容)
NHD-0116AZ-FL-YBW 字符 LCD(HD44780 兼容,16×1)
接线方面,超声波模块的 Trig 接 D2(P2_4,GPIO 输出),Echo 接 D4(P2_5,GPIO 输入)。LCD 采用 4 位总线、只写模式:RS 接 D7(P3_1),E 接 D8(P3_15),DB4~DB7 分别接 D9/D10/D11/D12(P3_14 / P2_6 / P2_13 / P2_16),R/W 直接接地。两块模块都通过杜邦线插在 Arduino 排针上。LCD 的 V0 接 10kΩ 电位器调对比度,背光串限流电阻后接 5V——这里我用另一块开发板提供 5V 供电。


软件结构
工程基于 MCUXpresso SDK 裸机框架,用户代码集中在 source 目录下,主要包含几个部分:
app_delay.h:延时和计时全部基于 DWT->CYCCNT 周期计数器实现,提供 APP_DelayUs、APP_DelayMs、APP_GetTick、APP_Elapsed 等接口。好处是不占用任何定时器外设,也不需要中断。
ultrasonic.c/h:Trig 先发 10µs 高电平脉冲,然后轮询 Echo,用 DWT 计数测量高电平脉宽,按 时间(µs) × 0.0343 cm/µs ÷ 2 换算距离。超时 60ms 返回 -1.0f,表示没有回波。
lcd1602.c/h:4 位数据总线、只写模式驱动。
NXP.c:主循环每 500ms 测一次,刷新 LCD,并通过 LPUART0(115200)用 PRINTF 输出。

调试中遇到的几个问题
1. Echo 始终读到 0
MCXA153 的外设上电后处于复位保持状态,用 GPIO 之前必须调用 CLOCK_EnableClock() 和 RESET_ReleasePeripheralReset()。更隐蔽的是,PORT_SetPinMux() 只负责设置 MUX,并不会使能输入缓冲 IBE。必须改用 PORT_SetPinConfig(),并把 inputBuffer 设为 kPORT_InputBufferEnable,否则 GPIO_PinRead() 永远返回 0。这个问题排查花了最长时间。
2. LCD 只显示 8 个方块
NHD-0116AZ 用的是 ST7066U,1/16 Duty,内部 DDRAM 实际是 8×2 结构:物理第 1~8 列对应 0x00~0x07,第 9~16 列对应 0x40~0x47。所以 Function Set 必须用 0x28(4 位 / 2 行,N=1)。如果用 0x20,控制器只扫描 COM0~7,右半边直接没信号。驱动里我在第 8 列自动切换 DDRAM 地址来解决。
3. 复位后屏幕内容每次都不一样
根因是复位释放到 LCD_Init() 之间有 1~3ms 总线悬空。E 是下降沿锁存,噪声抖出一个沿就可能被当成“写数据”,随机字节进了 DDRAM。软件上在 main() 第一句加 LCD_BusIdle(),把窗口缩短到 0.3ms,但根治还是要靠硬件——E 和 RS 各加 10kΩ 下拉到 GND。
4. 延时基准不可信
BOARD_InitBootClocks() 是空函数,系统跑的是复位默认时钟,而 SystemCoreClock 只是 C 语言初值,从未和寄存器校验过。一旦不一致,所有延时都会按比例缩放,LCD 时序直接不达标。解决办法是在 APP_InitDelay() 里先调用 SystemCoreClockUpdate()。
最终效果
上电后 LCD 稳定显示 Dist: xx.x cm。拿手掌在 5~150cm 范围内移动,读数跟随流畅,没有明显跳变;超出量程或无回波时显示 Dist: ---- cm,串口同步打印 Distance: ---- cm。
小结
这个项目代码量不到 500 行,但覆盖了嵌入式入门容易翻车的几个点:外设复位释放、输入缓冲配置、复用功能与时序、时钟基准校验、5V/3.3V 电平兼容。建议在做 GPIO 采集类实验时,先单独验证“读数是否真实”——比如把 Echo 脚接 3.3V,确认 GPIO_PinRead 能读到 1,再往上叠算法,能省下大量调试时间。
我要赚赏金
