zoukankan      html  css  js  c++  java
  • I2C通信时序图解析

    一、I2C协议简介

      I2C 通讯协议(Inter-Integrated Circuit)是由 Phiilps 公司开发的,由于它引脚少,硬件实现简单,可扩展性强,不需要 USART、CAN 等通讯协议的外部收发设备,现在被广泛地 使用在系统内多个集成电路(IC)间的通讯。 
      关于I2C协议的更多内容,可阅读《I2C总线协议》,本博文主要分析I2C波形图,对于I2C的基础知识不在做介绍。

    二、I2C协议标准代码

    2.1 起始信号&停止信号

      起始信号:当 SCL 线是高电平时 SDA 线从高电平向低电平切换。 
      停止信号:当 SCL 线是高电平时 SDA 线由低电平向高电平切换。

    2.1.1 起始信号代码

     1 void I2C_Start(void)
     2 {
     3     I2C_SDA_High();     //SDA=1
     4     I2C_SCL_High();     //SCL=1
     5     I2C_Delay();
     6     I2C_SDA_Low();
     7     I2C_Delay();
     8     I2C_SCL_Low();
     9     I2C_Delay();
    10 }

    2.1.2 停止信号代码

    1 void I2C_Stop(void)
    2 {
    3     I2C_SDA_Low();
    4     I2C_SCL_High();
    5     I2C_Delay();
    6     I2C_SDA_High();
    7     I2C_Delay();
    8 }

    2.2 发送一个字节

      CPU向I2C总线设备发送一个字节(8bit)数据

     1 u8 I2C_SendByte(uint8_t Byte)
     2 {
     3     uint8_t i;
     4  
     5     /* 先发送高位字节 */
     6     for(i = 0 ; i < 8 ; i++)
     7     {
     8         if(Byte & 0x80)
     9         {
    10             I2C_SDA_High();
    11         }
    12         else
    13         {
    14             I2C_SDA_Low();
    15         }
    16         I2C_Delay();
    17         I2C_SCL_High();
    18         I2C_Delay();
    19         I2C_SCL_Low();
    20         I2C_Delay();
    21  
    22         if(i == 7)
    23         {
    24             I2C_SDA_High();                     /* 释放SDA总线 */
    25         }
    26         Byte <<= 1;                             /* 左移一位  */
    27  
    28         I2C_Delay();
    29     }
    30 } 

    2.3 读取一个字节

      CPU从I2C总线设备上读取一个字节(8bit数据)

     1 u8 I2C_ReadByte(void)
     2 {
     3     uint8_t i;
     4     uint8_t value;
     5  
     6     /* 先读取最高位即bit7 */
     7     value = 0;
     8     for(i = 0 ; i < 8 ; i++)
     9     {
    10         value <<= 1;
    11         I2C_SCL_High();
    12         I2C_Delay();
    13         if(I2C_SDA_READ())
    14         {
    15             value++;
    16         }
    17         I2C_SCL_Low();
    18         I2C_Delay();
    19     }
    20  
    21     return value;
    22 }

    2.4 应答

    2.4.1 CPU产生一个ACK信号

     1 void I2C_Ack(void)
     2 {
     3     I2C_SDA_Low();
     4     I2C_Delay();
     5     I2C_SCL_High();
     6     I2C_Delay();
     7     I2C_SCL_Low();
     8     I2C_Delay();
     9  
    10     I2C_SDA_High();
    11 }

    2.4.2 CPU产生一个非ACK信号

    1 void I2C_NoAck(void)
    2 {
    3     I2C_SDA_High();
    4     I2C_Delay();
    5     I2C_SCL_High();
    6     I2C_Delay();
    7     I2C_SCL_Low();
    8     I2C_Delay();
    9 }

    2.4.3 CPU产生一个时钟,并读取器件的ACK应答信号

     1 uint8_t I2C_WaitToAck(void)
     2 {
     3     uint8_t redata;
     4  
     5     I2C_SDA_High();
     6     I2C_Delay();
     7     I2C_SCL_High();
     8     I2C_Delay();
     9  
    10     if(I2C_SDA_READ())
    11     {
    12         redata = 1;
    13     }
    14     else
    15     {
    16         redata = 0;
    17     }
    18     I2C_SCL_Low();
    19     I2C_Delay();
    20  
    21     return redata;
    22 }   

    三、I2C通信时序图解析

      有了上边的I2C总线标准代码的基础,下面我们进入本博文所要讲解的内容,怎么分析I2C的时序图,以O2Micro的OZ9350为例,OZ9350是一款模拟前端(AFE)的IC器件。是一款性价比不错的电源管理芯片,由于其通讯是通过I2C来进行通讯的,所以这里用OZ9350的I2C通讯做例子进行讲解。

    3.1 写数据

      首先我们先来看一下写数据的时序图,如下图所示: 
      将上图中的写数据时序图进行分解,经分解后如下图所示: 

      结合I2C总线协议的知识,我们可以知道OZ9350的I2C写数据由一下10个步骤组成。 
      第一步,发送一个起始信号。 
      第二步,发送7bit从机地址,即OZ9350的地址。此处需要注意,发送数据时,无法发送7bit数据,此处发送了7bit地址+1bit读写选择位,即发送7bit+r/w。最低位为1表示读,为0表示写。 
      第三步,产生一个ACK应答信号,此应答信号为从机器件产生的应答。 
      第四步,发送寄存器地址,8bit数据。 
      第五步,产生一个ACK应答信号,此应答信号为从机器件产生的应答。 
      第六步,发送一个数据,8bit数据。 
      第七步,产生一个ACK应答信号,此应答信号为从机器件产生的应答信号。 
      第八步,发送一个CRC校验码,此CRC校验值为2、4、6步数据产生的校验码。 
      第九步,既可以发送一个应答信号,也可以发送一个无应答信号,均有从机器件产生。 
      第十步,发送一个停止信号。 
      接下来,按照以上是个步骤,可以写出OZ9350的i2c写数据的函数。代码如下:

     1 u8 I2C_WriteBytes(void)
     2 {
     3     I2C_Start();                    //1
     4  
     5     I2C_SendByte(Slaver_Addr | 0);  //2
     6     I2C_WaitToAck();                //3
     7  
     8     I2C_SendByte(Reg_Addr);         //4
     9     I2C_WaitToAck();                //5
    10  
    11     I2C_SendByte(data);             //6
    12     I2C_WaitToAck();                //7
    13  
    14     I2C_SendByte(crc);              //8
    15     I2C_WaitToAck();                //9
    16  
    17     I2C_Stop();                     //10
    18 }

    3.2 读数据

      读数据的时序图如下图所示: 

      读数据的时序图经分解后如下图所示: 

      通过分解后的时序图,可以看到OZ9350的读数据由以下13个步骤组成。 
      第一步,发送一个起始信号。 
      第二步,发送7bit从机地址,即OZ9350的地址。此处需要注意,发送数据时,无法发送7bit数据,此处发送了7bit地址+1bit读写选择位,即发送7bit+r/w。最低位为1表示读,为0表示写。 
      第三步,产生一个ACK应答信号,此应答信号为从机器件产生的应答。 
      第四步,发送寄存器地址。 
      第五步,产生一个ACK应答信号,此应答信号为从机器件产生的应答。 
      第六步,再次发送一个骑士信号。 
      第七步,发送7bit从机地址,即OZ9350的地址。此处需要注意,发送数据时,无法发送7bit数据,此处发送了7bit地址+1bit读写选择位,即发送7bit+r/w。最低位为1表示读,为0表示写。 
      第八步,产生一个ACK应答信号,此应答信号为从机器件产生的应答。 
      第九步,读取一个字节(8bit)的数据。 
      第十步,产生一个ACK应答信号,此应答信号为CPU产生。 
      第十一步,读取一个CRC校验码。 
      第十二步,产生一个NACK信号。此无应答信号由CPU产生。 
      第十三步,产生一个停止信号。 
      接下来,由以上分析步骤,可以写出OZ9350的I2C读数据代码。如下所示:

     1 u8 I2C_ReadBytes(void)
     2 {
     3     u8 data;
     4     u8 crc;
     5  
     6     I2C_Start();                    //1
     7  
     8     I2C_SendByte(Slaver_Addr | 0);  //2
     9     I2C_WaitToAck();                //3
    10  
    11     I2C_SendByte(Reg_Addr);         //4
    12     I2C_WaitToAck();                //5
    13  
    14     I2C_Start();                   //6
    15  
    16     I2C_SendByte(Slaver_Addr | 1);  //7 1-读
    17     I2C_WaitToAck();                //8
    18  
    19     data=I2C_ReadByte();            //9
    20  
    21     I2C_Ack();                      //10
    22  
    23     crc=I2C_ReadByte();             //11
    24  
    25     I2C_NoAck();                    //12
    26  
    27     I2C_Stop();                     //13
    28 }

    四、结语

      关于怎样分析I2C通信的时序图,在理解原理的基础上还需要自己多动手练习,只有这样才能熟练掌握。如果在博文中出现错误之处,还望指正。

    岁月蹉跎,怠慢了整个人生!
  • 相关阅读:
    mybatis(八)手写简易版mybatis
    mybaits(七)spring整合mybaits
    Java学习之String StringBuffer StringBuilder区别
    Java学习之基本概念
    java多态
    HashMap变成线程安全方法
    java高级开发工程师面试题
    同步和异步
    Oracle创建索引的原则(转)
    导入maven工程错误
  • 原文地址:https://www.cnblogs.com/zhb123456/p/10627886.html
Copyright © 2011-2022 走看看