IIC

313 阅读16分钟

同步时序和异步时序的区别

  • 异步时序
    • 好处:省一根时钟线,节省资源
    • 缺点:对时间要求严格,对硬件电路以来比较严重
  • 同步时序相反(主打下沉市场)
    • 好处:对时间要求不严格,对硬件电路不怎么依赖
    • 缺点:要一根时钟线

1.I2C通讯协议(inter IC BUS)

以前学51的IIC是通过AT24C02(存储器模块)来实现,本小节使用MCU6050(陀螺仪),加速度传感器来学习IIC

同步:同步通信指发送和接受双方在同一时刻使用相同时钟信号来进行数据传输

半双工:表示数据可以双向传输但是不能同时传输

2.硬件电路

  • 一主多从模型中协议的规定: 主机永远拥有SCL时钟线的控制权,在空闲时可以主动操控SDA线,也可以将SDA线的控制权交给从机;从机权力较小,永远只能被动的读取SCL线,不允许控制,从机不允许主动发起对SDA的控制,只有在主机发送从机读取的命令后或者从机应答的时候从机才能短暂的取得SDA的控制权。

  • 如果总线时序没有协调好,就极有可能发生两个引脚同时处于输出的状态。如果此时一个引脚输出高电平,一个引脚输出低电平,就会造成电源短路的情况,这是要极力避免的。 为了避免这种情况,I2C的设计规定所有设备不输出强上拉的高电平,而是采用外置弱上拉电阻加开漏输出的电路结构。这两点规定对应于前面提到的“设备的SCL和SDA均要配置成开漏输出模式”以及“SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右”。对应上面这个图。

引脚内部结构图

  • 原理(理解)输出低电平,这个开关管导通,引脚直接接地,是强下拉,输出高电平,这个开关管断开,引脚什么都不接,处于浮空状态,这样的话,所有的设备都只能输出低电平而不能输出高电平,为了避免高电平造成的引脚浮空,这时就需要在总线外面,SCL和SDA各外置一个上拉电阻,这是通过一个电阻拉到高电平的,所以这是一个弱上拉。
  • 引脚的信号输入都可以通过一个数据缓冲器或施密特触发器进行,因为输入对电路无影响,所以任何设备在任何时刻都可以输入。然而,在输出部分,采用的是开漏输出的配置。好处:
    • 第一,完全杜绝了电源短路现象,保证电路的安全。
    • 第二,避免了引脚模式的频繁切换。开漏加弱上拉的模式,同时兼具了输入和输出的功能。因为开漏模式下,输出高电平就相当于断开引脚,所以在输入之前,可以直接输出高电平,不需要再切换成输入模式了。
    • 第三,就是这个模式会有一个“线与”的现象。就是只要有任意一个或多个设备输出了低电平,总线就处于低电平,只有所有设备都输出高电平,总线才处于高电平。

3.I2C时序基本单元

  • SCL:迟到早退 SDA:早出晚归

  • 起始条件是指SCL高电平期间,SDA从高电平切换到低电平。在I2C总线处于空闲状态时,SCL和SDA都处于高电平状态,由外挂的上拉电阻保持。当主机需要数据收发时,会首先产生一个起始条件。这个起始条件是,SCL保持高电平,然后把SDA拉低,产生一个下降沿。当从机捕获到这个SCL高电平,SDA下降沿信号时,就会进行自身的复位,等待主机的召唤。之后,主机需要将SCL拉低。这样做一方面是占用这个总线,另一方面也是为了方便这些基本单元的拼接。这样,除了起始和终止条件,每个时序单元的SCL都是以低电平开始,低电平结束。

  • 终止条件是,SCL高电平期间,SDA从低电平切换到高电平。SCL先放开并回弹到高电平,SDA再放开并回弹高电平,产生一个上升沿。这个上升沿触发终止条件,同时终止条件之后,SCL和SDA都是高电平,回归到最初的平静状态。这个起始条件和终止条件就类似串口时序里的起始位和停止位。一个完整的数据帧总是以起始条件开始、终止条件结束。另外,起始和终止都是由主机产生的。因此,从机必须始终保持双手放开,不允许主动跳出来去碰总线。如果允许从机这样做,那么就会变成多主机模型,不在本节的讨论范围之内。这就是起始条件和终止条件的含义。

1.发送一个字节

  • 总结 :
    • 高位先行
    • 数据以字节传输
    • 数据在SCL高电平稳定
    • 数据发送完,还要有应答信号
  • 主机拉低SCL,把数据放在SDA上,主机松开SCL,从机读取SDA的数据。

SCL的同步下,依次进行主机发送和从机接收,循环8次,就发送了8位数据,也就是一个字节,另外注意,这里是高位先行,所以第一位是一个字节的最高位B7,然后依次是次高位B6…最后是B0。(串口时序是低位先行,I2C是高位先行) 另外,由于这里有时钟线进行同步,所以如果主机一个字节发送一半,突然进中断,不操作SDA,SCL,那时序就会在中断不断拉长,SDA,SCL电平都暂停变化,传输也暂停,等中断结束后,主机继续回来操作,传输仍然不会出问题,这就是同步时序的好处

