1、I2C通信的基本流程
2、I2C的数据帧格式
起始条件:SCL高电平期间,SDA从高电平切换到低电平
终止条件:SCL高电平期间,SDA从低电平切换到高电平
发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节
接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)
Tip:I2C发送数据是高位先行(看图),串口发送数据是低位先行
举例:
1、串口(UART)发送
规则:低位先行
在串口通信中,起始位(低电平)之后,紧跟着发送的是数据的最低位(bit 0)。
发送顺序:
-
起始位:拉低电平(开始)
-
bit 0:
0(最低位,波形:低) -
bit 1:
0 -
bit 2:
0 -
bit 3:
0 -
bit 4:
1 -
bit 5:
1 -
bit 6:
0 -
bit 7:
0(最高位) -
停止位:拉高电平(结束)
二进制流(从左到右是时间先后):
[起始] 0 0 0 0 1 1 0 0 [停止]
如果你用示波器抓串口的TX脚:
你会看到数据位是 00001100(反过来看的),但示波器通常直接解析成 0x30。
2、I2C发送
规则:高位先行
在I2C通信中,SCL时钟配合下,SDA上先发送的是数据的最高位(bit 7)。
发送顺序(仅数据字节部分,忽略起始/应答条件):
-
bit 7:
0(最高位) -
bit 6:
0 -
bit 5:
1 -
bit 4:
1 -
bit 3:
0 -
bit 2:
0 -
bit 1:
0 -
bit 0:
0(最低位)
二进制流(从左到右是时间先后):
0 0 1 1 0 0 0 0
如果你用示波器抓I2C的SDA线:
你会看到数据位是 00110000,这恰好就是 0x30 的二进制正序书写形式。
3、直观对比(示波器眼里的样子)
为了帮助你记忆,这里有一个非常直观的“书写对照”:
| 协议 | 二进制值 0x30 |
你在纸上写的二进制 | 实际线上先发的比特 | 波形从左到右的顺序 |
|---|---|---|---|---|
| 串口 | 0011 0000 |
MSB -> LSB | LSB (最右边) | 00001100(反着) |
| I2C | 0011 0000 |
MSB -> LSB | MSB (最左边) | 00110000(正着) |
记忆口诀:
串口是反着发的(先发低位)。
I2C是正着发的(先发高位)。
发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答
接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)
3、寻址
这里其实有争议:
(1)左移后末尾变1
(2)直接末尾变1
到底是哪一种,等作者实践之后给出答案。
如果有相同地址(相同型号芯片地址一般相同)的芯片挂载在同一根总线下呢?:可以通过更改芯片地址的可变部分
4、I2C时序
1、指定地址写
对于指定设备(Slave Address),在指定地址(Reg Address)下,写入指定数据(Data)
2、当前地址读
对于指定设备(Slave Address),在当前地址指针指示的地址下,读取从机数据(Data)
3、指定地址读
对于指定设备(Slave Address),在指定地址(Reg Address)下,读取从机数据(Data)