1.硬件介绍

这里一共两个硬件,一个是esp32-wroom-32,另一个是7针ssd1309 oled显示屏。分别如下图:
7针ssd1309 oled显示屏
在这里插入图片描述
oled显示屏可以多看几家,同样的产品价格还是差距挺大的。

2.接线连接

7针oled显示屏是SPI通信,共有7根接线。分别是GND,VCC,SCL,SDA,RES,DC,CS。其中注意VCC一定要接3.3V,不能接5V。SCL和SDA应该是IIC中通信信号,在SPI中对应的就是SCK和MOSI。剩下的RES,DC直接选择普通的支持IO输出接口即可。关于SCK和MOSI,CS,SCL和SDA可以看一下下面这个图。
在这里插入图片描述
看一下图中SPI对应颜色的端口,即可选出对应的引脚。
我这里选用的是:

名称 引脚
SCL 18
SDA 23
RES 22
DC 5
CSL 21

3.程序编写

#include <U8g2lib.h>  // 包含U8g2库
#include <SPI.h>      // 包含SPI库

// 使用硬件SPI的构造函数
// 参数依次:旋转方向、时钟(SCK)、数据(MOSI)、片选(CS)、数据/命令(DC)、复位(RST) 231821225
U8G2_SSD1309_128X64_NONAME0_1_4W_HW_SPI u8g2(U8G2_R0, /* cs=*/ 5, /* dc=*/ 21, /* reset=*/ 22);

void setup(void) {
  u8g2.begin();  // 初始化U8g2库
  u8g2.setFont(u8g2_font_ncenB08_tr); // 设置字体
}

void loop(void) {
  u8g2.firstPage(); // 开始绘制页面
  do {
    u8g2.drawStr(0, 20, "Happy Teachers' Day"); // 在坐标(0,20)绘制字符串
    u8g2.drawStr(0, 50, "welcome to 410 , 412");  // 在坐标(0,40)绘制字符串
    // 你可以在这里添加更多的绘制函数,如画线、画框等
  } while (u8g2.nextPage()); // 结束绘制页面并发送到显示器
  delay(1000);
}

这里一开始看网上的资料以及买的显示屏送的资料都不匹配,因为之前没接触过,其中也用了一下ssd 1309,1306的库,都是一堆问题。回归本质,简单了很多。这里也简单介绍一下SPI通信的原理,做个记录,感兴趣的也可以看看。

4.SPI通信

4.1 什么是SPI?

SPI(Serial Peripheral Interface),中文叫串行外设接口,是一种由摩托罗拉公司开发的同步、全双工的串行通信协议。

它被广泛应用于微控制器(如ESP32、Arduino)与各种外设(如传感器、存储器、SD卡、显示屏等)之间的短距离、高速通信。


核心思想:主从模式

SPI通信采用主从(Master-Slave) 架构。

  • 主设备 (Master):通常是微控制器(如你的ESP32)。它控制通信的节奏(产生时钟信号),并发起数据传输。
  • 从设备 (Slave):外围设备(如你的SSD1309 OLED屏幕)。它接收主设备的指令并响应,不能主动发起通信。

一个主设备可以同时控制多个从设备。


关键信号线(4根基本线)

SPI通信通常需要至少4根线(这就是为什么你的OLED是7针,它包含了电源和这4根数据控制线):

缩写 全称 方向(对主设备而言) 作用
SCK Serial Clock 输出 时钟信号。由主设备产生,用于同步数据传输。每一个时钟脉冲就传输一位数据。
MOSI Master Out, Slave In 输出 主设备输出,从设备输入。主设备通过这条线发送数据给从设备。
MISO Master In, Slave Out 输入 主设备输入,从设备输出。从设备通过这条线发送数据给主设备。
CS/SS Chip Select / Slave Select 输出 片选信号(或从设备选择)。由主设备控制,用于选择要通信的特定从设备。低电平有效

如何理解这4根线?
想象一个老师(主设备)和多个学生(从设备)的课堂:

  • SCK:老师拍手的节奏。“啪,啪,啪…” 每拍一次手,就传递一个信息。
  • MOSI:老师对学生说话。
  • MISO:学生对老师说话。
  • CS:老师点名。“小明(将小明的CS线拉低),你来回答”。其他没被点名的学生(CS线为高电平)就会忽略老师的讲话。

4.2 工作原理:数据移位与同步

SPI通信的核心是一个移位寄存器

  1. 初始化:主设备将想要通信的从设备的CS引脚拉低(激活它)。
  2. 同步:主设备开始产生SCK时钟脉冲。
  3. 传输
    • 在每一个时钟脉冲下,主设备通过MOSI线发送1位数据给从设备。
    • 同时,从设备也通过MISO线发送1位数据给主设备。
  4. 完成:8个时钟脉冲后,主设备和从设备就互相交换了一个字节(8位)的数据。传输完成后,主设备将CS引脚拉高(取消选择)。

