使用I2C通信简易控制OLED屏幕

I²C(Inter-Integrated Circuit)通信协议简介

I²C(Inter-Integrated Circuit,简称IIC)是一种 串行通信协议,用于在短距离内连接低速设备,如传感器、EEPROM、显示屏(如OLED)、ADC/DAC、RTC等。它由 飞利浦(现NXP) 在1982年开发,具有占用引脚少、支持多个设备、硬件开销低等优点,在嵌入式系统中应用广泛。


1. I²C 的特点

  • 主从结构:支持 一个或多个主机(Master) 控制多个从机(Slave)。
  • 双线通信:使用两条信号线:
    • SCL(Serial Clock,串行时钟线):由主设备提供时钟信号。
    • SDA(Serial Data,串行数据线):用于主从设备之间的数据传输(双向)。
  • 地址传输:每个从设备都有唯一的 7位或10位地址,主设备通过地址选择要通信的从设备。
  • 支持多个设备:在同一条总线上,可以连接多个主机和多个从机。
  • 半双工通信:数据传输为单向进行,每次只能有一个设备在发送数据。
  • 支持不同速率
    • 标准模式(Standard Mode):最大传输速率 100kbps
    • 快速模式(Fast Mode):最大传输速率 400kbps
    • 高速模式(High-speed Mode, HSM):最大传输速率 3.4Mbps
    • 超高速模式(Ultra Fast Mode, UFm):最大传输速率 5Mbps

2. I²C 总线的工作机制

2.1 I²C 设备连接

I²C 设备通过 SCL 和 SDA 连接到总线,所有设备共享这两条总线,由 主机 负责发送 时钟信号,并向从机发起通信请求。


2.2 I²C 数据传输格式

I²C 采用 主设备(Master) 发送 起始信号(Start Condition) 来通知从设备准备通信,然后通过 SDA 发送 从设备地址,如果有匹配的从机,它会发送应答信号(ACK)。数据传输完成后,主机发送 停止信号(Stop Condition) 结束通信。

I²C 传输步骤

  1. 起始条件(START)
    • SDA 从高变低,SCL 维持高电平,表示开始通信。
  1. 发送从机地址(7位或10位)+ 读/写位(1位)
    • 主机发送 从机地址,并设置最后 1 位(R/W):
      • 0:写(主机向从机发送数据)
      • 1:读(主机从从机接收数据)
  2. 从机应答(ACK)
    • 如果地址匹配,从机会 拉低 SDA 发送 ACK 响应。
    • 若没有匹配,从机保持 SDA 高电平(NACK)。
  1. 数据传输
    • 发送或接收 8 位数据,每发送 1 字节,从机需要发送 ACK
  2. 停止条件(STOP)
    • SDA 从低变高,SCL 维持高电平,表示数据传输完成。

2.3 I²C 数据帧

一个完整的 I²C 通信帧格式如下:

   START   |  7-bit 地址  | R/W | ACK |  数据字节  | ACK | ... | STOP
  ---------|-------------|-----|-----|-----------|-----|-----|------
           |  从机地址    | 0/1 |  0  |  数据字节  |  0  |     |     

3. I²C 读写操作示例

3.1 通过 CubeMX 配置 I²C

  • 设置 I2C1
    • SCL 口:PB8
    • SDA 口:PB9
    • 模式:主机模式(Master Mode)
    • 时钟速度:400 kHz(快速模式 Fast Mode)

3.2 配置 PC13 作为 LED 控制引脚

  • 模式:推挽输出(Output Push-Pull)
  • 初始状态高电平(LED1 熄灭)

3.3 配置 PB1 作为外部中断

  • 引脚:PB1
  • 模式:外部中断(EXTI)
  • 触发方式:下降沿触发(Falling Edge)

3.4 启用 EXTI1 中断

  • 中断控制器(NVIC)中启用 EXTI1
  • 默认优先级

3.5 生成代码

  • 生成代码后,开始编写应用逻辑。

3.6 在 EXTI1 的中断回调函数中切换 OLED 状态

目标:在中断触发时,通过 I²C 发送数据来切换 OLED 状态。

简要阅读SSD1306的数据手册,同时观察SSD1306的背面I2C地址指示,我们得知了OLED的I2C地址为0x78,以及点亮测试的基本流程,这样我们就能写控制驱动了。

uint8_t oled_on_cmd[]={0x00,0x8d,0x14,0xaf,0xa5};// {命令流,使能电荷泵,使能电荷泵,打开屏幕,屏幕全亮}
uint8_t oled_off_cmd[] = {0x00, 0xAE};  // 关闭显示
uint8_t DataRcvd;// 设置缓冲区存取读到的数据
uint8_t oled_state = 0; // 0: 关闭, 1: 打开

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_1)  // 确保是 B1 按键的中断
    {
        oled_state = !oled_state;  // 切换 OLED 状态
        
        if (oled_state)
        {
            //uint8_t oled_on_cmd[] = {0x00, 0xAF};  // 0xAF = 打开 OLED 显示
            HAL_I2C_Master_Transmit(&hi2c1, OLED_I2C_ADDR, oled_on_cmd, sizeof(oled_on_cmd), HAL_MAX_DELAY);
        }
        else
        {
            uint8_t oled_off_cmd[] = {0x00, 0xAE};  // 0xAE = 关闭 OLED 显示
            HAL_I2C_Master_Transmit(&hi2c1, OLED_I2C_ADDR, oled_off_cmd, sizeof(oled_off_cmd), HAL_MAX_DELAY);
        }
    }
}

3.7 在主循环中轮询 OLED 状态,并控制 LED

目标:持续读取 OLED 的状态,并根据 OLED 是否点亮来控制 LED 开关。

while (1)
  {
    /* USER CODE END WHILE */
		HAL_I2C_Master_Receive(&hi2c1,OLED_I2C_ADDR,&DataRcvd,1,HAL_MAX_DELAY);// 轮询读取oled的返回值,判断屏幕状况
		if ((DataRcvd & (1 << 6)) == 0) 
		{  // 检查第6位
        HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);  // 点亮LED
    } 
		else 
		{
        HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET); // 熄灭LED
    }
		HAL_Delay(100);// 每0.1秒检查一下LED的情况
}

3.8 实验现象


4. I²C 与 SPI 的对比

特性I²CSPI
线数2 条(SCL、SDA)4 条(SCK、MISO、MOSI、CS)
速度最高 3.4 Mbps最高几十 Mbps
设备数量可连接多个设备需要独立 CS 选择设备
硬件开销
通信模式半双工全双工

5. I²C 在 STM32 开发中的使用

STM32 通过 I2C 外设 控制从设备,使用 HAL 库进行配置:

  1. 配置 I2C 引脚(如 SCL: PB6, SDA: PB7)
  2. 初始化 I2C
  3. 使用 HAL_I2C_Master_Transmit()HAL_I2C_Master_Receive() 进行数据传输

6. 结论

  • I²C 是一种常用的低速串行总线,适用于短距离、多设备通信。
  • 只需 2 根线即可连接多个设备,占用引脚少,硬件开销低。
  • 支持多种传输速率(100kbps、400kbps、3.4Mbps等)。
  • 适用于 OLED 屏幕、EEPROM、RTC、传感器等外设的通信。
上一篇
下一篇