IIC协议详解,附单片机软件模拟源码

I2C协议

  • 物理层
    1. 原理
    2. 总体特征
    3. 电气限制
  • 协议层
    1. 起始和停止条件
    2. 数据有效性
    3. 响应/应答
    4. 寻址
    5. 读数据
    6. 写数据
  • 单片机通讯
    1. 软件模拟
    2. 硬件外设

(一)物理层

img

2. 总体特征

? 连接到总线的器件输出级必须是漏极开路或集电极开路才能执行线与的功能。上拉能力即上升沿时间由外部电源和上拉电阻决定, 下降沿由器件OD产生, 速度快。因此IIC的通信速率由上拉能力决定。

? I2C 总线上的每一个设备都可以作为主设备或者从设备,而且每一个设备都会对应一个唯一的地址(可以从I2C器件的数据手册得知),主从设备之间就通过这 个地址来确定与哪个器件进行通信。

? I2C 总线上数据的传输速率在标准模式下可达 100kbit/s ,在快速模式下可达 400kbit/s ,在高速模式下可达 3.4Mbit/s ,连接到总线的接口数量只由总线电容是 400pF 的限制决定。

? I2C 总线上的主设备与从设备之间以字节(8位)为单位进行双向的数据传输。

3. 电气限制

最大device数量

IIC协议本身没有严格规定总线上device最大数目, 从理论上看, IIC能挂的device数目取决于能表示的最大地址空间, 在7位地址模式下, 减去0x00地址不可用, 理论上可以挂 2 7 ? 1 = 127 2^7 -1 = 127 27?1=127个设备。

但是IIC规定了总线电容不能超过400pF(具体与通信速率有关如下图)。

IIC协议详解,附单片机软件模拟源码

(二)协议层

1. 起始和停止条件

IIC协议详解,附单片机软件模拟源码
  • 总线在空闲状态 时,SCL和SDA都保持着高电平,
  • 当SCL为高而SDA由高到低的跳变,表示产生一个起始条件;
  • 当SCL为高而SDA由低到高的跳变,表示产生一个 停止条件。
  • 在起始条件产生后,总线处于忙状态,由本次数据传输的主从设备独占,其他I2C器件无法访问总线;
  • 而在停止条件产生后,本次数据传输的主从设备将释放总线,总线再次处于空闲状态。

2. 数据有效性

SDA线上的数据必须在SCL的高电平时保持稳定。

SDA线的高或低电平状态只有在 SCL 线的时钟信号是低电平时才能改变。

tMhU1J.png

3. 响应

数据传输必须带响应,相关的响应SCL时钟脉冲由主机产生,在响应的时钟脉冲期间,发送器释放 SDA 线(输出高阻态使SDA线被上拉电阻拉高)。在响应的时钟脉冲期间,接收器必须将 SDA 线拉低,使它在这个时钟脉冲的高电平期间保持稳定的低电平。 必须考虑建立和保持时间。

tMLssS.png

在起始条件 S 后 ,发送了一个从机地址SLAVE ADDRESS, 这个地址共有 7 位,紧接着的第 8 位是数据方向位[R/W], 0 表示写,1表示读。接下来的一个bit是应答位NACK/ACK,当这个帧中前面8bits发送完后,接收端获得SDA控制权,此时接收设备应该在第9个时钟脉冲之前回复一个ACK(将SDA拉低)以表示接收正常,如果接收设备没有将SDA拉低,则说明接收设备可能没有收到数据(如寻址的设备不存在或设备忙)或无法解析收到的消息,如果是这样,则由master来决定如何处理(stop或repeated start condition)。

tMLSEj.png

10 位从机地址是由在起始条件 S 或重复起始条件 Sr 后的头两个字节组成。

第一个字节的头 7 位是 11110XX 的组合 ,其中:最后两位 XX 是 10 位地址的两个最高位 MSB

第一个字节的第 8 位是 R/ W 位, 决定了报文的方向 :0 表示写, 1 表示读。

如果 R/ W 位是 0 则下一个字节是 10 位从机地址剩下的 8 位;

如果 R/ W 位是 1 则下一个字节是从机发送给主机的数据。

仲裁过程

主机只能在总线空闲的时侯启动传输。两个或多个主机可能在起始条件的最小持续时间内产生一个起始条件,结果在总线上产生一个规定的起始条件。

当 SCL 线是高电平时,仲裁在 SDA 线发生。这样,在其他主机发送低电平时,发送高电平的主机将退出竞争, 因为总线上的电平与它自己的电平不相同。

仲裁可以持续多位。第一个阶段是比较地址位,如果每个主机都尝试寻址相同的器件,当主机作发送器时仲裁会继续比较数据位,当主机作接收器时仲裁会继续比较响应位。