2.接收一个字节

  • warning:

    • 注意此处为高位先行与串口不同,串口为低位先行
    • 主机在接收时,必须释放SDA(所有设备默认处于输入模式,当主机发送时可以主动去拉低SDA,主机在被动接收时必须先释放SDA,以免影响别人发送,因为总线是线与的特征,任何一个设备拉低了总线就是低电平,如果你接受时,不是放SDA,拿别人无论发送什么数据都是低电平)
  • 该图的SDA实线部分表示主机控制的电平,虚线为从机控制的部分

接收一个字节和释放一个字节的区别
  • 发送一个字节,SCL低电平主机放数据,高电平从机读数据
  • 接受一个字节,SCL低电平从机放数据,高电平主机读数据

SDA线主机在接受前要释放SDA,从机获得SDA控制权。从机发送0,就将SDA拉低;从机发送1,就将SDA释放,


3.发送应答和接收应答


4.I2C的完整时序

主要有指定地址写,当前地址读和指定地址读这3种。 I2C总线上每个从机都确定一个唯一的设备地址(使用7位标准协议地址),主机在起始条件之后会先发送一个字节确认相应的设备地址,相应的设备响应之后的读写操作,MPU6050地址为1101000

1.指定地址写

本图表示了在指定设备(1101000)在指定地址(0x19)下,写入指定数据(0xAA)

  • 首先,SCL高电平期间,拉低SDA,产生起始条件(start,s),在起始条件后,紧跟着时序,
    • 第一个字节,必须是发送一个字节的时序,字节的内容,必须是从机地址+读写位,正好从机地址是7位,读写位是1位,加起来是1个字节,8位,发送从机地址,就是确定从机的对象。发送读写位,就是确认接下来要写入还是读出。在这里SCL低电平期间,SDA变换数据,高电平期间,从机读取SDA。绿色的线,标明从机得到的数据。然后就是1101000,0表示之后的时序主机要进行写操作,1表示之后的时序主机要进行读出操作,这里是0说明之后要进行写操作。
    • 第二个字节,一般第二个字节可以是寄存器地址或者指令控制字,比如该图表示要操控MPU6050的0x19寄存器
    • 第三个字节,便为要写入的内容

image.png

  • 注意这里的应答位:在这个时刻主机要释放SDA(主机每次接受前都要释放SDA,上面的为主机),但是根据接收应答 的原则,从机要拉低SDA。因此根据线与的原则,SDA总线被拉低

2.当前地址读(不常用,因为不能指定地址)

本图表示了对于指定地址(1101000)在当前地址指针(即为上次调用的函数指定地址写的指定地址下+1=0x1A),读取从机数据(0x0F)

  • 在从机应答后,从这里开始,数据的传输方向就要反过来了,因为主机发出了读的命令,所以之后,主机就不能继续发送了,要把SDA控制权交给从机,主机调用接收一个字节的操作,进行接收操作因此缺少了指定地址这一项

  • 这里的当前地址,指的是指定地址写后的下一个地址

3.指定地址读

指定地址读=指定地址写+当前地址读

前面两段相当于把指针移到想要读的寄存器

  • 指定地址读就是在指定地址写到一半,也即制定了寄存器的地址,但是还没来得及写,就转化为了当前地址读
  • 有两个起始条件

4.IIC硬件介绍(主要考察软件)

image.png

  • 主机,就是拥有主动控制总线的权利。从机,只能在从机允许的情况下,才能控制总线。多主机模型可分为固定多主机和可变多主机

    • 固定多主机就是总线上,有2个或2个以上固定的主机,上面固定为主机,下面是从机,只能是主机对从机进行控制,从机不能控制主机,当2个主机同时控制时,就会产生总线冲突,就要进行总线仲裁,仲裁失败的一方让出总线控制权。
    • 可变多主机,总线上挂载多个设备,总线上没有固定的主机和从机,任何一个设备,都可以在总线空闲时跳出来作为主机,然后指定其他任何一个设备进行通信,通信完成后,跳出来的主机就要退回到从机的位置。对于STM32的I2C,使用的是可变多主机
  • 支持7位/10位地址模式(7位地址只能支持128个设备,地址数量不够时可以通过开辟多条[I2C总线]或者改用10位地址来解决,十位地址的情况下就需要规定起始位后的两个字节都作为寻址为使用,如果想将第二个字节作为寻址使用那就要将第一个字节前五位写入11110来作为标志)

5.IIC外设结构框图

