
I2C(Inter-Integrated Circuit)是一种常用的串行通信协议,适用于短距离设备间的低速通信。广泛应用于各种单片机与传感器、EEPROM、LCD 模块等外围器件的短距离数据传输。其核心特点是仅需两根信号线即可实现双向通信,硬件成本低、布线简单,是单片机系统中最常用的通信接口之一。
I2C 通信仅依赖两根信号线,且需配合上拉电阻实现电平稳定,具体如下:
| 信号名称 | 英文全称 | 核心功能 | 关键特性 |
| SDA | Serial Data | 串行数据 | 双向传输,用于发送 / 接收数据字节(8 位) |
| SCL | Serial Clock | 串行时钟 | 单向传输(由主设备生成),用于同步数据传输节奏 |
关键硬件细节:上拉电阻
SDA 和 SCL 均为开漏输出(Open-Drain) 结构,自身无法输出高电平,需通过外接上拉电阻(通常为 4.7kΩ~10kΩ,接 VCC)将电平拉至高电平。
当器件输出 “0” 时:引脚拉低,总线电平为低;
当器件输出 “1” 时:引脚高阻,总线电平由上拉电阻拉为高。
这种结构保证了多设备挂载时不会出现 “总线竞争”(即多个设备同时输出高低电平导致短路)。
I2C 采用 “主从架构”,通信由主设备(如单片机) 发起和控制,从设备(如传感器) 仅被动响应,具体分工如下:
| 主从角色模式 | 核心职责 | |||||
| 主设备(Master) | 1.生成 SCL 时钟信号 | 2.发起 “起始信号” 和 “停止信号" | 3.发送从设备地址(选择通信对象) | 4.控制数据传输方向(读 / 写) | 5.生成 “应答信号(ACK)” 或 “非应答信号(NACK) | |
| 从设备(Slave) | 1. 拥有唯一的 7 位或 10 位地址 | 2. 检测总线地址是否与自身匹配 | 3. 按主设备指令发送 / 接收数据 | 4. 向主设备返回 ACK/NACK |
注:I2C 总线支持多主设备(需避免冲突)和多从设备(最多 128 个 7 位地址从设备),但单片机系统中 99% 以上为 “单主多从” 场景。
I2C 通信的完整过程由 “起始→地址→数据→应答→停止”5 个时序阶段组成,每个阶段的 SDA 和 SCL 电平变化严格定义,是协议正确性的核心。
1. 起始信号(Start Condition,S):通信开始的标志
时序定义:在 SCL 保持高电平期间,SDA 由高电平跳转为低电平(“高→低” 跳变)。
作用:告知总线上所有从设备 “通信即将开始”,从设备需准备接收后续地址信号。
波形示意图:
2. 从设备地址与读写控制:选择通信对象和方向
起始信号后,主设备会连续发送8 位数据,其中前 7 位为 “从设备地址”,第 8 位为 “读写控制位(R/W#)”:
第 8 位 = 0:表示主设备向从设备写数据(Write);
第 8 位 = 1:表示主设备从从设备读数据(Read)。
时序要求:
SCL 为高电平时,SDA 电平必须稳定(数据有效);
SCL 为低电平时,SDA 可跳变(准备下一位数据)。
示例:若从设备地址为 0x48(二进制1001000),主设备要向其写数据,则发送的 8 位为10010000(0x48 + 0);若要读数据,则发送10010001(0x48 + 1)。
3. 应答信号(ACK/NACK):数据接收确认
每传输 8 位数据(地址或数据字节)后,接收方需向发送方返回 1 位 “应答信号”,确认数据已接收:
ACK(应答):接收方在第 9 个 SCL 高电平期间,将 SDA 拉为低电平(表示 “已接收,可继续传输”);
NACK(非应答):接收方在第 9 个 SCL 高电平期间,将 SDA 保持高电平(表示 “未接收 / 接收完成”,主设备通常会终止通信)。
关键规则:
地址字节的应答方:从设备(确认地址匹配);
数据字节的应答方:
写操作时:从设备(确认数据接收);
读操作时:主设备(确认数据接收,若主设备无需更多数据,会返回 NACK)。
波形示意图(ACK):
4. 数据传输:8 位为单位的双向传输
地址和 ACK 确认后,进入数据传输阶段,每个数据单元为8 位(1 字节),传输方向由 “读写控制位” 决定:
写操作(主→从):主设备连续发送数据字节,每字节后等待从设备的 ACK;
读操作(从→主):从设备连续发送数据字节,每字节后等待主设备的 ACK/NACK(主设备要终止时发 NACK)。
时序要求:与地址传输一致 ——SCL 高电平时 SDA 稳定(数据有效),SCL 低电平时 SDA 跳变。
5. 停止信号(Stop Condition,P):通信结束的标志
时序定义:在 SCL 保持高电平期间,SDA 由低电平跳转为高电平(“低→高” 跳变)。
作用:告知总线上所有从设备 “本次通信结束”,从设备可进入空闲状态。
波形示意图:
I2C 支持不同的传输速率,以适配不同的应用场景(速率越高,对布线和器件的要求越严格):
| 模式名称 | 最大传输速率 | 适用场景 |
| 标准模式(Standard-mode) | 100 kbps | 低速、长距离(如 1m 以上)、对稳定性要求高的场景 |
| 快速模式(Fast-mode) | 400 kbps | 中速、短距离(如 0.5m 内)温湿度传感器(SHT30)、OLED |
| 高速模式(Fast-mode Plus) | 1 Mbps | 高速、短距离(如 0.3m 以内)场景 |
注:部分高端器件支持 10Mbps 的 “超高速模式(High-speed mode)”,但单片机系统中极少使用。
在树莓派Pico开发板的引脚上有两个 I2C 控制器分别为(I2C0 和 I2C1)
其中代表I2C0的引脚如下:
SDA (数据): GPIO0 (默认) 或 GPIO4、GPIO8、GPIO12、GPIO16、GPIO20
SCL (时钟): GPIO1 (默认) 或 GPIO5、GPIO9、GPIO13、GPIO17、GPIO21
其中代表I2C1的引脚如下:
SDA (数据): GPIO2 (默认) 或 GPIO6、GPIO10、GPIO14、GPIO18、GPIO26
SCL (时钟): GPIO3 (默认) 或 GPIO7、GPIO11、GPIO15、GPIO19、GPIO27
使用 MicroPython 初始化 I2C 控制器:
from machine import Pin, I2C
import time
# 初始化I2C0,使用默认引脚
i2c0 = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000)
# 初始化I2C1,使用默认引脚
i2c1 = I2C(1, scl=Pin(3), sda=Pin(2), freq=400000)
print("I2C初始化完成")
连接好 I2C的设备后,可以扫描总线上的设备地址:
from machine import Pin, I2C
# 初始化I2C
i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000)
# 扫描I2C设备
devices = i2c.scan()
if devices:
print("找到I2C设备:")
for dev in devices:
print(f"设备地址: 0x{dev:02x}")
else:
print("未找到I2C设备")
以下是 I2C 主机发送数据到从设备和从从设备接收数据的示例:
from machine import Pin, I2C
import time
# 初始化I2C
i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000)
# 假设我们有一个地址为0x48的I2C设备
DEVICE_ADDR = 0x48
def send_data(register, data):
"""向指定寄存器发送数据"""
try:
# 格式: i2c.writeto_mem(设备地址, 寄存器, 数据, 数据格式)
i2c.writeto_mem(DEVICE_ADDR, register, bytes([data]), addrsize=8)
print(f"已发送数据 0x{data:02x} 到寄存器 0x{register:02x}")
return True
except OSError as e:
print(f"发送失败: {e}")
return False
def receive_data(register, length):
"""从指定寄存器接收指定长度的数据"""
try:
# 读取数据
data = i2c.readfrom_mem(DEVICE_ADDR, register, length, addrsize=8)
print(f"从寄存器 0x{register:02x} 接收数据: {[hex(b) for b in data]}")
return data
except OSError as e:
print(f"接收失败: {e}")
return None
# 示例用法
if __name__ == "__main__":
# 向寄存器0x00发送数据0xAA
send_data(0x00, 0xAA)
time.sleep(0.1)
# 从寄存器0x01读取2字节数据
receive_data(0x01, 2)SHT30是一款完全校准的线性化的温湿度数字传感器,增强了数字信号。采用I2C通讯,频率达1MHz。具有高可靠性及高稳定性,我们常见的SHT系列有三种型号:SHT30、SHT31、SHT35,其中比较便宜性价比较高的是 SHT30。在使用过程中需要用到 I2C 来通信。如果你没作更改过传感器,传感器的默认的从机地址是 0x44。它的供电是宽电压可输入2.15V-5.5V,可单次读取或周期性读取温度和湿度传感器数值,需要通过公式转换为摄氏度和相对湿度值。

| Pico开发板 | SHT传感器 |
| 3.3v | VCC |
| GND | GND |
| GP0 | SDA |
| GP1 | SCL |

1.下载源代码后,上传至树莓派Pico内,直接运行代码查看结果

线性化的温湿度传感器测量到的环境温湿度数据是非常精准的!
| 传感器详细参数 | 产品手册 | CAD模型 |
关于更多SHT传感器详细参数可查看以下资料
https://sensirion.com/cn/products/catalog/SHT30-DIS-B
https://blog.csdn.net/weixin_44350337/article/details/141168150