IIC协议

1.认识IIC

1、IIC协议概述:

  • IIC(Inter-Integrated Circuit,集成电路总线)是一种串行通信协议,也被称为I2C协议。它是由荷兰的PHILIPS公司(现在philips公司将其半导体部门拆分出来并更名为NXP半导体公司)在1982年开发的一种简单、高效的通信协议。
  • IIC协议主要用与连接电路之间进行短距离的数字通信,比如连接微控制器及其外围设备。
  • IIC协议使用两线式串行总线。
  • IIC有点像串口,但是串口是全双工,但是IIC属于半双工同步通信方式,数据传输线只有一根,传输和接收要去占用SDA线。

2、IIC协议特点:

  1. 简单性:IIC协议只使用了两根信号线,并且由于接口直接在组件之上,因此IIC总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本。能够支持40个组件。
  2. IIC协议的通信速率:在一些特定的应用或特定的环境下(比如用于学习),为了提供高通信的稳定确定性和可靠性,某些设备或系统选择将IIC协议的传输速率限制在较低的速率,例如10 Kbps。但它并不代表IIC协议的最大通信速率就是10 Kbps。根据协议版本不同IIC协议的通信速率会有不同,标准模式的IIC协议支持最大传输速率为100 Kbps,快速模式则为 400 Kbps,高速模式则为 3.4 Mbps。
  3. 多主控(multimastering):其中任何能够进行发送和接收的设备都可以成为主控设备,这些主控设备可以是MCU、OLED、手持传感器、陀螺仪等其他I2C接口器件(如下图),这些I2C接口器件都共用这两根串行总线。当然,在任何时间点上只能有一个主控。主控设备负有责任发起和控制通信,它可以向其他设备发送命令、读取数据,并负责协调总线上的通信活动。其他设备被称为从属设备(Slave Device),它们被主控设备控制并响应主控设备的命令。从属设备不能主动发起通信,而正在主控设备的指示下进行相应的操作。因此,虽然任何设备都可以作为IIC协议中的主控设备,但在实际应用中,根据设备的功能和设计,选择合适的设备作为主控设备,其他设备则作为从属设备,以满足通信需求和数据交换的要求
  4. 硬件地址查找:每个从设备在总线上都有唯一一个硬件地址,主设备通过这个地址来选择与之通信的从设备。

3、IIC协议构成:IIC协议是两线式串行总线,两根信号线分别是数据线SDA和时钟线SCL。所有用IIC通讯的设备都需要遵循相同的通讯时序。

  1. SDA(Serial Data Line,数据线):用于传输数据。
  2. SCL(Serial Clock Line)时钟线:用于传输时间信息,时钟信号是由主控器件产生的。

IIC协议_第1张图片

  • 在时间信息的控制下,主设备(如微控制器)可以与多个从设备(如传感器、存储器、显示器等)进行双向通信。
  • 所有接到IIC总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。对于并联在一条总线上的每个IC都有唯一的地址。

4、单片机使用IIC协议的注意点:

  1. 由于51单片机开发板上刚好有硬件串口,也就是有与串口对应的寄存器支持,所以,51单片机的串口通信协议(波特率、数据位、起始位、停止位)是通过配置寄存器来完成的。
  2. 但是51单片机上没有IIC这种硬件设备,所以无法通过配置寄存器来驱动串行通信协议,需要分析I2C接口器件时序后转化为代码,通过I/O口来模拟IIC协议(类似于LCD模块、DHT11模块这些非标协议)。
  3. 接下来,我们以51单片机作为主设备,以OLED屏幕作为从设备,连接方式是直连。当然如果有多个从设备,那么就需要用到面包板,实现如上图中并联的效果。
  4. C语言在调用函数时有一个压栈和弹栈的过程,所以即使你调用的函数什么也没有做,在晶振为11.0592MHz的情况下,也需要耗费5微秒的时间。而单片机中_nop()_就是一个空函数,一个nop的耗时为5微秒。

5、IIC总线的信号类型:IIC总线在传输数据的过程中一共有三种类型信号,分别为:开始信号、结束信号和应答信号。

  • 类似于串口,多机通讯无非要关注:起始位,停止位,数据位,波特率。
  • 那么在IIC协议中,开始信号就相当于设置起始位,结束信号就相当于设置停止位,程序中根据时序图通过延时等方法去控制时间点相当于设置波特率。

