I2C通信协议
I2C通信
- I2C(Inter IC Bus) 是由Philips公司开发的一种通用数据总线
- 两根通信线: SCL(Serial Clock) 、SDA(Serial Data)
- SCL: 时钟线
- 同步通信中,主机通过时钟线(SCL)向从机传输时钟信号,从而指导从机接受数据; 当主机需要暂停传输去处理其他事情时,时钟线也暂停,从机也暂停接受数据;因此,同步通信对传输的时间要求不高
- 而异步通信中,若主机停止传输数据,从机仍以一定速率读取数据,很容易造成数据传输错误等问题,因此通信对传输的时间要求高,必须有硬件电路(如USART电路) 的支持才能保证传输的正确
- 由于I2C的传输是通过时钟信号同步进行的 因此,可以通过软件模拟I2C通信
- SDA:
- 数据读写通道,半双工
- SCL: 时钟线
- 同步, 半双工
- 带数据应答
- 支持总线挂载多设备(一主多从, 多主多从)
硬件电路(硬件规定)
- 所有I2C设备的SCL连在一起, SDA连在一起
- 设备的SCL和SDA均要配置成开漏输出模式
- SCL和 SDA各添加一个上拉电阻, 阻值一般为4.7KΩ左右
I2C工作特点(对照硬件电路)
- CPU作为主机, 任何时候都是主机完全掌握SCL线
- 在空闲状态下, 主机可以主动发起对SDA的控制;当从机发送数据和从机应答的时候, 主机转交SDA的控制权给从机
- 挂载的从机, 在任何时刻都只能被动读取SCL时钟线
- 从机不允许主动发起对SDA的控制(只有在主机发送读取从机的命令或从机应答时才有控制权)
配置成开漏输出模式的原因
I2C电路特点
- 因为I2C是半双工的协议, 主机和从机的SDA在发送时是输出,在接受时是输入,引脚的输入输出模式需要频繁切换;若总线时序没协调好,极有可能发生两个引脚同时处于输出的状态,若又正好一个输出高电平, 一个输出低电平, 则会造成电源短路
- 为了避免上面的问题, I2C禁止所有设备输出强上拉的高电平, 采用外置弱上拉电阻加开漏输出的电路结构的方案
- 三极管导通时, 引脚输出低电平(强下拉); 三极管关断时且浮空时, 由上拉电阻拉至高电平(弱上拉); 三极管关断时且有输入时,可观察电平高低判断输入的信号波形
采用开漏输出的优点
- 杜绝了电源短路现象, 保证电路的安全
- 避免了引脚模式的频繁切换(开漏输出加上拉的模式同时兼具输入和输出的功能)
- “线与”现象,任意一个或多个设备输出低电平, 总线处于低电平,所有设备输出高电平, 总线处于高电平; 多主机模式下可以利用这个特征
I2C时序基本单元(软件规定)
- 起始条件: SCL高电平期间, SDA从高电平切换到低电平(下降沿触发)
- 终止条件: SCL高电平期间, SDA从低电平切换到高电平(上升沿触发)
起始条件和终止条件都是由主机产生, 从机不允许产生起始和终止(一主多从模式下)
- 发送一个字节: SCL低电平期间, 主机将数据位依次放到SDA线上(高位先行), 然后释放SCL, 从机将在SCL高电平期间读取数据位, 所以SCL高电平期间SDA不允许有数据变化, 依次循环上述过程8次即可发送一个字节
- 接收一个字节: SCL低电平期间, 从机将数据位依次放到SDA线上(高位先行), 然后释放SCL, 主机将在SCL高电平期间读取数据位, 所以SCL高电平期间SDA不允许有数据变化, 依次循环上述过程8次, 即可接收一个字节
注意: ** 当主程序进入中断时, SCL保持, 执行完中断函数回到主程序后SCL继续变化, 保证了发送数据和接收的同步, 能够避免数据丢失**
- 发送应答: 主机在接收完一个字节后, 在下一个时钟发送一位数据, 数据0表示应答, 数据1表示非应答
- 接收应答: 主机在发送完一个字节后, 在下一个时钟接收一位数据, 判断从机是否应答, 数据0表示应答, 数据1表示非应答(主机在接收前,需要释放SDA)
I2C时序
基本概念
- 从机设备地址(7位、10位), 每个I2C设备在出厂时, 会分配一个7位地址
- 地址中的可变部分(用于挂载多个相同设备)
指定地址写
对于指定设备(Slave Address), 在指定地址(Reg Address) 下, 写入指定数据(Data)
- S: 起始条件(SCL高电平, SDA下降沿)
- Slave Address: 发送指定设备的地址 (该处地址为1101000) R/W 读或写 1为读 0为写
- RA: 0 表示应答位(此时SCL为高电平,主机SDA位释放, SDA控制权在从机, 从机SDA发送0, SDA整体波形为0)
- Reg Address: 发送指定地址(寄存器地址)(00011001)
- P: 终止条件(SCL高电平, SDA上升沿)
当前地址读
对于指定设备(Slave Address), 在当前地址指针指示的地址下, 读取从机数据(Data)
- R/W = 1 读
- 无指定地址(Reg Address)
- 发送指定设备地址后, SDA控制权在从机
- 写入后指针+1(指向下一位)
指定地址读
对于指定设备(Slave Address), 在指定地址(Reg Address) 下, 读取从机数据(Data)
- 先指定地址写(但是不发送数据)
- 再当前地址读
- 发送指定地址后, SDA控制权在从机
- 写入后指针+1(指向下一位)