I2C总线标准代码

/********

起始信号,SCL=1,时钟总线为高电平,数据总线由高电平变为低电平SDA=1-->SDA=0

void I2C_Start(void)

{

I2C_SCL_HIGH();//SCL=1

I2C_SDA_HIGH();//SDA=1  开始都为高电平,当SDA为低电平为起始信号

I2C_DELAY();

I2C_SDA_LOW();

I2C_DELAY();

I2C_SCL_LOW();

I2C_DELAY();

}

停止信号 SCL=1,SDA=0,时钟总线为高电平,数据总线由低电平变为高电平SDA=0-->SDA=1

void I2C_Stop(void)

{

    I2C_SDA_Low();

    I2C_SCL_High();

    I2C_Delay();

    I2C_SDA_High();

    I2C_Delay();

}

发送一个字节8位

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

    }

} 

 

//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;

}
//CPU产生一个ACK信号
void I2C_Ack(void)

{

    I2C_SDA_Low();

    I2C_Delay();

    I2C_SCL_High();

    I2C_Delay();

    I2C_SCL_Low();

    I2C_Delay();

    I2C_SDA_High();

}
//CPU产生一个非ACK信号
void I2C_NoAck(void)

{

    I2C_SDA_High();
    I2C_Delay();
    I2C_SCL_High();
    I2C_Delay();
    I2C_SCL_Low();
    I2C_Delay();

}
//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写数据由一下10个步骤组成。 
  第一步,发送一个起始信号。 
  第二步,发送7bit从机地址,即OZ9350的地址。此处需要注意,发送数据时,无法发送7bit数据,此处发送了7bit地址+1bit读写选择位,即发送7bit+r/w。最低位为1表示读,为0表示写。 
  第三步,产生一个ACK应答信号,此应答信号为从机器件产生的应答。 
  第四步,发送寄存器地址,8bit数据。 
  第五步,产生一个ACK应答信号,此应答信号为从机器件产生的应答。 
  第六步,发送一个数据,8bit数据。 
  第七步,产生一个ACK应答信号,此应答信号为从机器件产生的应答信号。 
  第八步,发送一个CRC校验码,此CRC校验值为2、4、6步数据产生的校验码。 
  第九步,既可以发送一个应答信号,也可以发送一个无应答信号,均有从机器件产生。 
  第十步,发送一个停止信号。 
  接下来,按照以上十个步骤,可以写出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

}

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

通过分解后的时序图,可以看到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,发送停止信号;

 

你可能感兴趣的:(I2C,读写数据)