6、分析时序图的正确逻辑:回顾DHT11模块的时序分析,我们做的还不好,正确的分析逻辑应该如下。

  1. 对总线上的信号进行分类:因为不同信号的表达方式是不一样的,比如启动信号是置高低电平,响应信号是被拉成高低电平。分类完成后的每部分信号都是总体通讯时序图中的一部分。
  2. 在每种信号时序上标注字母:每种信号时序图上可能有多个数据线,所以标注的点最好划分的细致一点
  3. 三步骤读时序图:读时序图关注开始、转折、结尾。读的时候进行记录,可以使用“置高/低电平”、“电平被拉高/低”、“从低/高电平转折为高/低电平”、“维持高/低电平”、“延时”、“卡x点,直到数据线变成高/低电平”等字眼帮助判断。
  4. 编写代码:将时序逻辑复制到代码编辑器中,照着时序分析写代码(一个时序分析完之后就进行一次函数封装)。
  • 注意:当时序图中总线多的时候(比如LCD1602的读写时序图中有4根总线),那么就需要先查看引脚说明。

2.IIC协议通讯时序分析1:起始、终止、应答

1、起始信号:

IIC协议_第2张图片

  1. o点:
    1. SCL置高电平
    2. SDA置低电平
  2. a点:
    1. SCL维持高电平
    2. SDA从低电平转折为高电平,时间未知
  3. a—>b:
    1. SCL维持高电平
    2. SDA延时4.7微秒
  4. b—>c:
    1. SCL维持高电平
    2. SDA从高电平转折为低电平,时间未知
  5. c—>d:
    1. SCL延时4微秒
    2. SDA维持低电平
  6. d点:
    1. SCL从高电平转折为低电平,时间未知
    2. SDA维持低电平
  7. void IIC_Start()
    {
        // a点:
        scl = 1;    // SCL置高电平
        sda = 1;    // SDA从低电平转折为高电平,时间未知
        // a—>b:
                    // SCL维持高电平
        _nop_();    // SDA延时4.7微秒
        // b—>c:
                    // SCL维持高电平
        sda = 0;    // SDA从高电平转折为低电平,时间未知
        // c—>d:
        _nop();    // SCL延时4微秒
                    // SDA维持低电平
        // d点:
        scl = 0;    // SCL从高电平转折为低电平,时间未知
                    // SDA维持低电平
    }

2、终止信号:

IIC协议_第3张图片

  1. o点:
    1. SCL置低电平
    2. SDA置低电平
  2. a点:
    1. SCL从低电平转折为高电平,时间未知
    2. SDA维持低电平
  3. a—>b:
    1. SCL维持高电平
    2. SDA延时4微秒
  4. b—>c:
    1. SCL维持高电平
    2. SDA从低电平转折为高电平,时间未知
  5. c—>d:
    1. SCL维持低高电平
    2. SDA延时4.7微秒
  6. d点:
    1. SCL维持高电平
    2. SDA从高电平转折为低电平,时间未知
  7. void IIC_Stop()
    {
        // a点:
        scl = 1;    // SCL从低电平转折为高电平,时间未知
        sda = 0;    // SDA置低电平
        // a—>b:
                    // SCL维持高电平
        _nop_();    // SDA延时4微秒
        // b—>c:
                    // SCL维持高电平
        sda = 1;    // SDA从低电平折为高电平,时间未知
        // c—>d:
                    // SCL维持低高电平
        _nop_();    // SDA延时4.7微秒
        // d点:
                    // SCL维持高电平
        sda = 0;    // SDA从高电平转折为低电平,时间未知
    }

3、应答信号ACK:应答信号的时序图如下图所示,由于SDA是被读量,所以只在SCL数据线上划分点。

IIC协议_第4张图片

  • 目的:IIC的设计是当SDA和SCL总线上连接有上拉电阻(电平被拉高)时,实际上是不走数据的,也就是释放数据线。在从设备收到完整的一个字节(8位)之后,就主动去拉低SDA总线上的电平,代表接收器成功地接收了该字节。
  • 响应形式:
    • 应答信号为低电平时,规定为有效应答位(ACK,Acknowledgement Character,简称应答位),表示接收器已经成功地接收了该字节;
    • 应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
  1. o点:
    1. SCL置低电平
    2. SDA:在主控设备发送完成一个字节数据后,就立马发送一个高电平,代表释放SDA数据线
  2. o—>a:
    1. SCL延时
  3. a点:
    1. SCL从低电平转折为高电平,代表释放SCL数据线
  4. a—>b:
    1. SCL延时4微秒,因为读取SDA的时候一定要保证SCL处于高电平的状态
    2. SDA被读
    3. SCL延时4微秒,因为读取SDA的时候一定要保证SCL处于高电平的状态
  5. b点:
    1. SCL从高电平转折为低电平
  6. b—>c:
    1. SCL延时
  • 实际上我们不是很关心ACK函数,只有在后面显示出问题了,比如说显示乱码了才会去调用这个函数进行判断。
    void IIC_ACK()
    {
        char flag;
        // o点:
                    // SCL置低电平
        sda = 1;    // SDA:在主控设备发送完成一个字节数据后,就立马发送一个高电平,代表释放SDA数据线
        // o—>a:
        _nop_();    // SCL延时
        // a点:
        scl = 1;    // SCL从低电平转折为高电平,代表释放SCL数据线
        // a—>b:
        _nop_();    // SCL延时4微秒,因为读取SDA的时候一定要保证SCL处于高电平的状态
        flag = sda; // SDA被读
        _nop_();    // SCL延时4微秒,因为读取SDA的时候一定要保证SCL处于高电平的状态
        // b点:
        scl = 0;    // SCL从高电平转折为低电平
        // b—>c:
        _nop_();    // SCL延时
        return flag;
    }

