博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
I2C通信时序图解析
阅读量:6279 次
发布时间:2019-06-22

本文共 4500 字,大约阅读时间需要 15 分钟。

一、I2C协议简介

  I2C 通讯协议(Inter-Integrated Circuit)是由 Phiilps 公司开发的,由于它引脚少,硬件实现简单,可扩展性强,不需要 USART、CAN 等通讯协议的外部收发设备,现在被广泛地 使用在系统内多个集成电路(IC)间的通讯。 

  关于I2C协议的更多内容,可阅读《I2C总线协议》,本博文主要分析I2C波形图,对于I2C的基础知识不在做介绍。

二、I2C协议标准代码

2.1 起始信号&停止信号

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

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

2.1.1 起始信号代码

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();}

2.1.2 停止信号代码

void I2C_Stop(void){    I2C_SDA_Low();    I2C_SCL_High();    I2C_Delay();    I2C_SDA_High();    I2C_Delay();}

2.2 发送一个字节

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

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();    }} 

2.3 读取一个字节

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

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();        I2C_Delay();    }    return value;}

2.4 应答

2.4.1 CPU产生一个ACK信号

void I2C_Ack(void){    I2C_SDA_Low();    I2C_Delay();    I2C_SCL_High();    I2C_Delay();    I2C_SCL_Low();    I2C_Delay();    I2C_SDA_High();}

2.4.2 CPU产生一个非ACK信号

void I2C_NoAck(void){    I2C_SDA_High();    I2C_Delay();    I2C_SCL_High();    I2C_Delay();    I2C_SCL_Low();    I2C_Delay();}

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

uint8_t I2C_WaitToAck(void){    uint8_t redata;    I2C_SDA_High();    I2C_Delay();    I2C_SCL_High();    I2C_Delay();    if(I2C_SDA_READ())    {        redata = 1;    }    else    {        redata = 0;    }    I2C_SCL_Low();    I2C_Delay();    return redata;}   

三、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写数据的函数。代码如下:

u8 I2C_WriteBytes(void){    I2C_Start();                    //1    I2C_SendByte(Slaver_Addr | 0);  //2    I2C_WaitToAck();                //3    I2C_SendByte(Reg_Addr);         //4    I2C_WaitToAck();                //5    I2C_SendByte(data);             //6    I2C_WaitToAck();                //7    I2C_SendByte(crc);              //8    I2C_WaitToAck();                //9    I2C_Stop();                     //10}

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读数据代码。如下所示:

u8 I2C_ReadBytes(void){    u8 data;    u8 crc;    I2C_Start();                    //1    I2C_SendByte(Slaver_Addr | 0);  //2    I2C_WaitToAck();                //3    I2C_SendByte(Reg_Addr);         //4    I2C_WaitToAck();                //5    I2C_Start();                   //6    I2C_SendByte(Slaver_Addr | 1);  //7 1-读    I2C_WaitToAck();                //8    data=I2C_ReadByte();            //9    I2C_Ack();                      //10    crc=I2C_ReadByte();             //11    I2C_NoAck();                    //12    I2C_Stop();                     //13}

四、结语

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

转载于:https://www.cnblogs.com/Tangledice/p/7622794.html

你可能感兴趣的文章
Windows PowerShell2.0之使用PowerTab加强Tab键自动补全
查看>>
ASA8.4的Inside区域同时访问DMZ公网地址和真实地址测试
查看>>
组织机构管理里只有“内部组织”会出现在即时通讯的目录树里(可供C#.NET源码下载学习)...
查看>>
如何实现安全web服务
查看>>
结构化编程的三重境界:见山还是山:朴素又正确的逻辑
查看>>
IGRP中的RTP、Neighbor Discovery协议及Time总结
查看>>
Silverlight C# 游戏开发:Flyer09扇动翅膀的蝴蝶
查看>>
Linux超级杯:7步让你换个新内核
查看>>
Memcached实战之单机部署----单实例/多实例
查看>>
搭建NTP时间服务器
查看>>
城域网国干BGP路由宣告
查看>>
thrift的使用—servlet服务器端与as3客户端通信
查看>>
Spring集成ActiveMQ
查看>>
理解 Keystone 核心概念 - 每天5分钟玩转 OpenStack(18)
查看>>
NP系列三十六--利用ODR实现公司总部和分支机构的通讯
查看>>
遭遇ARP欺骗
查看>>
【移动开发】Android中一些你可能不太知道的东西
查看>>
MongoDB mapReduce案例分析一
查看>>
asp.net 关于提示“当前上下文中不存在名称"XXX"”的一种情况的解决办法
查看>>
MOSS系列二 创建第一个SharePoint站点
查看>>