这个过程就是SPI “全双工” 的体现:数据在同时双向地流动。

图示帮助理解:
想象主设备和从设备内部各有一个8位的移位寄存器,并且通过MOSI和MISO连接成一个大的16位循环寄存器。时钟脉冲一来,所有数据就向右移动一位。8个脉冲后,主设备寄存器里的数据就移到了从设备里,而从设备的数据也移到了主设备里。

主设备移位寄存器       从设备移位寄存器
[ABCDEFGH]  <--->  [abcdefgh]
    MOSI ---->---->----> MISO
    MISO <----<----<---- MOSI
    SCK  ---->---->----> SCK
(每个时钟周期,数据沿箭头方向移动一位)

如何连接多个从设备?

有两种常见方式:

  1. 独立CS(推荐):主设备为每个从设备提供一个独立的CS引脚。一次只将一个CS拉低,与其他从设备通信时互不干扰。

  2. 菊花链(Daisy-Chaining):所有从设备的MISO和MOSI首尾相连。数据需要从一个设备传到下一个设备。这种方式节省GPIO引脚但软件更复杂,并非所有设备都支持。


4.3 SPI的优点和缺点

优点 缺点
速度快:远高于I2C和UART。 需要更多引脚:每增加一个从设备,至少多一根CS线。
全双工:可以同时收发数据,效率高。 没有硬件应答机制:主设备无法知道从设备是否成功接收到数据。
协议灵活:没有严格的数据格式限制。 通信距离短:通常用于板级通信,不适合长距离传输。
软件实现简单 没有寻址机制:完全依靠硬件片选(CS)线来选择设备。

4.4 总结与你的OLED屏幕的联系

对于你的ESP32和SSD1309 OLED屏幕:

  • ESP32主设备 (Master)
  • SSD1309从设备 (Slave)
  • 你连接了 SCK (时钟)、MOSI (数据)、CS (片选)、DC (数据/命令控制,可视为一条额外的控制线) 和 RST (复位)。
  • 当ESP32想要在屏幕上绘图时,它:
    1. 将OLED的CS引脚拉低(选中它)。
    2. 根据要发送的是数据还是命令,设置DC引脚的电平(高或低)。
    3. 产生SCK时钟信号。
    4. 通过MOSI线将像素数据或命令指令一位一位地发送给屏幕。
    5. 发送完毕后,将CS拉高。

而你使用的 U8g2库 已经帮你封装好了所有这些底层的、复杂的SPI时序操作,你只需要调用简单的函数,如 drawStr(),库就会自动通过SPI总线帮您完成与屏幕的通信。

下面再介绍一下IIC通信用作记录,感兴趣的也可以看一下。

5.IIC通信

好的,我们来详细讲解I2C通信(也常被写作IIC)。它会和刚刚介绍的SPI形成非常有趣的对比。

5.1 什么是I2C?

I2C(Inter-Integrated Circuit),中文叫集成电路总线,是一种由飞利浦公司开发的同步、半双工的串行通信协议。

它的设计初衷是提供一种用最少连线就能让芯片之间互相通信的方式。它非常适合连接各种低速外设,如传感器、EEPROM、RTC时钟、以及很多型号的OLED屏幕。


核心思想:主从模式 + 地址寻址

和SPI一样,I2C也采用主从(Master-Slave) 架构。

  • 主设备 (Master):控制通信节奏(产生时钟)并发起通信的设备(如你的ESP32)。
  • 从设备 (Slave):响应主设备请求的外设(如温度传感器、OLED屏幕)。

关键区别在于寻址方式

  • SPI使用硬件片选(CS)线来选择从设备。
  • I2C使用软件地址来选择从设备。每个I2C从设备都有一个唯一的7位(或10位)地址。

关键信号线(2根线!)

这是I2C最大的优势:只需要两根线就可以连接多个设备。

缩写 全称 作用
SDA Serial Data 串行数据线。用于主设备和从设备之间双向传输数据。
SCL Serial Clock 串行时钟线。由主设备产生,用于同步所有设备的数据传输。

所有设备都并联在这两条总线上,形成如下拓扑结构:

主设备 (ESP32)
   |
  SDA  ---¬
   |      |
  SCL  ---¬
   |      |      |
从设备1 从设备2 从设备3 ... (OLED, 传感器等)

5.2 工作原理:复杂的协议帧

I2C的通信过程比SPI更复杂,因为它要在两根线上实现所有功能,包括寻址、读写控制和数据确认。

一次完整的I2C通信数据帧通常包含以下几部分:

1. 起始条件 (Start Condition)
  • 主设备在SCL为高电平期间,将SDA从高电平拉低
  • 这个独特的下降沿信号告诉总线上所有从设备:“注意,通信要开始了!”。
2. 地址帧 (Address Frame)
  • 主设备发送一个7位(或10位)的从设备地址,后面跟1位读写控制位
  • 读写位 (R/W#)
    • 0:表示主设备要写数据到从设备。
    • 1:表示主设备要向从设备读数据
  • 例如,发送 0x3C(地址) + 0(写),意思是“呼叫地址为0x3C的设备,我要给你发数据”。
3. 应答位 (ACK / NACK)
  • 发送完每个字节(8位)后,发送方(无论是主还是从)会释放SDA线。
  • 接收方需要在第9个时钟脉冲期间,将SDA线拉低,以此向发送方发送一个应答(ACK) 信号,表示“字节已成功收到!”。
  • 如果接收方没有拉低SDA(保持高电平),则是一个非应答(NACK) 信号,表示“接收失败”或“请停止发送”。
4. 数据帧 (Data Frames)
  • 在地址得到应答后,就开始传输数据字节。
  • 每个数据字节(8位)后同样跟一个应答位。
5. 停止条件 (Stop Condition)
  • 主设备在SCL为高电平期间,将SDA从低电平拉高
  • 这个独特的上升沿信号告诉所有设备:“本次通信结束,总线空闲了”。

图示帮助理解一次完整的“写”操作:
主设备想向地址为0x3C的OLED屏幕发送数据 0xAB

时间线 ------------------------------------------------------------------>
SDA:   起始条件  0  1  1  1  1  0  0  (0)  ACK   1  0  1  0  1  0  1  1  (0) ACK   停止条件
        |      A6 A5 A4 A3 A2 A1 A0 R/W  |      D7 D6 D5 D4 D3 D2 D1 D0   |
SCL:    ___     _   _   _   _   _   _   _   ___    _   _   _   _   _   _   _   ___   ___
        | |     | | | | | | | | | | | | | | |     | | | | | | | | | | | | | | |     | |
        起始     地址 (0x3C << 1 + 0)     应答       数据 (0xAB)           应答       停止

5.3 如何连接多个从设备?

I2C在连接多个设备上具有天然优势。

  • 所有从设备的SDASCL引脚分别并联到一起。
  • 主设备通过发送不同的地址来选择要通信的从设备。
  • 因为地址冲突问题,需要注意每个I2C设备的地址是否唯一。很多设备可以通过改变硬件引脚电平来修改地址。

5.4 I2C的优点和缺点

优点 缺点
引脚极其节省:只需要两根线,理论上可以连接127个(7位地址)设备。 速度较慢:标准模式100kbps,快速模式400kbps,高速模式3.4Mbps。普遍慢于SPI。
支持多主多从(虽然不常见)。 半双工:同一时间只能在一个方向上传输数据(读或写)。
有硬件应答机制(ACK),增加了通信可靠性。 协议更复杂:软件实现相对繁琐。
通信距离通常比SPI稍长。 上拉电阻:总线需要外部上拉电阻,阻值需要根据速度和总线电容计算。
地址冲突:不同设备的默认地址可能相同,需要留意。

6. I2C vs SPI: 核心区别总结

特性 SPI I2C
引脚数量 4根线 (3+CS/设备) 2根线
寻址方式 硬件片选 (CS) 软件地址
通信方式 全双工 (同时收发) 半双工 (分时收发)
速度 (通常50Mbps+) (通常400kbps)
协议复杂度 简单 ( essentially just shifting bits) 复杂 (起始、地址、应答、停止)
可靠性 无硬件应答 有硬件应答 (ACK)

7. 与你的OLED屏幕的联系

很多OLED屏幕(包括基于SSD1306/SSD1309的)都同时支持SPI和I2C两种模式。屏幕模块上通常有电阻焊盘,通过焊接不同的电阻来选择通信模式。

  • I2C模式下的OLED连接

    • ESP32 <–> OLED
    • SDA (GPIO 21) <–> SDA
    • SCL (GPIO 22) <–> SCL
    • VCC <–> VCC
    • GND <–> GND
      (注意:在I2C模式下,OLED的CS、DC引脚可能需要进行特定处理,如CS接高电平,DC引脚可能不再需要)
  • 在代码中,使用U8g2库的I2C构造函数初始化即可,库会自动处理所有底层的I2C协议细节,包括发送地址、数据、检查应答等。

    #include <U8g2lib.h>
    #include <Wire.h> // I2C库
    
    // 使用I2C的构造函数
    U8G2_SSD1309_128X64_NONAME0_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
    // U8X8_PIN_NONE 表示复位引脚未连接,或者使用硬件复位
    
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