2022 04月01日
作者: 阳光
  • 浏览: 219
  • 收藏:0
  • 点赞:1
IIC通讯时序详解

        在刚开始接触单片机的时候,会被板级内的各种通讯接口方式弄的晕头转向。嵌入式系统中常用板级通讯方式有:并口(8位、16位)、SPI(4线、3线)、IIC、USB、TYPE-C等。具体采用什么通讯方式,要根据实际项目情况选择。并口传输速度快,处理数据量大,像处理图形图像优先考虑,硬件成本高;串口传输速度相对比较慢,接线简单,硬件成本低。这里详细介绍下IIC通讯方式的使用。
一、IIC 简介
    IIC(Inter-Integrated Circuit)总线是由NXP(原PHILIPS)公司开发的两线式串行总线,用于连接单片机及其外围设备。多用于主控制器和从器件间的主从通信,适用数据量少,传输距离短场合。在 MCU 与被控 IC 之间、IC 与 IC 之间进行二线制、双向、同步半双工传输。IIC传输速度分为标准100Kbps、快速400Kbps、高速3.4Mbps,目前大多数器件都支持快速传输。IIC总线的传输距离受到布线、速度、总线电容的影响,虽然没有明确规定距离,但是建议不要超过300mm,否则最好加上IIC中继芯片。


二、IIC物理层接线

IIC.jpg 
    从上图可以看出,在IIC物理层有主机(MCU)、从机(IIC器件);2条总线,SCL(时钟线)和SDA(数据线)及上拉电阻(必接4.7K-10K)。
    所有接到I2C总线设备上的串行数据SDA都必须接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。I2C总线上的每个设备都自己一个唯一的地址,来确保不同设备之间访问的准确性。器件的物理地址是器件厂商出厂设定好的,须按照IC手册设定。
    在IIC总线中可以接多个主机,其中任何一个能够进行发送和接收的设备都可以成为主总线。一个主机能够控制信号的传输和时钟频率。当然,在任何时间点上只能有一个主机控制。

---------------------------------------------------------------------------------------------------------------
三、IIC协议层
    IIC 总线在传送数据过程中共有三种类型信号, 它们分别是:启始信号(Start)、终止信号(Stop)和应答信号(Ack)。
启始信号:SCL 为高电平时(1),SDA 由高电平向低电平跳变,表示起始信号,接下来可以进行数据传输,必须有;
终止信号:SCL 为高电平时(1),SDA 由低电平向高电平跳变,表示终止信号,表示结束数据传输,必须有;
应答信号:接收端器件(不论主从)在接收到 8bit 数据后,向发送端器件(不论主从)发出特定的低电平脉冲,表示已收到数据。发送端向接收端发出一个信号后,等待接收端发出一个应答信号,发送端接收到应答信号后,根据实际情况作出是否继续传递数据的判断。若在约定的等待周期内未收到应答信号,判断为接收端接收数据不成功。
非应答信号:若接收端希望结束数据传输,则可以向发送端发一个“非应答信号NAck”,接收端收到此信号后会产生一个终止信号,结束传输。
IIC 总线时序图

IIC总线时序图.jpg

启始信号:SCL高电平(1)状态下,SDA由高(1)变低(0),保持至少4.7us后,产生启始信号;程序表示如下
    void IIC_Start()        
   {
       SDA=1;             //确保SDA线为高电平
       SCL=1;             //确保SCL高电平
       delay_us(5);       //保持5us
       SDA=0;             //在SCL为高时拉低SDA,产生启始信号
       delay_us(5);
   }
终止信号:SCL高电平(1)状态下,SDA由高(0)变低(1),保持至少4.7us后,产生终止信号;程序表示如下
    void IIC_Stop()         
   {
       SDA=0;             //确保SDA线为低电平
       SCL=1;             //确保SCL高电平
       delay_us(5);
       SDA=1;             //在SCL为高时拉高SDA线,产生终止信号
       delay_us(5);     
    }
应答信号:主机SCL拉高,读取从机SDA的电平,为低电平(SDA=0)表示产生应答,为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节,可以继续发送;若为高电平(SDA=1)时,为非应答位(NACK),一般表示接收器接收该字节没有成功,结束发送。如下图

应答信号2.jpg


    每发送一个字节(8个bit)后,在一个字节传输的8个时钟后的第九个时钟期间,接收器接收数据后必须回一个ACK应答信号给发送器,这样才能进行数据传输。程序表示如下:
//主机产生应答信号Ack
void IIC_Ack(void)
{
   SCL=0;                          //先拉低SCL,使得SDA数据可以发生改变
   SDA=0;                          //SAD=0,产生应答信号 
   delay_us(2);
   SCL=1;

   delay_us(5);
   SCL=0;                         //一个SCL时钟等待周期
   delay_us(5);
   SDA=1;                         //释放SDA总线控制权

}
    有时候从机因某种原因不需要对主机应答时,须将SDA置为高电平(1),由主机产生终止信号结束数据传输。程序表示如下:
//主机产生非应答信号NAck
void IIC_NAck(void)
{
   SCL=0;                          //先拉低SCL,使得SDA数据可以发生改变
   SDA=1;                          //SAD=1,产生非应答信号 
   delay_us(2);
   SCL=1;
   delay_us(5);
   SCL=0;
   delay_us(5);
}

    在实际写程序时,我们可以用一个等待应答子程序来判断应答信号,程序如下:
等待接收端的应答信号:应答0,非应答1
u8 IIC_WaitAck (void)
{
    u8 temptime;                  //临时计时器
    SDA=1;                        // 释放SDA线的控制权              
    SCL=1;
    delay_us(5);
    if(SDA_READ==1)               // 如果读回的SDA=1,则为非应答
     {
       temptime++;
       if(temp>250)               //超时,这里250大概数参考
                    {
           IIC_Stop();            //停止传输
           return 1;
                    }
     }
     SCL=0;                      // SCL拉低
     delay_us(5);     
     return 0;                   //如果读回的SDA=0,则为应答
}

------------------------------------------------------------------------------------------------------------- 

三、IIC数据有效性规定和传输格式

    IIC信号在数据传输过程中,当SCL=1高电平时,数据线SDA必须保持稳定状态,不允许有电平跳变,只有在时钟线上的信号为低电平期间(SCL=0),数据线上的高电平或低电平状态才允许变化。简而言之,SCL=1时, 数据线SDA的任何电平变换会看做是总线的起始信号或者停止信号,只有SCL=0时,才允许SDA数据进行电平转换。如下图所示

IIC数据有效性.jpg

    在IIC数据传输过程中,输出到SDA线上的每个字节必须是8位,数据传送时,高位(MSB)在前,低位(LSB)在后,每次发送的字节数量不受限制,但是每一个被传送的字节后面都必须跟随一位应答位(即一帧共有9位)。当一个字节按数据位从高位到低位的顺序传输完后,紧接着从设备将拉低SDA=0,回传给主设备一个应答位ACK, 此时才认为一个字节真正的被传输完成 ;如果一段时间内没有收到从机的应答信号(SDA=1),则认为该数据接收不成功。如下图

IIC数据传输2.jpg

  



主机写数据过程如下:
1.主机首先产生START信号;
2.然后紧跟着发送一个从机地址,这个地址共有7位,紧接着的第8位是数据方向位(R/W),  0表示主机发送数据(写),1表示主机接收数据(读);
3.主机发送地址时,总线上的每个从机都将这7位地址码与自己的地址进行比较,若相同,则认为自己正在被主机寻址,将自己确定为发送器和接收器;
4.这时候主机等待从机的应答信号(A)
4.1当主机收到应答信号时,发送要访问从机的那个地址, 继续等待从机的应答信号;
4.2当主机收到应答信号时,发送N个字节的数据,继续等待从机的N次应答信号;
4.3主机产生停止信号,结束传送过程。


主机发送数据程序表示如下:
//写入一个字节
void Send_Byte(u8 dat)
{
 u8 i;
    SCL=0;                   //拉低时钟,开始传输数据
 for(i=0;i<8;i++)
 {
  if(dat&0x80)              //将dat的8位从最高位依次写入
  {
   SDA=1;                  //传送1
    }
  else
  {
   SDA=0;                 //传送0


  }
  delay_us(5);            //这里延时可选2-10us,根据实际情况确定,不要省略
  SCL=1;                  //SCL=1,保持SDA不变
  delay_us(5);           
  SCL=0;                  //SCL=0,允许SDA跳变
        delay_us(5);      //表示一个SCL时钟周期传送1位数据
  dat<<=1;                //下一位数据
  }
}
IIC主机发送一个字节程顺序如下(以AT24C02为例)
void IIC_ WR_Byte(u8 dat,u8 mode)
{
 IIC_Start();                //启动信号
 Send_Byte(0xA0);           //RW=0表示主机写入,发送从机地址要根据实际器件确定
 IIC_WaitAck();              //等待应答
 Send_Byte(address);         //发送要写入的字节地址(此处与0XA0不同)
 Send_Byte(dat);             //发送数据
 delay_us(2);
    IIC_WaitAck();            //等待应答,若是非应答则结束发送数据
 IIC_Stop();                 //完成发送
}

