目录
[1. I2C介绍](#1. I2C介绍)
[1.1 常用术语](#1.1 常用术语)
[1.2 I2C物理层](#1.2 I2C物理层)
[1.3 I2C协议层](#1.3 I2C协议层)
[1.3.1 数据有效性规定](#1.3.1 数据有效性规定)
[1.3.2 起始和停止信号](#1.3.2 起始和停止信号)
[1.3.3 应答响应](#1.3.3 应答响应)
[1.3.4 总线的寻址地址](#1.3.4 总线的寻址地址)
[1.3.5 数据传输](#1.3.5 数据传输)
1. I2C介绍
I2C(Inter-Integrated Circuit)总线是一种两线式串行总线,用于连接微控制器及其外围设备,是同步通信的一种特殊形式,具有接口线少,控制方式简单,器件封装形式小,通信速率较高等优点
I2C 总线只有两根双向信号线,一根是数据线 SDA ,另一根是时钟线 SCL,由于其管脚少,硬件实现简单,可拓展性强等特点,被广泛的使用在各大集成芯片内
1.1 常用术语
I2C 通信设备 :采用 I2C总线协议进行数据传输的电子设备 / 芯片
主机:启动数据传送并产生时钟信号的设备
从机:被主机寻址的器件
主模式:用 I2CNDAT 支持自动字节计数的模式,位 I2CRM,位I2CSTT,I2CSTP控制数据的接收和发送
从模式:发送和接收操作都是由I2C模块自动控制的
仲裁:在有多个主机同时尝试控制总线但只允许其中一个控制总线并使传输不被破坏的过程
同步:两个或多个器件同步时钟信号的过程
发送器:发送数据到总线的器件
接收器:从总线接收数据的器件
多主机:同时有两个及两个以上的主机尝试控制总线但不破坏传输
1.2 I2C物理层
I2C 通信设备常用的连接方式如下所示:

物理层有如下特点:
①总线支持多设备:"总线"是指多个设备共用的信号线。在一个I2C通讯总线中,可连接多个I2C通讯设备,支持多个通讯主机及多个通讯从机
②一个I2C总线只使用两条总线线路,一条双向串行数据线(SDA),一条串行时钟线(SCL)。数据线用来表示数据,时钟线用于数据收发同步
③每个连接到总线的设备都有一个独立的地址,主机可以利用这个地址进行不同设备间的访问
④总线通过上拉电阻接到电源。当 I2C 设备空闲时,会输出高阻态,而当所有设备都空闲,都输出高阻态时,由上拉电阻把总线拉成高电平
⑤多个主机同时使用总线时,为了防止数据冲突,会用仲裁的方式决定由哪个设备占用总线
⑥具有三种传输模式:标准模式传输速率为100kbit/s,快速模式为400kbit/s,高速模式为3.4Mbit/s,但目前大多I2C设备尚不支持高速模式
⑦连接到相同总线的IC数量受到总线的最大电容400pF 限制
1.3 I2C协议层
I2C协议定义了通信的起始信号、停止信号、数据有效性、响应、仲裁、时钟同步和地址广播等环节
1.3.1 数据有效性规定
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定
只有在时钟线上的信号为低电平期间,数据线上的高/低电平状态才允许变化
每次数据传输都以字节为单位,每次传输的字节数不受控制

1.3.2 起始和停止信号
SCL为高电平期间,SDA线 由高电平向低电平的变化表示起始信号
SCL为高电平期间,SDA线 由低电平向高电平的变化表示终止信号
起始信号和终止信号都是由主机发出的,在起始信号产生后,总线就处于被占用的状态
终止信号产生后,总线就处于空闲状态

1.3.3 应答响应
每当发送器件传输完一个字节的数据后,后面必须紧跟一个校验位 【该校验位是接收端控制SDA来实现的(SDA,SCL都是双向信号线)】,以提醒发送端数据我这边已接收完成,可以继续进行数据传送,这个校验位就是数据/地址传输过程中的响应;
响应包括"应答(ACK) "和"非应答(NACK)"两种信号:
通信中 "应答位(ACK)" 的交互规则固定:主机发送完 1 字节数据(地址或数据)后,会释放 SDA 线的控制权 ,然后在第 9 个时钟周期内,由从机控制 SDA 线状态,完成应答或不应答操作。
左侧灰色区域:起始信号(S)
I2C 的起始信号是通信的 "开场白",规则是:
- 当
SCL(主机时钟)处于高电平 时,SDA(主机数据线)出现从高到低的下降沿(图中 SDA 的黑色箭头就是这个动作)。 - 这个信号的作用是告诉总线上的所有从机:"我(主机)要开始发数据了,准备接收"。
SCL 的 1~8 时钟周期:主机发送 8 位数据
I2C 中数据是按字节(8 位)传输 的,这 8 个时钟周期对应 1 字节数据(可能是从机地址、读写指令 ,或是实际数据):
SCL由主机控制,每一个时钟的高电平期间 ,从机会采样SDA上的电平(高 = 1,低 = 0),所以主机要在SCL低电平期间提前把下一位数据的电平准备好,保证SCL高电平时SDA稳定(图中主机 SDA 的波形在每个 SCL 周期内是平稳的,就是为了让从机准确采样)。- 这一步是 "主机→从机" 的单向数据传输。
第 9 个时钟周期:应答位(ACK/NACK)
这是 I2C 的 "反馈环节",规则是:
- 主机发完 8 位数据后,会在第 9 个时钟周期释放 SDA 的控制权(不再主动控制 SDA 电平);
- 此时由从机控制 SDA :
- 若从机拉低 SDA(图中 "应答" 标注的波形),则表示 "我收到这字节数据了",这叫应答位(ACK);
- 若从机不操作 SDA(SDA 因上拉电阻保持高电平,图中 "非应答" 标注的状态),则表示 "我没收到 / 无法处理",这叫非应答位(NACK)。
每一个字节必须保证是8位长度,数据传送时,先传送最高位(MSB) ,每一个被传送的字节后面都必须跟随一个应答位(即一帧共有9位)
如果从机由于某种故障等原因无法应答时,主机检测到不应答后,为避免总线阻塞,通常会主动发送终止信号,释放总线资源
如果从机对主机进行了应答,但在数据传送一段时间后无法继续接收更多的数据时(即从机接收能力不足 ),从机可以通过对无法接收的第一个数据字节的"非应答 "(应答位的本质:"对当前字节的接收结果负责")通知主机,主机则应发出终止信号以结束数据的继续传送(主机每传 1 个字节,从机都在第 9 个时钟周期发 "应答(ACK)" ,表示 "我收到了,继续传下一个"。)
当主机接收数据时(即主机读取从机数据, 核心是 "读操作时,应答位的控制权转到了主机手里"),主机收最后一个字节,发 "非应答" ,即主机收完最后一个字节后,不再需要更多数据了 ------ 此时主机在第 9 个时钟周期释放 SDA(因为总线有上拉电阻,SDA 会保持高电平),这就是 "非应答(NACK)",告诉从机:"这是最后一个了,别发了"。从机收到这个 "非应答",就停止发送数据,并完全释放 SDA 线的控制权,主机确认 SDA 被释放后,发送 "终止信号"(SCL 高电平时,SDA 从低变高),结束整个读传输。
简单地说,读操作时,主机是 "收数据的一方",用 "最后一个字节后的非应答" 喊 "停",从机停了之后,主机再收尾。
注意:
① 从机无需主动置高 SDA ,而是不主动拉低 SDA 。由于总线有上拉电阻,SDA 会自然保持高电平,这就是 I2C 协议中的非应答位(NACK);
② 从机的 "主动动作" 仅出现在应答时 :**应答时从机会主动拉低 SDA 线,使第 9 个时钟周期内 SDA 保持低电平;**不应答时,从机完全释放 SDA,总线依靠上拉电阻回到高电平,并非从机主动输出高电平信号。

1.3.4 总线的寻址地址
按从机地址位数可分为两种,一种是 7 位,另一种是 10 位
采用 7 位的寻址字节(即起始信号后的第一个字节)的定义如下:
D7-D1 位组成从机的地址。
D0 位是数据传送方向位,0:表示主机向从机写数据;1:表示主机由从机读数据
10位 寻址和 7位 寻址兼容,而且可以结合使用。10位 寻址不会影响已有的7位寻址,有7位和10位地址的器件可以连接到相同的I2C总线
I2C 总线支持多从机挂载 (比如 51 单片机总线上同时接了 AT24C02 存储芯片、BH1750 光照传感器),每个从机都有唯一的 7 位地址(部分设备支持 10 位地址,但入门场景常用 7 位)
现以 7位 寻址为例:
主机发起 通信时,第一个发送的字节是 "7 位从机地址 + 1 位 R/W 位",此时:
- 总线上所有从机都会 "监听" 这字节的前 7 位;
- 每个从机把这 7 位和自己的地址对比:
- 地址匹配的从机:判定 "主机在找我",会在后续的应答位发 "应答(ACK)",准备和主机通信;
- 地址不匹配的从机:判定 "和我无关",会忽略后续的所有数据 / 时钟信号,进入 "静默状态"。
"R/W 位":决定从机是 "收数据" 还是 "发数据"
地址字节的第 8 位(最后 1 位)就是 R/W 位,它的作用是定义本次通信的方向:
- 若 R/W 位为
0:表示 "写(Write)",此时从机是从机接收器------ 主机要给从机发送数据(比如 51 单片机给 AT24C02 写存储内容); - 若 R/W 位为
1:表示 "读(Read)",此时从机是从机发送器------ 从机要给主机发送数据(比如 51 单片机读 BH1750 的光照数据)。
再来说说从机地址
I2C 从机地址的硬件设计 核心是通过 "固定地址 + 可编程地址" 的组合,解决 "同一型号从机多设备并联" 的问题;
I2C 从机的 7 位地址(入门场景常用)本质是厂商预设的固定位 + 用户可配置的可编程位组成,两者分工明确:
固定部分 :芯片出厂时由厂商固化在内部,同一型号的从机固定部分完全相同,作用是区分 "不同类型的器件"。
可编程部分 :芯片引脚引出的地址配置位(通常标注为 A0/A1/A2),用户可通过硬件接线(接 VCC 或 GND)设置其电平(高 = 1,低 = 0),从而改变这几位的地址值。作用是区分 "同一型号的不同个体",避免总线上相同型号的从机地址冲突。
注意:
- 可编程部分的设置是硬件层面的,一旦接线完成,地址就固定了,不能通过软件修改;
- 同一总线上,所有从机的完整地址必须唯一,哪怕是不同型号的器件,也不能设置相同地址;
- 部分芯片的可编程引脚如果悬空,可能会有不确定电平,建议项目中明确接 VCC 或 GND,避免地址错乱。

1.3.5 数据传输
I2C总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号
主机产生起始信号,起始信号后必须传送一个从机的地址(7位),第8位是数据的传送方向位(R/W),用 0 表示主机发送(写)数据,1 表示主机接收(读)数据。
每次数据传送总是由主机产生的终止信号结束,若主机希望继续占用新的数据传送,马上再次发出起始信号对另一从机进行寻址
在总线的一次数据传送过程中,可以有以下几种组合方式:
阴影部分:主机向从机传送数据 无阴影部分:从机向从主机传送数据
A:表示应答 A非:表示非应答(高电平)
S:起始信号 P:终止信号
① 主机向从机发送数据,数据传送方向在整个传送过程中不变

②主机发送第一个字节后,立即从从机读取数据

③ 在传送过程中,当需要改变传送信号(从 "主机→从机写数据" 切换为 "从机→主机读数据")时,起始信号和从机地址都被重复产生一次,但两次读/写方向位正好相反
主机先发起始信号 S + 从机地址 + 写方向位 0 ,给从机传数据(比如 AT24C02 的存储地址);当需要切换成 "读数据" 时,不发终止信号,直接重复发起始信号 S + 同一个从机地址 + 读方向位 1;这样就完成了 "传送方向的改变",同时保持总线一直被主机占用(避免被其他设备干扰)。
