提到嵌入式开发中最常用的通信协议,除了串口(UART)和 SPI,毫无疑问就是 I2C (Inter-Integrated Circuit)了。1982年,飞利浦(现在的 NXP)发明了这套两线制(SCL 和 SDA)通信协议,它的初衷非常简单:为了解决电视机里面芯片之间互相通信时,连线太多的问题。你没看错, 这套协议诞生至今已经超过40年,快50岁了! 在过去的几十年里,I2C 几乎统治了整个低速外设市场:传感器、EEPROM、RTC 芯片、OLED 屏幕……哪里都有它的身影。它最牛的地方在于: 只需要两根线,就能挂载几十个设备,极大地节省了 MCU 的引脚。 然而,随着物联网(IoT)、可穿戴设备和智能手机里塞入的传感器越来越多,这位“50岁的老将”渐渐有些力不从心了:
- 速度太慢: 标准模式 100kHz,快速模式 400kHz,即便是高速模式(High-Speed)也勉强到 3.4MHz。在读取高清摄像头数据或大量陀螺仪数据时,根本不够用。
- 功耗太高: I2C 采用的是开漏输出(Open-Drain)结构。当总线要拉低(输出 0)时,外部的上拉电阻会产生持续的电流消耗。对于靠纽扣电池续航的智能手表来说,这简直是噩梦。
- 中断线灾难: I2C 本身不支持中断。如果一个传感器(比如计步器)检测到了步数变化,它没法主动通过 I2C 告诉主机。解决办法是:额外拉一根中断线(INT)连到 MCU 上。如果板子上有 10 个传感器,就需要额外 10 根中断线,引脚又不够用了!
- 地址冲突: I2C 的地址只有 7 位(少数 10 位),这意味着最多只能挂载 100 多个设备。更要命的是,很多芯片出厂时地址就写死了,如果你想在同一个总线上挂两个同型号的传感器,就会发生地址冲突。
就在这时候, I3C(Improved Inter Integrated Circuit) 闪亮登场!MIPI 联盟(制定手机摄像头 CSI 和屏幕 DSI 接口的那个组织)实在看不下去了,联合了各大芯片巨头,推出了这套 向后兼容 I2C,但性能全面吊打 I2C 的新一代总线标准。
![]()
图:I2C 的瓶颈先暴露在速率、功耗和中断上,I3C 再逐项补上动态地址、带内中断和兼容落地能力。
I3C 的杀手级特性:到底牛在哪里?
既然叫 I3C,那它到底比 I2C 多了些什么“黑科技”?
特性一:速度狂飙,从开漏变推挽
I3C 最直观的改变就是 快。 它在标准 SDR(单数据速率)模式下,时钟频率可以直接飙到 12.5MHz! 而且还支持 HDR(高数据速率)模式,最高有效数据吞吐量可以达到 30 Mbps 以上。
为什么它能这么快?
因为 I3C 改变了电气特性!I2C 只有开漏输出,必须靠外部电阻把电平拉上去,所以上升沿很慢(像爬坡一样)。而 I3C 在传输数据时, 允许使用推挽输出(Push-Pull)! 内部的晶体管直接把电平强行拉高或拉低,上升沿非常陡峭,速度自然就上去了。更绝的是,为了省电,I3C 的上拉不再依赖外部的死电阻,而是由主机内部的动态上拉电路(Active Pull-up)来控制。
特性二:带内中断(IBI),彻底干掉额外的中断线
这是 I3C 最伟大的创新之一: In-Band Interrupt(带内中断)。 以前,传感器有数据了,必须拉高外部 INT 引脚,主机检测到中断后,再发起 I2C 读取。 现在, 不需要额外的 INT 线了! I3C 允许从机在总线空闲时, 主动拉低 SDA 线, 向主机发起中断请求。主机一旦检测到 SDA 被拉低,就会马上提供时钟(SCL),让从机把自己的地址发过来。这就相当于:以前学生有问题只能举手(拉高 INT 引脚),老师点名后才能说话;现在学生可以在自习时间直接走到老师面前(拉低 SDA)说:“老师,我有个问题!”
![]()
// 伪代码:I3C 主机处理带内中断(IBI)的流程特性三:动态地址分配(DAA)
void I3C_IRQHandler(void) {
uint8_t slave_addr;
uint8_t payload[4 ];
// 1 . 主机检测到总线被拉低,进入 IBI 处理流程
if(I3C_GetInterruptStatus & I3C_INT_IBI) {
// 2 . 主机提供时钟,读取是谁发起了中断
slave_addr = I3C_ReadIBIAddress;
// 3. 读取该从机附带的中断载荷(比如直接把传感器数据发过来了)
I3C_ReadIBIPayload(slave_addr, payload, sizeof(payload));
// 4 . 清除中断标志
I3C_ClearInterrupt(I3C_INT_IBI);
printf("收到来自设备 0x%02X 的中断,数据: %d\n", slave_addr, payload[0 ]);
}
}
在 I3C 总线上,你再也不用担心两个芯片地址冲突了。因为 I3C 支持 Dynamic Address Assignment(动态地址分配)。 在系统上电初始化时,I3C 主机会向总线广播一个特殊命令(ENTDAA)。接着,总线上的所有从机开始“自报家门”,报出自己独一无二的 48 位 PID(类似于网卡的 MAC 地址)。主机根据 PID,给每个从机临时分配一个 7 位地址。这套机制完美解决了地址冲突,而且支持设备热插拔(Hot-Join),简直就是总线界的 DHCP!
特性四:向后兼容老旧的 I2C 设备
如果板子上既有新买的 I3C 传感器,又有库存的老旧 I2C 芯片怎么办?完全没问题!I3C 总线可以无缝挂载传统的 I2C 从机。只要主机的速度降下来,用开漏模式去和老设备通信即可。在同一根总线上,主机面对 I3C 设备时就切入“狂飙模式”,面对 I2C 设备时就切入“散步模式”。
I2C 与 I3C 协议的底层差异对比
我们来看一下,在代码层面,这两种协议的驱动逻辑会有什么不同。
I2C 的典型读取流程:
你需要指定设备地址,发送寄存器地址,然后发起重新启动(Repeated Start),再读取数据。
![]()
// I2C 典型读取
HAL_I2C_Master_Transmit(&hi2c1, DEV_ADDR, ®_addr, 1 , HAL_MAX_DELAY);
HAL_I2C_Master_Receive(&hi2c1, DEV_ADDR, data_buf, 4 , HAL_MAX_DELAY);
I3C 的 CCC(公共命令代码)机制:
I3C 引入了一套标准化的命令系统,叫做 CCC(Common Command Codes)。
你可以用一条命令让所有设备休眠,或者用一条命令获取设备的能力信息(GETBCR)。
![]()
// 伪代码:I3C 发送广播命令,让所有设备进入休眠
uint8_t ccc_entAS0 = 0x00; // Enter Activity State 0
I3C_SendBroadcastCCC(ccc_entAS0);
// I3C 读取设备特征寄存器 (BCR)
uint8_t bcr_val;
I3C_SendDirectCCC(DEV_ADDR, CCC_GETBCR, &bcr_val, 1 );
if(bcr_val & 0x02) {
printf("该设备支持带内中断 (IBI)!\n");
}
可以明显看到,I3C 的软件架构比 I2C 复杂得多。它不再只是单纯的读写字节,而是更像一个一个小型的网络协议栈,有自己的管理命令、地址分配机制和错误恢复机制。
总结:I2C 真的会被淘汰吗?
看完 I3C 这么多牛逼的特性,你可能会问: 既然 I3C 这么强,那 I2C 是不是马上就要凉了?答案是:短期内绝对不会,但长期来看 I3C 必然上位。
目前,I3C 主要应用在高端智能手机、VR/AR 设备和高级汽车电子中。这些场景对功耗极其敏感,且传感器数量庞大(动辄十几个摄像头和陀螺仪),I2C 根本扛不住。但在普通的单片机(比如我们常用的 STM32F1/F4 系列)、简单的家电控制、甚至大部分工业控制节点中,I2C 依然是王者。原因很简单:
1. 够用就好: 读个温湿度、写个 24C02,100kHz 的速度绰绰有余。
2. 成本极低: 几乎所有几十毛钱的廉价 MCU 都内置了 I2C 硬件外设。
3. 生态无敌: 市面上有数以万计的成熟 I2C 传感器模块,换协议的代价太大。
不过,随着物联网的不断进化,当未来连一个几块钱的 MCU 都标配 I3C 外设时,这场总线革命才会真正完成。作为嵌入式工程师, 现在可能还不需要你立刻在项目中把 I2C 换成 I3C,但你必须开始了解它、学习它。 因为总有一天,你会拿到一块带有 I3C 接口的新芯片,而那时,我希望你已经准备好了。
没有好的单片机项目,到处找项目做? 需要哇塞单片机项目的 完整源码+技术文档+视频教程?
![]()
点击此处领取单片机项目资料
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.