I2C的全称是Inter-Integrated Circuit,中文一般译为"内部集成电路总线"。它由飞利浦半导体公司(现恩智浦NXP半导体)在1982年提出,是一种专门用于电路板上芯片间短距离数据交换的串行通信总线标准。I2C属于同步串行通信总线,这意味着数据线上每个比特的传输都由一根独立的时钟线来同步,不需要通信双方各自维护独立的波特率发生器。I2C仅依靠两根信号线——串行数据线SDA和串行时钟线SCL——即可在单个主设备与多个从设备之间完成双向数据传输。在软考嵌入式系统设计师大纲中,I2C属于"嵌入式系统通信接口"模块的核心考点,与SPI、UART、CAN并列为四类主流串行总线。
从协议规范角度看,I2C标准经历了多次速率升级。最初定义了100kbit/s的标准模式,1992年引入400kbit/s的快速模式,1998年推出3.4Mbit/s的高速模式,2012年补充了5Mbit/s的超快速模式。但不管速率如何提升,I2C的帧格式、起始停止条件、应答机制和仲裁逻辑始终保持向下兼容,这正是协议设计精良的体现。软考命题通常以标准模式和快速模式为参考,考察考生对基本时序参数和协议状态机的理解。
I2C区别于其他串行总线的最大特征是它的多主多从架构和片选线精简设计。SPI总线每增加一个从设备就需要增加一根片选线,一个挂载四个从设备的SPI系统至少需要七根信号线(SCK加MOSI加MISO加四根CS),而I2C无论挂载多少个从设备,始终只占用两根信号线。每个从设备通过唯一的设备地址来区分,主设备在每次通信开始时首先发送目标从设备的地址字节,所有挂载在总线上的设备都会接收这个地址并与自身地址比对,匹配者继续参与后续通信,不匹配者进入空闲等待状态。这种"寻址式"的多设备管理机制使得I2C在引脚资源极度紧张的嵌入式系统中具有无可替代的优势。
I2C的另一个核心设计思想是"线与"逻辑与开漏输出。SDA和SCL两条线都通过上拉电阻连接到电源,总线上的所有设备输出级均采用开漏或开集结构,只能主动输出低电平而不能主动输出高电平,高电平完全靠上拉电阻来维持。这一设计产生了一个关键特性:任意一个设备将线路拉低,整条线路就被拉低;只有当所有设备都不拉低时,上拉电阻才能将线路恢复到高电平。这种机制不仅天然支持了多主设备的冲突检测与仲裁,还使得从设备可以通过拉低时钟线来主动插入等待周期,即时钟拉伸机制。
在嵌入式系统的通信接口技术栈中,I2C处于一个非常明确的位置。从传输距离来看,I2C是典型的板级总线,传输距离通常不超过数米,主要用于同一块PCB上芯片之间的短距离互联。从速率来看,I2C标准模式100kbit/s、快速模式400kbit/s的数据吞吐量适合传感器数据读取、配置寄存器读写和EEPROM存取等中低速场景。从拓扑结构来看,I2C支持真正的多主架构,任何设备都可以主动发起通信,这一点不同于UART的点对点特性和SPI的固定主从关系。理解I2C在通信技术栈中的位置,有助于在系统设计时正确选择总线类型,也能在面对软考选择题时快速排除干扰项。
I2C总线的物理层由两个关键元素构成:开漏输出驱动器和上拉电阻。总线上的每个设备,其SDA和SCL引脚内部都是一个N沟道MOSFET的漏极,源极接地。当设备需要输出低电平时,MOSFET导通,将线路拉到地;当设备需要释放总线时,MOSFET关断,引脚进入高阻态,此时由上拉电阻将线路拉高到VCC。这种结构决定了总线上不会出现两个设备一个输出高电平、一个输出低电平导致的短路冲突——因为根本没有设备可以真正"输出"高电平,所有高电平都是上拉电阻被动拉上去的。
上拉电阻的取值是I2C硬件设计中最常被忽略却又至关重要的参数。电阻太大,RC充电时间常数增大,信号上升沿变慢,严重时会导致时序违例;电阻太小,总线上设备拉低线路时需要灌入更大的电流,可能超出器件IO引脚的灌电流能力,也会增加系统功耗。实际设计中,上拉电阻的最小值由器件的最大灌电流决定,最大值由总线电容和信号速率共同决定。在标准模式100kHz下,当总线电容不超过400pF时,典型上拉电阻为4.7kΩ;在快速模式400kHz下,推荐值通常降至2.2kΩ到3.3kΩ之间。软考命题偶尔会在选择题的硬件设计部分涉及上拉电阻的选型原则,考生需要理解权衡逻辑而非死记数值。
起始条件和停止条件是I2C协议中最基本的两个特殊信号状态,它们分别标志着一次总线传输的开始与结束。起始条件的定义是:当SCL为高电平时,SDA产生从高电平到低电平的下降沿跳变。停止条件的定义是:当SCL为高电平时,SDA产生从低电平到高电平的上升沿跳变。两组定义听起来对称而简单,但其中隐含的条件恰好是软考命题人最喜欢设陷阱的地方。
起始条件和停止条件的关键约束有两条。第一,这两个跳变动作必须发生在SCL为高电平期间。如果在SCL为低电平时SDA发生变化,那是在为下一个数据位做准备,属于正常的数据切换过程,不会被识别为起始或停止。第二,起始条件必须由主设备产生,总线上其他设备在检测到合法的起始条件后,立即转入监听状态,准备接收接下来的地址字节。在标准模式下,起始条件的建立时间至少需要维持4.7微秒,保持时间至少需要4.0微秒,这些参数在高速模式下会相应缩减。
除了常规的起始与停止条件外,I2C协议还定义了一个特殊信号:重复起始条件。在主设备未发送停止条件之前,可以用一个新的起始条件替代停止条件,直接在当前传输中启动下一帧数据,而不释放总线。这一机制主要用于组合写操作:主设备先写入从设备内部寄存器地址,接着使用重复起始条件切换传输方向,立即从该地址开始读取数据。软考中会考察重复起始条件与普通起始条件的区别及其适用场景。
I2C总线上每一个数据字节的长度固定为8位,从最高位开始逐位发送。发送方每发送完一个字节后,在第9个时钟脉冲期间释放SDA线,由接收方输出应答信号。应答信号为低电平表示ACK,即接收方成功接收该字节并准备好继续接收下一个字节;应答信号为高电平表示NACK,即接收方不再继续接收数据或发生了错误。主设备收到NACK后,必须主动发送停止条件来结束传输,否则总线将持续处于被占用状态。
应答机制在I2C协议中还有两个关键的延伸用法。第一,主设备作为接收方时,在读取完最后一个字节后主动返回NACK,以此告知从设备"我不需要更多数据了",从设备收到NACK后会释放SDA线,主设备随后发送停止条件。第二,从设备可以在接收地址字节后返回NACK来告知主设备"总线上没有这个地址的设备"或"该设备当前不可用",这是主设备检测从设备存在性的基本手段。许多初学者在调试I2C通信时遇到从设备始终不响应的问题,往往就是地址字节发错了,导致从设备返回NACK而主设备没有正确处理。
在多个主设备共享同一条I2C总线的场景中,每个主设备都有可能拥有不同的时钟频率。I2C通过线与逻辑实现了一种优雅的时钟同步机制:当SCL线上出现低电平时,所有监测到该低电平的主设备都会重置各自的时钟计数器,从此刻开始统一计时各自的低电平持续时间。最先结束低电平计时的主设备不能立即将SCL拉高,必须等待直到检测到SCL线实际已经变为高电平——而SCL线被拉高的条件是所有设备都释放了它。因此,总线上低电平的持续时间由所有主设备中低电平时钟最长的那一个决定,高电平的持续时间则由高电平时钟最短的那一个决定。整个SCL时钟周期是所有主设备时钟周期的"最小公倍数"式的协商结果。
时钟拉伸是时钟同步机制在从设备侧的延伸应用。当一个从设备接收到数据但内部处理尚未完成、暂时无法继续接收下一个字节时,它可以在主设备释放SCL之后立即将SCL拉低,强迫主设备进入等待状态。主设备在每个时钟周期结束前都会检查SCL是否已经被释放,如果发现SCL仍被拉低,就暂停发送下一个时钟脉冲。这种机制避免了从设备因处理速度跟不上而导致的数据丢失,尤其常见于低速EEPROM和传感器芯片。需要注意的是,并非所有I2C从设备都支持时钟拉伸,部分简单的GPIO扩展器芯片不允许从设备干预SCL线,主设备如果在初始化阶段未正确配置时钟拉伸超时参数,遇到从设备拉低SCL的场景可能会导致死等或超时复位。
I2C总线上的每个从设备由唯一的设备地址来标识。协议最初定义的是7位寻址模式,地址字节的高7位为从设备地址,最低位为读写方向位。方向位为0代表主设备写入从设备,方向位为1代表主设备从从设备读取。7位寻址可支持最多128个设备地址,但其中16个地址被协议规范保留用于特殊用途(如通用呼叫地址0x00、高速模式主设备码0x00001xxx等),因此实际可用地址约为112个。
随着I2C应用范围的扩大,部分复杂系统对地址空间提出了更高要求。协议后续扩展了10位寻址模式,使用两个字节来承载完整地址。第一个字节的前5位固定为11110,紧接着两位为10位地址的高两位,最低位仍为读写方向位。
本篇完!