IIC多主从,双向传输,只有两根线:一根数据,一根时钟,时钟必须由主机发出控制。初始化时主机把SCL和SDA的电平都拉高,然后在SCL保持高电平时SDA拉低形成一个开始信号,紧接着开始信号就开始发送要通信的7位从机地址(从机地址一般由芯片内置+电阻设置两部分组成一般为7位),然后再接着传一位读(1)写(0)标识,与7位从机地址共同组成八位,然后等待从机返回应答(从机收到自己的地址后在第九个时钟周期把SDA拉低作为应答),然后主机再发送1个字节数据,等待一位应答,再发送,再应答,直到发完,然后主机拉低SDA拉高SCL并在拉高SCL后再拉高SDA开成一个结束信号,至此一个相对完整的IIC通信过程结束。应答与非应答信号,应答是由从机发给主机的,非应答信号是主机发给从机的,信号来源不一样。应答与非应答的时钟都由主机提供,都在第九个时钟周期出现。非应答信号作用在主机接收完了一个字节数据后,不再接收数据时就发送一个非应答信号,然后再发送一个停止信号。

I2C总线在传送数据过程中共有三种类型信号, 它们分别是:开始信号、结束信号和应答信号。
  开始信号:SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
  结束信号:SCL为低电平时,SDA由低电平向高电平跳变,结束传送数据。
  应答信号:接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。若未收到应答信号,由判断为受控单元出现故障。

    

    

 

  总线必须由主器件(通常为微控制器)控制,主器件产生串行时钟(SCL)控制总线的传输方向,并产生起始和停止条件。SDA线上的数据状态仅在SCL为低电平的期间才能改变,SCL为高电平的期间,SDA状态的改变被用来表示起始和停止条件。

 

程序示例://##################################################################################

//开始传输函数
void Start_I2C()
{
    SDA=1;
    delay(1);
    SCL=1;
    delay(5);       //保证周期大于4.7us
    SDA=0;
    delay(5);       //保证周期大于4us
    SCL=0;          //钳住I2C总线准备发送数据
    delay(3);
}

//结束传输函数
void Stop_I2C()
{
    SDA=0;
    delay(1);
    SCL=1;
    delay(5);
    SDA=1;
    delay(5);      //保证周期大于4us
}

//发送一个字节数据的函数
void SendByte(uchar cSend)
{
    uchar BitCnt;
    
    for(BitCnt=0; BitCnt<8; BitCnt++) //传送的数据长度为8位,循环一次发送一位数据
    {
        if( (cSend<<BitCnt) & 0x80 )
        {
            SDA=1;
        }
        else
        {
            SDA=0;
        }
        
        delay(1);
        SCL=1;                 //设置时钟线为高,通知从机开始接收数据
        Delay(5);             //保证周期大于4us
        SCL=0;
    }
    
    delay(2);
    SDA=1;                       //发送完8位数据后释放数据线,准备接收应答位
    delay(2);
    SCL=1;
    delay(3);
    
    if(SDA==1)
    {
        ack=0;
    }
    else
    {
        ack=1;                   //判断是否接收到应答
    }
    
    SCL=0;                      //钳住I2C总线
    delay(2);

}


//接收一个字节数据的函数
uchar RcvByte()
{
    uchar cReceive;
    uchar BitCnt;
    
    cReceive=0;
    SDA=1;                       //数据线为输入方式
    
    for(BitCnt=0; BitCnt<8; BitCnt++)
    {
        delay(1);
        SCL=0;                 //准备接收数据
        delay(5);              //保证周期大于4.7us
        SCL=1;                 //时钟线为高,此时数据有效
        delay(2);
        cReceive=cReceive<<1;      //把上一位接收到的数据向高位移一位
        if(SDA==1)
        {
            cReceive=cReceive+1;   //把接收到的数据放入cReceive中
        }
    }
    
    SCL=0;                     //钳住I2C总线
    delay(2);
    
    return(cReceive);
}

//发送应答信号函数
void Ack_I2C(bit a)
{
    if(a==0)
    {
        SDA=0;              //此处发出应答信号
    }
    else
    {
        SDA=1;
    }
    
    delay(3);
    SCL=1;
    delay(5);                  //保证周期大于4us
    SCL=0;                     //清时钟线,钳住I2C总线
    delay(2);
      
}

//向无子地址器件写字节数据函数
bit ISendByte(uchar sla, uchar *c)
{
    Start_I2C();           //启动I2C总线
    SendByte(sla);      //发送从机地址,后面的“+1”表示读
    
    if(ack==0)
    {
        return 0;        //从机无响应,则返回0
    }
    
    SendByte(*c);         //写入数据
    if(ack==0)
    {
        return 0;        //从机无响应,则返回0
    }    
    
    Stop_I2C();            //结束总线
    return(1);             //成功返回1 
}


//向无子地址器件读字节数据函数
bit IRcvByte(uchar sla, uchar *c)
{
    Start_I2C();          //启动I2C总线
    SendByte(sla+1);    //发送从机地址,后面的“+1”表示读
    
    if(ack==0)
    {
        return 0;        //从机无响应,则返回0
    }
    
    *c= RcvByte();        //读取数据
    Ack_I2C(1);           //发送非应答
    Stop_I2C();           //结束总线
    return(1);            //成功返回1 
}