C51IO口模拟I2C总线驱动AT24C16 (I2C协议部分)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/plm199513100/article/details/79710837

/*
名称:C51IO口模拟I2C总线驱动EEPROM(AT24C16)

说明:I2C总线是由Philips公司开发的一种简单、半双工同步串行总线。它只需要两根线(SCL、SDA)即可在连接于总线上的器件之间传送信息。其中SCL时钟总线用于同步数据,SDA数据总线用来发送数据(或地址)。

和SPI总线不同的是,I2C总线通过在SDL上发送存储器的地址用来选中总线上对应的设备。关于具体的通信协议这里就不说了,无非是通过IO口模拟产生所需信号
(如通信开始信号是SCL为高时,SDA产生一个下降沿信号。) 驱动程序中有 具体的说明。
*/


//定义I2C相关变量
sbit     SCL=P2^1;     //I2C  时钟 
sbit     SDA=P2^0;     //I2C  数据 

bit ack;                 /*应答标志位*/


static void Delay_I2C() /*延时函数*/
{
    _Nop();
    _Nop();
    _Nop();
    _Nop();
    _Nop();
}


//启动I2C总线,即发送I2C起始条件:SCL为高电平期间,SDA出现下降沿
void Start_I2C()
{
    SDA = 1;
    Delay_I2C();            //延时一段时间
    SCL = 1;
    Delay_I2C();
    SDA = 0;
    Delay_I2C();

    SCL = 0;                //???           /*钳住I2C总线,准备发送或接收数据 */
    Delay_I2C();        


}

//停止I2C总线信号,即发送I2C停止条件:SCL为高电平期间,SDA出现上升沿
void Stop_I2C()
{
    SDA = 0;
    Delay_I2C();            //延时一段时间
    SCL = 1;
    Delay_I2C();
    SDA = 1;
    Delay_I2C();
}


//检验应答信号
bit CheckAck(void)
{
        bit val;
        /*发送完一个字节后检验设备的应答信号*/
        SDA=1;
        SCL=1;
        Delay_I2C();
        val=SDA;
        Delay_I2C();
        SCL=0;
        Delay_I2C();

        return val;
}


//通过I2C总线发送一个字节
bit  SendByte_I2C(unsigned char  c)
{
    unsigned char i = 0;

    SCL = 0;                //???           /*钳住I2C总线,准备发送或接收数据 */
    Delay_I2C();        

    for(i = 0;i<8;++i)
    {
        if(c<<i & 0x80)
            SDA = 1;
        else
            SDA = 0;

            SCL = 1;    /*置时钟线为高,通知被控器开始接收数据位*/
            Delay_I2C();    
            SCL = 0;
            Delay_I2C();            //???

    }

    return CheckAck();      //返回接收方的确认结果
}


//从I2C总线中接收一个字节的数据
unsigned char RecByte_I2C()
{
    unsigned char  retc;
  unsigned char  BitCnt;

  retc=0; 
  SDA=1;                       /*释放总线*/
  for(BitCnt=0;BitCnt<8;BitCnt++)
    {

        SCL=0;                  /*置时钟线为低,准备接收数据位*/
        Delay_I2C();
        SCL=1;                  /*置时钟线为高使数据线上数据有效*/
        Delay_I2C();
        retc=retc<<1;
        if(SDA==1)retc=retc+1;  /*读数据位,接收的数据位放入retc中 */
        Delay_I2C(); 
    }
        SCL=0;    
        Delay_I2C();
        return(retc);
}


//发送应答信号
void Ack_I2C(bit ack)
{
    if(ack==0)
        SDA=0;              /*在此发出应答或非应答信号 */
  else
        SDA=1;
  Delay_I2C();     
  SCL=1;
  Delay_I2C();
  SCL=0;                     /*清时钟线,钳住I2C总线以便继续接收*/
  Delay_I2C(); 
}

猜你喜欢

转载自blog.csdn.net/plm199513100/article/details/79710837
I2C