I2C总线及单片机模拟I2C总线通信程序编写

来源:互联网 发布:日本推理小说 知乎 编辑:程序博客网 时间:2024/05/05 19:46

1、I2C总线

        I2C总线是Inter-IntegratedCircuit(集成电路总线),这种总线类型是由飞利浦半导体公司在八十年代初设计出来的,主要是用来连接整体电路(ICS) ,IIC是一种多向控制总线,也就是说多个芯片可以连接到同一总线结构下,同时每个芯片都可以作为实时数据传输的控制源。

        I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。


2、数据有效性、起始和终止信号

        数据位的有效性:I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。


        起始信号:SCL线为高电平期间,SDA线由高电平向低电平的变化;

        终止信号:SCL线为高电平期间,SDA线由低电平向高电平的变化。

        起始信号和终止信号都由主机发出。


3、数据传送格式     

      1)字节传送与应答

       每一个字节必须保证是8位长度。数据传送时,先传送最高位(MSB),每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。如果一段时间内没有收到从机的应答信号,则自动认为从机已正确接收到数据。


       2)数据帧格式    

        I2C总线上传送的数据信号是广义的,既包括地址信号,又包括真正的数据信号。

        在起始信号后必须传送一个从机的地址(7位),第8位是数据的传送方向位(R/T),用“0”表示主机发送数据(T),“1”表示主机接收数据(R)。

        每次数据传送总是由主机产生的终止信号结束。

        若主机希望继续占用总线进行新的数据传送,则可以不产生终止信号,马上再次发出起始信号对另一从机进行寻址。 

  在总线的一次数据传送过程中,可以有以下几种组合方式:

  a、主机向从机发送数据,数据传送方向在整个传送过程中不变:


  注:有阴影部分表示数据由主机向从机传送,无阴影部分则表示数据由从机向主机传送。

    A表示应答, A非表示非应答(高电平)。S表示起始信号,P表示终止信号。

  b、主机在第一个字节后,立即从从机读数据


  c、在传送过程中,当需要改变传送方向时,起始信号和从机地址都被重复产生一次,但两次读/写方向位正好反相。



4、单片机模拟I2C总线通信程序

1)起始信号

Void I2CStart(void){                                SDA = 1;SomeNop(  );SCL = 1;SomeNop(  );SDA = 0;SomeNop(  );//自己定义的子函数,延时大于4us;}

2)终止信号

void I2cStop(void){SDA = 0;SomeNop(  );SCL = 1;SomeNop(  );SDA = 1;SomeNop(  );}
3)写一个字节操作

bit I2CWrite(unsigned char dat)              //I2C总线写操作,待写入字节dat,返回值为应答状态{    bit ack;                              //用于暂存应答位的值    unsigned char mask;                  //用于探测字节内某一位值的掩码变量         for (mask=0x80; mask!=0; mask>>=1)  //从高位到低位依次进行    {        if ((mask&dat) == 0)          //该位的值输出到SDA上            I2C_SDA = 0;        else            I2C_SDA = 1;              I2CDelay();             I2C_SCL = 1;          //拉高SCL                  I2CDelay();                I2C_SCL = 0;         //再拉低SCL,完成一个位周期    }                  I2C_SDA = 1;            //8位数据发送完后,主机释放SDA,以检测从机应答                I2CDelay();                 I2C_SCL = 1;           //拉高SCL                ack = I2C_SDA;             //读取此时的SDA值,即为从机的应答值                I2CDelay();                I2C_SCL = 0;              //再拉低SCL完成应答位,并保持住总线                  return (~ack);            //应答值取反以符合通常的逻辑:0=不存在或忙或写入失败,1=存在且空闲或写入成功}
4)读一个字节操作

unsigned char I2CReadACK()                 //I2C总线读操作,并发送应答信号,返回值为读到的字节{    unsigned char mask;    unsigned char dat;          I2C_SDA = 1;                           //首先确保主机释放SDA    for (mask=0x80; mask!=0; mask>>=1)       //从高位到低位依次进行    {        I2CDelay();        I2C_SCL = 1;                 //拉高SCL        if(I2C_SDA == 0)                 //读取SDA的值              dat &= ~mask;                  //为0时,dat中对应位清零              else            dat |= mask;                //为1时,dat中对应位置1        I2CDelay();        I2C_SCL = 0;                  //再拉低SCL,以使从机发送出下一位    }            I2C_SDA = 0;                   //8位数据发送完后,拉低SDA,发送应答信号            I2CDelay();            I2C_SCL = 1;                    //拉高SCL             I2CDelay();             I2C_SCL = 0;                   //再拉低SCL完成应答位,并保持住总线                 return dat;}




0 0
原创粉丝点击