image.png SDA:

  • 数据收发的核心部分:数据寄存器和数据移位寄存器
  • 发送数据时,将数据放在数据寄存器,当没有移位时候,数据从数据寄存器转运到移位寄存器,同时,下一个数据送到数据寄存器,然后移位寄存器将数据给SDA,数据寄存器中的数据给移位寄存器,如此往复 当数据寄存器转到移位寄存器时,就会置状态寄存器的TXE位为1,表示数据寄存器为空
  • 接收数据时,从SDA转到移位寄存器,再转到数据寄存器,同时置标志位RXNE,表示接受寄存器非空,这时候可以把数据从数据寄存器读出来 比较器和地址寄存器时从机模式使用(即再stm32不进行通信的时候,这个stm32支持同时响应两个从机地址)

SCL:

  • 时钟控制:控制SCL线
  • 时钟控制寄存器(CCR):写对应的位,电路就会执行对应的功能
  • 控制逻辑电路:写入控制寄存器(CR1/CR2),就可以对整个电路进行控制
  • 读取状态寄存器,可以得知电路的工作状态
  • 中断:当内部有一些标志位置1后,可能事件比较紧急,就可以申请中断 如果开启中断,当事件发生后,程序可以跳转到中断函数处理事件

6.IIC外设基本结构图

image.png

  • 这个移位寄存器和数据寄存器是核心,因为这是高位先行,所以这个移位寄存器向左先行,在法送时,最高位移出去,一个SCL时钟,是移位一次;移位8次,这就能把一个字节,由高位到低位,依次放到SDA总线上。

  • 接收时,数据从GPIO口,从右边依次移进来,移位8次,最终一个字节就接收完成了。

  • 对于GPIO口都要配置成复用开漏输出模式,复用就是GPIO口的状态,由片上外设控制的;开漏输出,是I2C协议要求配置。

  • SCL这里,时钟控制器通过GPIO去控制时钟线。SDA部分,输出数据,通过GPIO,输出到端口,输入数据,通过GPIO,输入到移位寄存器。

7.IIC外设主机发送

image.png

image.png

  • 7位地址的主发送和10位地址的主发送,区别是,7位地址,起始条件后的一个字节是寻址; 10位地址,起始条件后的两个字节都是寻址,其中前一个字节,帧头:内容是5位的标志位11110+2位地址+1位读写位,后一个字节,是8位地址,两个字节加一起,构成10位寻址。

  • 7位地址的主发送:流程是,起始,从机地址,应答,数据1,应答,数据2,应答,最后P停止。

  • 首先,初始化后,总线默认空闲状态,STM32默认从模式,为了产生一个起始条件,STM32需要写入控制寄存器,之后,STM32由从模式转换为主模式,然后会发生EV5事件,EV5其实相当于检查标志位,SB表示状态寄存器的一个状态,SB置1,表示起始条件已发送,当检测起始地址已发送时,就可以发送一个字节的从机地址,从机地址需要写到数据寄存器DR中,写入DR后,硬件电路会自动把这一字节,转到移位寄存器里,在把这个字节发送到I2C总线上,之后硬件自动接收应答并判读,如没有应答,硬件就会置应答失败的标志位,在寻址完成后,会发生EV6事件,EV6事件结束后,发送EV8事件,然后接收应答,数据2就转入移位寄存器发送,又发生EV8事件,但此时下一个数据,已经被写到寄存器等着了,所以EV8事件消失,之后应答,产生EV8事件,写入数据寄存器,EV8消失。一旦检测到EV8事件,就开始写入下一个数据,最后,当想要发送的数据写完后,这时就没有新的数据写入数据寄存器,当移位寄存器移位完成时,此时就是移位寄存器器空,数据寄存器也空状态,这个事件就是EV8_2,检测到EV8_2时,产生终止条件。

主机接收

image.png

  • 时序流程是,起始,从机地址+读,接收应答,然后接收数据,发送应答,接收数据,发送应答,最后一个数据给非应答,然后终止

  • 首先,写入控制寄存器start位,产生起始条件,然后等待EV5事件,EV5事件代表起始条件已发送,之后是寻址,接收应答,产生EV6事件,EV6事件代表寻址已完成,数据1代表数据正通过移位寄存器进行输入,,EV6_1是没有对应的事件标志,只适用于接收1个字节的情况,这个,EV6_1,是数据1还在移位,数据没有收到,所以事件没有标志位,之后当时序单元完成时,把应答位发送出去,移入的一个字节就整体转移到数据寄存器,同时置RXNE标志位,表数据寄存器费空,收到了一个字节的数据,就是,EV7事件,当把数据读走后,,EV7事件就没了,说明此时数据1被读走,当然数据1还没读走的时候,数据2就可以直接移入移位寄存器,之后,数据2移位完成,收到数据2,产生,EV7事件,读走数据2,,EV7事件没了,按照这个流程,就一直接收数据,最后,当不需要接收时,需要在最后一个时序单元发生时,提前把ACK置0,,并设置终止条件的请求,这就是,EV7_1事件,之后,在时序完成后,设置了ACK=0,这里就给出非应答,由于设置STOP位,产生终止条件。