3.IIC协议通讯时序分析2:数据发送

1、回顾串口和LCD的数据发送:

  • 在学习串口的时候,我们不去关心数据的发送需要根据数据发送时序图写什么代码,只需要往SBUF里面传输数据就可以了,这是因为单片机上有对应的寄存器硬件;IIC协议_第5张图片
  • 在学习LCD1602的时候,我们也不去关心数据的发送需要根据写操作时序图写什么代码,只需要往单片机的P0这个I/O口组(和LCD的DB0~DB7相连)里面传输数据就可以了,这也是因为有硬件。IIC协议_第6张图片
  • 二者相同点:数据传输伴随着一个脉冲信号。
    • 串口发送数据时,脉冲信号由串行移位寄存器SHIFT提供:
      • SHIFT为低电平时进行一位数据的发送;
      • SHIFT由低变高(上升沿)代表发送结束;
      • SHIFT为高电平时允许数据翻转;
      • SHIFT由高变低(下降沿)代表开始发送下一位数据。
    • LCD发送数据时,脉冲信号由使能引脚E提供:
      • 在E由低变高(上升沿)之前就开始发送一字节数据;
      • 一字节数据发送完毕之后E由高变低(下降沿)。

 

 

2、IIC数据发送的时序:

IIC协议_第7张图片

  1. 与起始/终止信号的区别:IIC在进行数据发送的时候,需要注意:IIC协议_第8张图片
    1. 在SCL为高电平时,允许SDA上进行一位数据的传输,期间不允许数据的翻转;
    2. 在SCL为低电平时,允许数据的翻转。
    3. 如果在SCL为高电平时出现了SDA上数据的翻转,那么IIC接收器会误以为这是起始信号或终止信号。所以每次SDA上进行数据翻转前都要保证SCL处于低电平。
  2. 时序逻辑
    1. o点:
      1. SCL置低电平:允许数据翻转
      2. SDA发送1bit数据
    2. o—>a:
      1. SCL延时5微秒
      2. SDA正在发送数据
    3. a点:
      1. SCL从低电平转折为高电平
    4. a—>b:
      1. SCL延时5微秒
      2. SDA正在发送数据
    5. b点:
      1. SCL从高电平转折为低电平:为下一次数据翻转做准备
    6. b—>c:
      1. SCL延时5微秒

 

3、IIC协议发送一个字节数据:

  1. 编程逻辑:我们用字符型变量cdata来保存8bit的待发数据。
    1. cdata从哪里来?答:函数传递。
    2. 怎么往SDA线上发1个字节?答:将cdata的每一bit依次传输给sda,共传输8次。
  2. 前提:基于SDA总线数据传输时高位先出的原则。不同的数据传输方法对应不同的读取方式。
  3. 方法:不同于串口的数据位是低位在先,IIC的数据位是高位在先。根据高位先出的原则,每次从SDA发送出去的都是字符型变量cdata的最高位。
    1. 让cdata位与上二进制数1000 0000,即十六进制的0x80(按位运算):这是取位技巧,将取到的最高位结果发送给SDA。
    2. 传输完1bit后让cdata进行左移1位(移位运算):剔除cdata的最高位。IIC协议_第9张图片

     

  4. void IIC_Send_Byte(char cdata)
    {
        int i;
        for(i=0; i<8; i++){
            // o点:
            scl = 0;            // SCL置低电平:允许数据翻转
            sda = cdata & 0x80; // SDA发送1bit数据
            // o—>a:
            _nop_();            // SCL延时5微秒
                                // SDA正在发送数据
            // a点:
            scl = 1;            // SCL从低电平转折为高电平
            // a—>b:
            _nop_();            // SCL延时5微秒
                                // SDA正在发送数据
            // b点:
            scl = 0;            // SCL从高电平转折为低电平:为下一次数据翻转做准备
            // b—>c:
            _nop_();            // SCL延时5微秒
            cdata = cdata << 1;
        }
    }

你可能感兴趣的:(单片机)