I2C协议---I2C时序图解析

一、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)数据

uint8 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
}

四、结语

写:MCU在数据总线上的数据稳定之后,检测边沿信号(上升沿)写数据到器件;

读:MCU发出边沿信号(下降沿)告诉器件发送数据,检测到边沿信号之后,器件改变(更新)数据,等待稳定之后MCU读取数据

 

数据的写操作:图中演示了I2C连续写数据,两个字节的连续写入,更多字节同样

数据的读操作:在上图中,可以认为写入了设备地址及寄存器地址,再次重启总线后,发送读命令,连续读取两个字节,发送NACK,发送停止信号;

全文转自:https://blog.csdn.net/weixin_42229404/article/details/815144517

引用\[1\]:硬件IIC通信是通过硬件电路实现的,而软件IIC通信是通过软件模拟实现的。在硬件IIC通信中,主机和从机之间的通信是由硬件电路自动完成的,而在软件IIC通信中,主机需要通过编程来模拟硬件电路的功能,实现通信的过程。 软件IIC通信的实现主要包括以下几个步骤: 1. 初始化:首先,需要对主机的GPIO引脚进行配置,将其设置为输出模式和输入模式,分别对应SCL和SDA线。同时,还需要设置时钟频率和通信速率等参数。 2. 起始信号:主机发送起始信号,即将SCL线保持高电平的同时,将SDA线从高电平拉低,表示通信的开始。 3. 地址发送:主机发送从机的地址,通过将地址和读写位组合成一个字节,发送到SDA线上。从机通过检测地址位来判断是否是自己需要响应的通信。 4. 数据传输:主机发送数据时,将数据按位发送到SDA线上,然后通过拉高和拉低SCL线来进行时钟同步。从机在接收到数据后,进行相应的处理。 5. 停止信号:主机发送停止信号,即将SCL线保持高电平的同时,将SDA线从低电平拉高,表示通信的结束。 通过以上步骤,主机可以模拟硬件IIC通信的过程,实现软件IIC通信。需要注意的是,软件IIC通信的实现需要考虑时序的控制和数据的传输,因此相对于硬件IIC通信来说,软件IIC通信的编程复杂度较高。 总结起来,硬件IIC通信是通过硬件电路实现的,而软件IIC通信是通过编程模拟硬件电路的功能实现的。在软件IIC通信中,主机需要通过编程来控制GPIO引脚的状态和时序,以实现通信的过程。 #### 引用[.reference_title] - *1* *2* *3* [STM32硬件IIC驱动设计](https://blog.csdn.net/summers_wind/article/details/74139822)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浮华蒲公英

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值