在过程贴中我们已经完成了OLED和HC-SR04的模块化写法,下面就是具体的实现步骤与功能演示。
1.系统框图详情
本项目采取基于FRDM-MCXA153开发板,外接超声波测距模块和0.96寸i2cOLED屏幕,以实现测距及显示功能,测距可精确到0.1cm,在OLED在显示的同时,也可通过J15板载调试串口COM5发送数据到电脑端。系统框图如下
2.电路原理图
根据电路 原理图,我们可以很清晰的知道电路的连接关系

3.主要引脚参数的具体配置和注意事项
在HC-SR04.c和HC-SR04.h中先写到对HC-SR04进行驱动,trig发送一个至少10us的高电平脉冲,后用CTIMER0(1MHz自由 运行定时器)测量echo高电平脉宽,除以58得到厘米(cm)。
在ssd1306.c和ssd1306.h中先对其进行驱动,LPI2C0通信+128*64帧缓冲+5*7点阵字库。
而后在pin_mux.c和pin_mux.h中进行引脚配置,trig(P3_15)输出,echo(P3_1)输入,SDA(P3_28),SCL(P3_27)占用LPI2C0外设。还得在hardware_init.c中挂起LPI2C0的时钟,CTIMER0的时钟,务必在prj.conf中加入driver.Ctimer和driver.lpi2c两个组件,不加会导致编译错误,缺少驱动driver。还需把新创建的文件在CMakeLists.txt中加入文件路径。

4.如何开启运行
首先确认硬件本身功能是否完好,而后检查接线是否正确。后打开Vscode,我是使用的官方提供的vscode扩展进行开发。正常按照扩展之后,左侧栏会出现一个X的标识,我们右键所开发的工程文件,即可完成编译烧录的工作。而后屏幕会出现一秒钟的白屏,串口会有以下输出。


5.实现步骤
步骤 1:建立工程骨架
以 SDK 的 `driver_examples/gpio/led_output` 示例为基础复制工程,
在 `CMakeLists.txt` 的 `mcux_add_source()` 中登记自己新增的源文件:
SOURCES main.c
hc_sr04.c
ssd1306.c
步骤 2:规划并配置引脚与外设
1. 选定各功能所用引脚(见 2.3),确保互不冲突。
2. 在 `frdmmcxa153/led_output/pin_mux.c` 的 `BOARD_InitPins()` 中;
- 使能对应 PORT 时钟:`CLOCK_EnableClock(kCLOCK_GatePORTn)`
- 释放对应 PORT 复位:`RESET_ReleasePeripheralReset(kPORTn_RST_SHIFT_RSTn)`
- 释放 外设自身复位(LPI2C0、GPIO3 等)
- 用 `PORT_SetPinConfig()` 设置每个引脚的复用值、上下拉、方向
3. 在 `frdmmcxa153/led_output/hardware_init.c` 中把 **FRO12M** 分别接到
LPI2C0 和 CTIMER0,并设置分频。
步骤 3:实现 HC-SR04 驱动
1. `HCSR04_Init()`
- 把 TRIG 配成输出、ECHO 配成输入
- 把 CTIMER0 配成 1 MHz 自由运行计数器(prescale = 11)
2. `HCSR04_MeasureEchoUs()`
- 发 20 µs 触发脉冲
- 轮询等 ECHO 上升沿 → 记下 `tStart`
- 轮询等 ECHO 下降沿 → 记下 `tEnd`
- 两个等待各自带超时计数,超时返回约定的错误码
- `tEnd - tStart` 即为高电平时长,并对 32 位回绕做补偿
3. `HCSR04_GetDistanceCm()` —— 时长 ÷ 58 得到厘米数
步骤 4:实现 SSD1306 驱动
分三层,自底向上实现:
第一层:I2C 通信
SSD1306_Init()` 里配置并启动 LPI2C0
ssd1306_send_command()` —— 发送控制字节 `0x00` + 命令
ssd1306_send_data()` —— 发送控制字节 `0x40` + 显存数据
ssd1306_probe_address()` —— 地址探测(起始 + 地址 + 1 字节 + 停止,取返回状态)
第二层:显存与刷新
- 定义与屏幕同构的帧缓冲 `s_framebuffer[8][128]`
(每个字节纵向装 8 个像素,bit0 是该页最上面一行)
- `SSD1306_Update()`:先设列范围 `0x21`、页范围 `0x22`,
再整块推送 1024 字节。
水平寻址模式下地址会自动递增,因此只需设置一次地址窗口
第三层:字符绘制
- 建 5×7 点阵字库表
- `ssd1306_draw_char()`:逐行逐列取字形位 → 按 `scale` 放大 →
按 `[py/8][px]` 定位、`1 << (py%8)` 置位 → 边界检查
- `SSD1306_DrawString()`:逐字符调用,每字符右移 `6 × scale` 像素
初始化命令序列(顺序不可随意调换):
```
0xAE 关显示(避免配置中途闪出乱码)
0xD5 0x80 时钟分频 / 振荡频率
0xA8 0x3F 扫描行数 = 64
0xD3 0x00 显示偏移 = 0
0x40 起始行 = 0
0x8D 0x14 使能电荷泵 ← 漏掉此项屏幕全黑,但 I2C 通信正常
0x20 0x00 水平寻址模式
0xA1 段重映射
0xC8 COM 反向扫描
0xDA 0x12 COM 引脚硬件配置
0x81 0xCF 对比度
0xD9 0xF1 预充电周期
0xDB 0x40 VCOMH 电平
0xA4 恢复显示(按显存内容)
0xA6 正常显示(非反色)
0xAF 开显示
```
步骤 5:主程序整合
1. `BOARD_InitHardware()` —— 时钟、引脚、串口
2. 红灯闪 3 次 —— 确认程序确实在运行(与串口、屏幕无关的独立指示)
3. `HCSR04_Init()`
4. `SSD1306_Init()` —— **返回值存入 `oledReady`,失败时仅跳过刷屏
5. 进入主循环(见第四节)
步骤 6:调试与验证
- 加入 HardFault 异常处理器,打印 CFSR / HFSR / MMFAR / BFAR 和出错 PC
- 加入 I2C 总线扫描,在地址不应答时区分"地址不对"与"设备不在总线上"
- 加入引脚电平采样与寄存器转储,用于判定故障在总线侧还是控制器侧
- OLED 初始化成功后做 1 秒全屏白屏自检。

本期活动的全部设计就差不多结束了,后面可以会加上中值和EMA滤波滤除一些野值,也可以使用开发板进行其他的项目设计,因为其的外设功能非常丰富。
我要赚赏金