--------------------------------------------------------------------------------------------------------------

主机读(接收)数据过程如下:
1.主机首先产生START信号;
2.然后紧跟着发送一个从机地址,注意此时该地址的第8位为RW=0,表明是向从机写命令;
3.这时候主机等待从机的应答信号(ACK);
4.当主机收到应答信号后,发送要访问的从机地址,继续等待从机的应答信号;
5.当主机收到应答信号后,主机要改变通信模式(主机由发送变为接收,从机由接收变为发送);
5.1主机重新发送一个开始start信号;
5.2然后紧跟着发送一个从机地址,注意此时该地址的第8位为RW=1,表明将主机设置成接收模式开始读取数据;
5.3主机等待从机的应答信号,当主机收到应答信号时,就可以接收1个字节的数据,当接收完成后,主机发送非应答信号,表示不在接收数据;
6.主机进而产生停止信号,结束传送过程。程序表示如下:


//IIC主机接收一个字节
void IIC_Read_Byte(u8 ack)
{
 u8 i=0,receive=0;
    IIC_SDA_IN();                  //SDA设为输入
    for(i=0;i<8;i++)
 {
       SCL=0; delay_us(2);          //允许数据转换
       SCL=1; delay_us(2);          //读数据
       receive<<=1;                 //读下一位
       if(Read_Sda==1) receive++;



  delay_us(2);
}
if(!ack)  IIC_NAck();                             //发送非应答
else    IIC_Ack();                              //发送应答
return  receive;
}
  }


   以读取EEPROM AT24C02为例,读取程序如下(仅参考):
u8 IIC_READ_AT24C02(u16 addr)
{
  u8 temp=0;
  IIC_Start();                       //发首次启始信号
  Send_Byte(0xA0);                 //发送地址,D0=0表示写入
  IIC_WaitAck();                    //等待应答
  Send_Byte(data);                 //发送数据(24C02数据低位地址)
  IIC_WaitAck();
  IIC_Start();                       //再次发启始信号
  Send_Byte(0xA1);                 //发送地址,D0=1表示读入数据,与上面相反
  IIC_WaitAck();
  temp= IIC_Read_Byte(0);          //应答
  IIC_Stop();                      //结束
  return temp;
}

------------------------------------------------------------------------------------------------------------
四、IIC寻址
    前面有说到,启始信号后必跟从机地址,那么从机地址如何确定?在IIC总线上,每个器件都有自己固定的地址,这地址是IC在出厂时就已经设定好的,使用者只能按照手册进行配置。还是以AT24C02为例说明。AT24C02为地址低位D3-D1,可以设为000-111共8个不同地址 ,高4位D7-D4=1010这是厂商固定地址,不能改变;D0位是读写控制位,0表示写,1表示读。如果硬件电路A0-A2这3个脚接地(000),按照前面数据格式规定,那么向AR24C02写入时,发送的地址码为A0(10100000),如果要读回数据则发送的地址码为A1(10100001)。
    还有些IC有发送命令和数据之分,因此在发送地址码后,还要发送控制字标识(D/C)位(通常0表示命令,1表示数据),总之从器件地址和控制字标识要按IC手册设定,否则会出现通讯错误。

五、其它
    IIC协议理论上可以接127个从机(8位地址去掉一个广播位和0x00地址),实际上还受到总线电容的限制,IIC总线电容不能超过400pf,电容增大会导致数据和时钟信号的跳变产生延时畸变,导致通讯不能正常进行。在实际运用中,发送数据后的延时(2-10us)要保留,有时会出现程序都没变,换个场合就异常的情况,这时要重点注意延时是否合适。上拉电阻一定要加上,虽然有时候没有加也能正常运行,但是你不知道什么时候就不正常了。示例是用模拟IIC时序,STM32F103X支持硬件IIC,应用起来比较简单,速度也比模拟的要快,只是IO口就没有模拟的那么灵活,看情况而定。








  

发表评论

评论列表


没有评论

筛选

文章分类

热门文章

投稿及奖励(必看)

2022-11-28  浏览:60630次

企业网址

2022-11-28  浏览:50746次

2021年秋招经历

2022-10-01  浏览:514次

浅谈学习单片机的前景

2022-03-15  浏览:461次

怎样才能学好单片机

2022-03-28  浏览:439次