2、硬件连接与初始化:树莓派/ESP32引脚定义、I2C地址配置、SPI接线方式、电源与电平匹配、初始化序列代码实现。
好,咱们正式开始动手前的最后一步——把屏幕和主控板连起来。
这一步看着简单,但坑不少。我见过太多人代码写得飞起,结果屏幕死活不亮,最后发现是线接错了,或者电压没对上。所以这一节咱们把硬件连接和初始化序列彻底讲透。
2.1 引脚定义:先搞清楚屏幕上的每个焊盘
不管是0.96寸还是1.3寸的OLED模块,引脚定义基本一致。常见的接口有4针(I2C)和7针(SPI)两种。我习惯先看模块背面的丝印,确认是哪一种。
| 引脚名称 | I2C模式 | SPI模式 | 说明 |
|---|---|---|---|
| GND | 电源地 | 电源地 | 必须共地 |
| VCC | 3.3V / 5V | 3.3V / 5V | 看模块稳压器 |
| SCL / SCK | 时钟线 | 时钟线 | I2C和SPI共用 |
| SDA / MOSI | 数据线 | 主出从入 | I2C双向,SPI单向 |
| RES / RST | 可不接 | 复位 | SPI模式必须接 |
| DC | — | 数据/命令选择 | SPI模式必须接 |
| CS | — | 片选 | SPI模式必须接 |
2.2 I2C地址配置:为什么是0x3C还是0x3D?
SSD1306的I2C地址由硬件决定。看模块背面,如果有一个标注“ADDR”的焊盘或电阻,它的电平决定了地址。
- ADDR接GND:地址为0x3C(最常见)
- ADDR接VCC:地址为0x3D
我曾经在一个项目里,两块OLED共用一条I2C总线,一块设0x3C,另一块设0x3D,完美共存。如果你只接一块,默认0x3C基本不会错。
i2cdetect -y 1看到的0x3C,在代码里写地址时也是0x3C。有些库内部会左移一位,但大部分现代库已经帮你处理好了。
2.3 SPI接线方式:速度更快,但线更多
如果你需要高帧率刷新(比如显示动画或视频),SPI是更好的选择。我个人的经验是,SPI模式下刷新率可以轻松跑到30fps以上,而I2C通常只能到10fps左右。
以树莓派4B为例,SPI接线如下:
| OLED模块 | 树莓派GPIO | ESP32 GPIO |
|---|---|---|
| GND | GND (Pin 6) | GND |
| VCC | 3.3V (Pin 1) | 3.3V |
| SCK | GPIO 11 (Pin 23) | GPIO 18 |
| MOSI | GPIO 10 (Pin 19) | GPIO 23 |
| RES | GPIO 25 (Pin 22) | GPIO 16 |
| DC | GPIO 24 (Pin 18) | GPIO 17 |
| CS | GPIO 8 (Pin 24) | GPIO 5 |
2.4 电源与电平匹配:3.3V还是5V?
这个问题问的人最多。OLED模块的VCC标称范围通常是3.3V~5V,但内部有稳压器。你想想看,如果模块自带3.3V稳压器,你接5V进去,稳压器会发热,长期使用有风险。
我的建议:
- 树莓派:直接用3.3V供电,省事又安全
- ESP32:也是3.3V逻辑,直接对接
- STM32或Arduino:如果板子是5V逻辑,OLED模块的SCL和SDA需要加电平转换,或者用I2C电平转换模块
2.5 初始化序列代码实现
好了,线接好了,该写代码了。初始化序列说白了就是给屏幕发一串配置命令,让它进入工作状态。SSD1306的初始化序列是固定的,我直接给你一个经过验证的版本。
下面是一个Python示例,适用于树莓派和ESP32(MicroPython):
# OLED初始化序列(SSD1306 128x64)
def oled_init():
commands = [
0xAE, # 关闭显示
0xD5, 0x80, # 设置振荡频率
0xA8, 0x3F, # 设置多路复用比(64行)
0xD3, 0x00, # 设置显示偏移
0x40, # 设置显示起始行
0x8D, 0x14, # 启用电荷泵
0x20, 0x00, # 设置内存寻址模式(水平)
0xA1, # 段重映射(左右翻转)
0xC8, # COM扫描方向(上下翻转)
0xDA, 0x12, # 设置COM引脚配置
0x81, 0xCF, # 设置对比度
0xD9, 0xF1, # 设置预充电周期
0xDB, 0x40, # 设置VCOMH电压
0xA4, # 全局显示开启(不忽略RAM)
0xA6, # 正常显示(非反色)
0xAF # 开启显示
]
for cmd in commands:
send_command(cmd)
初始化完成后,别忘了清屏。清屏就是把整个GRAM(显存)写0:
def oled_clear():
for page in range(8): # 128x64 = 8页,每页8行
set_page_address(page)
set_column_address(0)
for col in range(128):
write_data(0x00) # 每个字节8个像素全灭
嗯,这里要注意:清屏操作虽然简单,但如果你用I2C模式,每写一个字节都要发一次起始信号和地址,128×8=1024个字节,速度会慢一些。SPI模式就快多了,连续发1024个字节,一气呵成。
2.6 知识结构总览
我把这一节的核心逻辑画成了一张图,方便你对照理解:
这张图把整个流程串起来了。你从硬件连接开始,选好接口模式,配好地址或接线,搞定电平,最后用代码初始化。每一步都有坑,但每一步也都有解法。