IIC总线的地址和数据信息由赢得仲裁的主机决定,因此在仲裁过程中不会丢失信息。

丢失仲裁的主机可以产生时钟脉冲,直到丢失仲裁的该字节末尾。

tMLZb4.png

第一步,主机发送一个起始信号S。

第二步,主机发送7bit从机地址。此处需要注意,发送数据时,无法发送7bit数据,此处发送了7bit地址+1bit读写选择位,即发送7bit+R/W。最低位为1表示读,为0表示写。

第三步,从机产生一个ACK应答信号。

//第四步,主机发送寄存器地址。
//第五步,从机产生一个ACK应答信号。
//第六步,主机再次发送一个起始信号。
//第七步,主机发送7bit从机地址,即7bit+R/W。最低位为1表示读,为0表示写。
//第八步,从机产生一个ACK应答信号。

第九步,主机读取一个字节(8bit)的数据(相当于从机发送一个字节)。
第十步,CPU产生一个ACK应答信号。

//第十一步,读取一个CRC校验码。

第十二步,CPU产生一个NACK无应答信号。
第十三步,主机产生一个停止信号。

常规的使用就是第一、二、三、九、十、十二、十三步。 注释掉的是单片机继承的硬件IIC整个完整的通讯过程。

6. 写数据

CPU作为主发送器

tMbPds.png

第一步,主机发送一个起始信号。

第二步,发送7bit从机地址。此处需要注意,发送数据时,无法发送7bit数据,此处发送了7bit地址+1bit读写选择位,即发送7bit+R/W。最低位为1表示读,为0表示写。

第三步,从机产生一个ACK应答信号。

//第四步,主机发送寄存器地址,8bit数据。
//第五步,从机产生一个ACK应答信号。

第六步,主机发送一个字节(8bit)数据。
第七步,从机产生一个ACK应答信号。

//第八步,主机发送一个CRC校验码,此CRC校验值为2、4、6步数据产生的校验码。

第九步,从机既可以发送一个应答信号,也可以发送一个无应答信号。
第十步,主机发送一个停止信号。

(三)单片机IIC通讯


1. 软件模拟

CPU与EEPROM通讯为例

相关函数:

stm32硬件I2C配置流程:

  1. 初始化GPIO

    • 模拟总线SDA, SCL ,GPIO引脚开漏输出

  2. 写起始信号函数

    • SDA, SCL拉高 , 延时

    • SDA由高变低 , 延时

    • SCL拉低,延时等待发送/接收

  3. 写终止信号函数

    • SCL拉低后将SDA拉低 (SCL低电平时SDA可变),延时

    • SCL拉高 , 延时

    • SDA由低变高 , 延时

  4. 等待应答信号函数

  5. 产生/不产生ACK应答

  6. 写一个字节

  7. 读一个字节

//延时static void I2c_Delay(void){    /*CPU主频72MHz 10: SCL频率205KHz 7:  SCL频率347KHz,高电平1.5us,低电平2.87us; 5:  SCL频率421KHz,高电平1.25us,低电平2.375us;*/    u8 i;    for(i = 0; i  10; i++);}//起始信号void I2C_Start(void){    I2C_SDA_High();     //SDA=1    I2C_SCL_High();     //SCL=1    I2C_Delay();    I2C_SDA_Low();    I2C_Delay();    I2C_SCL_Low();    I2C_Delay();}//终止信号void I2C_Stop(void){    I2C_SDA_Low();    I2C_SCL_High();    I2C_Delay();    I2C_SDA_High();    I2C_Delay();}//写一个字节u8 I2C_SendByte(uint8_t Byte){    uint8_t i;     /* 先发送高位字节 */    for(i = 0 ; i  8 ; i++)    {if(Byte & 0x80){    I2C_SDA_High();}else{    I2C_SDA_Low();}I2C_Delay();I2C_SCL_High();I2C_Delay();I2C_SCL_Low();I2C_Delay(); if(i == 7){    I2C_SDA_High();  /* 释放SDA总线 */}Byte  1;      /* 左移一位  */ I2C_Delay();    }} //读取一个字节u8 I2C_ReadByte(void){    uint8_t i;    uint8_t value;     /* 先读取最高位即bit7 */    value = 0;    for(i = 0 ; i  8 ; i++)    {value  1;I2C_SCL_High();I2C_Delay();if(I2C_SDA_READ()){    value++;}I2C_SCL_Low();来源:Ethan-Code
                                                        

声明:本站部分文章及图片转载于互联网,内容版权归原作者所有,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2021年8月24日
下一篇 2021年8月25日

相关推荐