K230基础-I2C协议介绍及使用
·
第九章 I2C协议-K230多设备互联的简洁总线
🎯 本章目标:
深入理解 I2C(Inter-Integrated Circuit)通信协议原理,掌握 K230 MicroPython 中 I2C 模块的配置与使用方法,学会驱动 OLED 屏幕、AHT20 温湿度传感器、EEPROM 存储器 等常见外设,构建具备人机交互与数据存储能力的完整嵌入式系统。
1. I2C 协议基础概念
1.1 什么是 I2C?
I2C(Inter-Integrated Circuit) 是由 Philips(现 NXP)开发的一种两线式串行总线,用于连接低速外围设备。
- 仅需两根线:
SDA:数据线(Serial Data)SCL:时钟线(Serial Clock)
- 支持多主多从架构
- 地址寻址:每个从设备有唯一 7 位或 10 位地址
- 典型速率:100kHz(标准)、400kHz(快速)、1MHz(高速)
✅ 优点:
- 接线简单,节省引脚
- 支持总线扩展(挂载多个设备)
- 广泛用于传感器、存储器、显示屏
⚠️ 缺点:
- 速率较低
- 需要上拉电阻(通常 4.7kΩ)
- 总线长度受限(建议 < 1m)
2. I2C 通信机制详解
2.1 信号线电气特性
- 开漏输出:SDA 和 SCL 均为开漏结构
- 必须外接上拉电阻到 VCC(3.3V)
- 典型上拉电阻值:4.7kΩ
📌 开发板说明:
多数开发板已在 I2C 引脚内置上拉电阻,无需外接。
2.2 数据帧格式
I2C 通信由以下部分组成:
[起始] [从机地址+R/W] [ACK] [数据字节...] [ACK] ... [停止]
- 起始条件(START):SCL 高电平时,SDA 从高→低
- 停止条件(STOP):SCL 高电平时,SDA 从低→高
- ACK:每传输一个字节后,接收方拉低 SDA 表示应答
2.3 7 位地址与读写位
- 7 位地址 + 1 位读写控制 → 8 位字节
- 读操作:地址 << 1 | 1
- 写操作:地址 << 1 | 0
📊 常见设备地址(7 位):
- OLED(SSD1306):
0x3C- AHT20:
0x38- AT24C02(EEPROM):
0x50- BMP280:
0x76
3. K230 I2C 系统架构
3.1 硬件资源
K230 提供多个 I2C 控制器(如 I2C0, I2C1),每个:
- 支持主/从模式(MicroPython 通常只用主模式)
- 支持标准/快速模式(100/400kHz)
- 需通过 FPIOA 映射到物理引脚
3.2 FPIOA 映射
| 功能名 | FPIOA 编号 | 说明 |
|---|---|---|
I2C0_SDA |
32 | I2C0 数据线 |
I2C0_SCL |
33 | I2C0 时钟线 |
I2C1_SDA |
34 | I2C1 数据线 |
I2C1_SCL |
35 | I2C1 时钟线 |
📌 建议:使用 I2C1,避免与调试接口冲突
4. MicroPython I2C API 详解
4.1 导入模块
from machine import I2C, Pin, fpioa
或使用 MaixPy 风格:
from fpioa_manager import fm from machine import I2C
4.2 初始化流程
4.2.1 步骤1:FPIOA 映射
fm.register(sda_pin, fm.fpioa.I2C1_SDA)
fm.register(scl_pin, fm.fpioa.I2C1_SCL)
4.2.2 步骤2:创建 I2C 对象
i2c = I2C(I2C.I2C1, freq=400_000, sda=Pin(sda_pin), scl=Pin(scl_pin))
参数说明:
freq:通信频率,通常100000或400000sda,scl:指定引脚对象
4.3 常用方法
| 方法 | 说明 |
|---|---|
i2c.scan() |
扫描总线上所有从设备,返回地址列表 |
i2c.readfrom(addr, nbytes) |
从指定地址读取 nbytes 字节 |
i2c.writeto(addr, buffer) |
向指定地址写入数据 |
i2c.readfrom_mem(addr, memaddr, nbytes) |
从设备的内存地址读取 |
i2c.writeto_mem(addr, memaddr, buffer) |
向设备的内存地址写入 |
5. 实战项目一:I2C 设备扫描
from fpioa_manager import fm
from machine import I2C, Pin
# === 1. FPIOA 映射 ===
sda_pin = 2 # 示例引脚
scl_pin = 3
fm.register(sda_pin, fm.fpioa.I2C1_SDA)
fm.register(scl_pin, fm.fpioa.I2C1_SCL)
# === 2. 初始化 I2C ===
i2c = I2C(I2C.I2C1, freq=400_000,
sda=Pin(sda_pin),
scl=Pin(scl_pin))
# === 3. 扫描设备 ===
devices = i2c.scan()
if devices:
print(f"发现 {len(devices)} 个 I2C 设备:")
for addr in devices:
print(f" 地址: 0x{addr:02X}")
else:
print("❌ 未发现 I2C 设备,请检查接线")
✅ 用途:快速确认设备是否连接成功。
6. 实战项目二:驱动 AHT20 温湿度传感器
6.1 AHT20 通信流程
- 发送初始化命令
0xBE, 0x08, 0x00 - 发送触发测量命令
0xAC, 0x33, 0x00 - 等待 80ms
- 读取 6 字节数据
- 解析温湿度
6.2 完整代码
from fpioa_manager import fm
from machine import I2C, Pin
import utime
# === 1. FPIOA 映射 ===
fm.register(2, fm.fpioa.I2C1_SDA)
fm.register(3, fm.fpioa.I2C1_SCL)
i2c = I2C(I2C.I2C1, freq=400_000,
sda=Pin(2),
scl=Pin(3))
AHT20_ADDR = 0x38
def aht20_init():
"""初始化 AHT20"""
i2c.writeto(AHT20_ADDR, b'\xBE\x08\x00')
utime.sleep_ms(10)
def aht20_trigger():
"""触发一次测量"""
i2c.writeto(AHT20_ADDR, b'\xAC\x33\x00')
utime.sleep_ms(80) # 等待转换完成
def aht20_read():
"""读取数据并解析"""
data = i2c.readfrom(AHT20_ADDR, 6)
if len(data) != 6:
return None, None
# 解析
humidity = ((data[1] << 12) | (data[2] << 4) | (data[3] >> 4)) * 100 / 2**20
temperature = (((data[3] & 0x0F) << 16) | (data[4] << 8) | data[5]) * 200 / 2**20 - 50
return humidity, temperature
# === 主循环 ===
aht20_init()
print("AHT20 温湿度读取")
try:
while True:
aht20_trigger()
h, t = aht20_read()
if h is not None and t is not None:
print(f"湿度: {h:.1f}% 温度: {t:.1f}°C")
else:
print("读取失败")
utime.sleep(2)
except KeyboardInterrupt:
pass
7. 实战项目三:驱动 SSD1306 OLED 屏幕
7.1 使用 ssd1306 官方库
# 通过 rshell 上传 ssd1306.py
rshell -p /dev/ttyUSB0
cp ssd1306.py /pyboard/
ssd1306.py可从 MicroPython 官方仓库获取:
https://github.com/micropython/micropython/blob/master/drivers/display/ssd1306.py
7.2 完整代码
from fpioa_manager import fm
from machine import I2C, Pin
import ssd1306
import utime
# === 1. I2C 配置 ===
fm.register(2, fm.fpioa.I2C1_SDA)
fm.register(3, fm.fpioa.I2C1_SCL)
i2c = I2C(I2C.I2C1, freq=400_000, sda=Pin(2), scl=Pin(3))
oled = ssd1306.SSD1306_I2C(128, 64, i2c, addr=0x3C)
# === 2. 清屏 ===
oled.fill(0)
# === 3. 显示文本 ===
oled.text("Hello K230", 0, 0)
oled.text("I2C OLED", 0, 10)
oled.show()
# === 4. 动态显示时间 ===
counter = 0
while True:
oled.fill(0)
oled.text("Counter:", 0, 20)
oled.text(str(counter), 70, 20)
oled.text("Time:", 0, 40)
oled.text(utime.localtime(), 40, 40)
oled.show()
counter += 1
utime.sleep(1)
8. 实战项目四:AT24C02 EEPROM 数据存储
8.1 AT24C02 特性
- I2C 接口,地址
0x50 - 容量 256 字节
- 支持
writeto_mem/readfrom_mem
8.2 完整代码
from fpioa_manager import fm
from machine import I2C, Pin
fm.register(2, fm.fpioa.I2C1_SDA)
fm.register(3, fm.fpioa.I2C1_SCL)
i2c = I2C(I2C.I2C1, freq=100_000, sda=Pin(2), scl=Pin(3))
EEPROM_ADDR = 0x50
def eeprom_write_byte(addr, data):
i2c.writeto_mem(EEPROM_ADDR, addr, bytes([data]))
def eeprom_read_byte(addr):
return i2c.readfrom_mem(EEPROM_ADDR, addr, 1)[0]
# === 测试读写 ===
test_addr = 0x00
eeprom_write_byte(test_addr, 0x55)
utime.sleep_ms(10) # 写入需要时间
value = eeprom_read_byte(test_addr)
print(f"EEPROM 地址 0x{test_addr:02X} 读回: 0x{value:02X}")
9. 高级技巧与优化
9.1 多设备共用总线
- 多个设备共享 SDA/SCL
- 通过地址区分
- 注意地址冲突(如多个 OLED)
9.2 软件模拟 I2C(bit-banging)
当硬件 I2C 不可用时:
from machine import Pin
import utime
def i2c_write_bit(scl, sda, bit):
scl.value(0)
sda.value(bit)
utime.sleep_us(5)
scl.value(1)
utime.sleep_us(5)
scl.value(0)
# 适用于调试、引脚受限场景
10. 常见问题与调试
❌ 问题1:scan() 无设备
排查:
- 接线是否正确(SDA/SCL 是否交叉)
- 上拉电阻是否缺失
- 设备地址是否正确
- 供电是否正常(3.3V)
❌ 问题2:读写超时或异常
解决:
- 降低
freq到 100kHz- 检查设备是否需要初始化
- 增加
sleep_ms等待转换完成
❌ 问题3:OLED 无显示
检查:
- 地址是
0x3C还是0x3D?- 是否调用
oled.show()?- 是否
fill(0)清屏?
11. 性能与限制
| 参数 | K230 MicroPython 限制 |
|---|---|
| 最高速率 | 400kHz(快速模式) |
| 最大设备数 | 10+(地址不冲突) |
| 总线电容 | 建议 < 400pF |
| 支持模式 | 主模式(Master) |
💡 建议:
- 总线设备多时,使用 I2C 集线器(TCA9548A)
- 关键操作加
try-except防止程序卡死
✅ 本章你已掌握:
- I2C 协议原理与帧结构
- K230 I2C + FPIOA 配置
- 设备扫描与地址识别
- 驱动 AHT20、OLED、EEPROM
- 常见问题排查
openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。
更多推荐


所有评论(0)