基于 RT-Thread 的软 I2C:比你想象的更简单

2026-05-20 274561阅读

一、前言

先楫 MCU 提供了多达 8 路硬件 I2C 接口,功能非常完善。但在实际项目中,由于引脚资源紧张引脚复用冲突,硬件 I2C 并不总是一个最优选择。

另一方面,I2C 在很多场景下仅用于初始化配置低频读写,对性能和带宽的要求并不高。

在这种情况下,使用 GPIO 模拟 I2C(即软 I2C)就显得非常有价值:

既能节省宝贵的硬件资源,又能满足功能需求,还能提升系统的灵活性。

本文将基RT-Thread框架,结合hpmicro BSP,以HPM6750EVK2开发板为例,介绍如何为先楫 MCU 实现一个灵活、可扩展、易于使用的软 I2C 驱动,并以AT24C02 EEPROM为实例展示其应用方式。

以往的先楫RT-Thread文章可以参考这个文章系列

《先楫RT-Thread开发系列文章》

二、从驱动层看实现细节

(一)板级定义模拟I2C的IO引脚

先楫的 RT-Thread BSP 已经完成了PIN 设备驱动的对接,这为软 I2C 的实现提供了良好的基础。

为了提升配置的可读性和可维护性,在板级配置(如 Kconfig)中,推荐使用字符串形式的引脚名来定义 SDA 和 SCL,例如:

SDA:PZ11SCL:PZ10

在驱动内部,可以通过rt_pin_get()接口,将字符串形式的引脚名转换为 RT-Thread 使用的实际 IO 索引(即先楫 MCU 的 IO 编号),后续所有 GPIO 操作都基于该索引完成。

这种方式相比直接使用数字引脚编号,有明显优势:

1、可读性更强例如PD21能直观反映出这是 D 组的第 21 个引脚。

2、可移植性更好不同平台的引脚编号规则不同,字符串形式可以屏蔽底层差异。

3、更不容易出错避免手工填写数字编号时常见的 off-by-one 错误。

基于 RT-Thread 的软 I2C:比你想象的更简单

在驱动中,无论是设置 SDA 电平,还是读取 SCL 状态,最终都会通过rt_pin_get()获取 IO 索引,再调用 RT-Thread 的 PIN 接口完成操作。

基于 RT-Thread 的软 I2C:比你想象的更简单

(二)I2C 的位级操作

I2C 是一种典型的串行通信协议,通过SCL(时钟线)SDA(数据线)两根信号线完成通信。

软 I2C 的本质,就是用 GPIO 的高低电平变化来模拟这两根信号线的时序。

从驱动角度来看,只需要实现以下四个最基础的位级操作

1、设置 SCL 为高 / 低电平

2、设置 SDA 为高 / 低电平

3、读取 SCL 电平

4、读取 SDA 电平

这四个操作是软 I2C 的最底层能力,所有更复杂的行为——如起始信号、停止信号、位传输、字节收发、ACK/NACK 判断——都可以在此基础上构建。

RT-Thread 已经提供了成熟的I2C 位操作框架(i2c_bit_ops)

驱动只需实现上述四个接口,并将其注册到 RT-Thread 的 I2C 框架中,协议层细节将完全由 RT-Thread 负责处理,极大地降低了驱动开发难度。

(三)驱动初始化的流程

驱动初始化函数会遍历所有配置的 I2C 设备,对每一个设备做以下工作:

1、根据配置结构体创建驱动对象

2、设置驱动对象的操作函数指针(指向上面提到的四个基本操作)

3、将驱动对象注册到 RT-Thread I2C 框架,这样应用层就可以通过 rt_device_find() 找到它

4、进行总线恢复(防止 I2C 总线被卡住)

5、输出初始化日志供调试

初始化完成后,应用层就可以把软 I2C 当作一个普通的 RT-Thread I2C 设备来使用了

基于 RT-Thread 的软 I2C:比你想象的更简单

三、另一种实现方式说明

如果系统已经启用了 RT-Thread 的 PIN 设备框架,也可以直接使能 RT-Thread 自带的RT_USING_SOFT_I2C组件。

这种方式下,软 I2C 的核心逻辑由 RT-Thread 提供,开发者只需要在配置中填写 SDA 和 SCL 对应的引脚编号

需要注意的是,这里的引脚编号需要根据先楫 MCU 的 IO 索引规则手动填写,相比字符串方式在可读性上略逊一筹。

基于 RT-Thread 的软 I2C:比你想象的更简单

四、应用层开发——以 AT24C02 为例

HPM6750EVK2 开发板上自带了一颗AT24C02 EEPROM,非常适合作为软 I2C 的验证对象。

在驱动加载完成后,可以通过 msh 查看系统设备列表,确认对应的软 I2C 总线(如 soft_i2c0)已经成功注册。

基于 RT-Thread 的软 I2C:比你想象的更简单

在应用层中,只需通过rt_device_find()获取该 I2C 设备句柄,后续的 EEPROM 读写操作即可完全复用 RT-Thread 提供的标准 I2C 接口。

基于 RT-Thread 的软 I2C:比你想象的更简单

例如,在写入 EEPROM 时,直接使用 I2C 发送接口即可;

随后再读取相同地址的数据,验证写入内容是否一致。

基于 RT-Thread 的软 I2C:比你想象的更简单

从实际测试结果来看,软 I2C 在约 300 kHz 的通信速率下工作稳定,逻辑分析仪抓取的波形也符合 I2C 时序要求,完全满足 AT24C02 这类低速外设的应用需求。

基于 RT-Thread 的软 I2C:比你想象的更简单基于 RT-Thread 的软 I2C:比你想象的更简单基于 RT-Thread 的软 I2C:比你想象的更简单

五、总结

嵌入式系统中,引脚资源紧张与外设需求多样化几乎是常态。

即便 MCU 提供了丰富的硬件外设,合理引入软实现方案,依然是提升系统灵活性的重要手段。

本文结合先楫 MCU 与 RT-Thread 框架,完整展示了一种工程化的软 I2C 实现思路。

通过配置驱动、分层设计以及对 RT-Thread 现有能力的充分利用,使软 I2C 在系统中具备了与硬件 I2C 一致的使用体验。

实践表明,只要设计得当,软 I2C 在稳定性和时序精度上完全可以满足常见外设的需求。

在硬件资源受限、I2C 使用频率不高或对引脚分配要求较高的场景下,软 I2C 是一种值得优先考虑的解决方案。

希望本文的实现思路和工程经验,能为你在后续项目中设计外设驱动、优化资源分配提供有价值的参考。

文章版权声明:除非注明,否则均为天创资讯网原创文章,转载或复制请以超链接形式并注明出处。