//--------------------------------------------------------------------------*
// 文件名: IIC.c                                                            *
// 说  明: IIC总线通信函数源文件                                            *
//--------------------------------------------------------------------------*

  //头文件                       
  #include "IIC.h"                         

  //------------------------------------------------------------------------*
  //函数名: IICInit                                                         *
  //功  能: 对I2C模块进行初始化,默认为允许I2C,I2C总线频率:227KHz,禁止I2C中  *
  //        断,从机接收模式,不发送应答信号                                  *
  //参  数: 无                                                              *
  //返  回: 无                                                              *
  //说  明: 无                                                              *
  //------------------------------------------------------------------------*
  void IICInit(void)
  {
      I2C_IIC1F = 0b01001100; //IIC总线频率:227KHz,SDA保持时间:0.55us
      //            ||||||||
      //            ||++++++-ICR     -- 时钟速率 
      //            ++-------MULT    -- 增频因子,2分频
      I2C_IIC1A = 0b11110000; //D7-D1位是MCU作为从机时的地址,最低位不使用
      //            ||||||||
      //            |||||||+-不用
      //            ++++++++-ADR7-ADR1    -- MCU作为从机时的从机地址
      I2C_IIC1C =0b10001000;
      //           ||||||||
      //           ||||||++-不用
      //           |||||+---RSTA    -- 不产生重新开始信号
      //           ||||+----TXAK    -- 不发送应答信号
      //           |||+-----TX      -- 接收模式
      //           ||+------MST     -- 从机模式
      //           |+-------IICIE   -- 禁止I2C中断请求
      //           +--------IICEN   -- 允许I2C
  }

  //-------------------------------------------------------------------------*
  //函数名: SendSignal                                                       *
  //功  能: 根据需要产生开始或停止信号                                       *
  //参  数: Signal = 'S'(Start),产生开始信号;Signal = 'O'(Over),             *
  //        产生停止信号                                                     *
  //返  回: 无                                                               *
  //说  明: 无                                                               *
  //-------------------------------------------------------------------------*
  void SendSignal(uint8 Signal)
  {
      if (Signal == 'S') 
         I2C_IIC1C |= 1<< MSTBit; //主机模式选择位MST由0变为1,可以产生开始信号
      else if (Signal == 'O')
         I2C_IIC1C &= ~(1<< MSTBit);//主机模式选择位MST由1变为0,可以产生停止信号
  }

  //-------------------------------------------------------------------------*
  //函数名: Wait                                                             *
  //功  能: 在时限内,循环检测接收应答标志位,或传送完成标志位,判断MCU         *
  //        是否接收到应答信号或一个字节是否已在总线上传送完毕               *
  //参  数: x = 'A'(Ack),等待应答;x = 'T'(Transmission),等待一个字节         *
  //        数据传输完成                                                     *
  //返  回: 0:收到应答信号或一个字节传送完毕;1:未收到应答信号或一个          *
  //        字节没传送完                                                     *
  //说  明: 无                                                               *
  //-------------------------------------------------------------------------*
  uint8 Wait(uint8 x)
  {
      uint8 ErrTime, i;
      ErrTime = 255;           //定义查询超时时限
      for (i = 0;i < ErrTime;i++)
      {
          if (x == 'A')        //等待应答信号
          {
              if ((I2C_IIC1S & (1 << RXAKBit)) == 0)    
                  return 0;    //传送完一个字节后,收到了从机的应答信号
          }
          else if (x == 'T')   //等待传送完成一个字节信号
          {
              if ((I2C_IIC1S & (1 << IICIFBit)) != 0)    
              {
                  I2C_IIC1S |= (1 << IICIFBit);  //清IICIF标志位
                  return 0;    //成功发送完一个字节
              }       
          }
      }
      if (i >= ErrTime)
          return 1;            //超时,没有收到应答信号或发送完一个字节
  }

  //-------------------------------------------------------------------------*
  //函数名: IICread1                                                         *
  //功  能: 从从机读1个字节数据                                              *
  //参  数: (1) DeviceAddr:设备地址                                          *
  //        (2) AccessAddr:访问地址                                          *
  //        (3) Data:带回收到的一个字节数据                                  *
  //返  回: 为0,成功读一个字节;为1,读一个字节失败                            *
  //说  明: 内部调用 SendSignal,Wait                                         *                 
  //-------------------------------------------------------------------------*
  uint8 IICread1(uint8 DeviceAddr, uint8 AccessAddr, uint8 *Data)
  {      
      I2C_IIC1C |= 1 << TXBit;      //TX = 1,MCU设置为发送模式  
      SendSignal('S');              //发送开始信号    
      I2C_IIC1D = DeviceAddr & 0xFE;//发送设备地址,并通知从机接收数据    
      if (Wait('T'))                //等待一个字节数据传送完成        
          return 1;                 //没有传送成功,读一个字节失败    
      if (Wait('A'))                //等待从机应答信号        
          return 1;                 //没有等到应答信号,读一个字节失败    
      I2C_IIC1D = AccessAddr;       //发送访问地址    
      if (Wait('T'))                //等待一个字节数据传送完成    
          return 1;                 //没有传送成功,读一个字节失败
      if (Wait('A'))                //等待从机应答信号    
          return 1;                 //没有等到应答信号,读一个字节失败       
      I2C_IIC1C |= 1 << RSTABit;    //主机模式下,RSTA位置1,产生重复开始信号    
      I2C_IIC1D = DeviceAddr | 0x01;//通知从机改为发送数据    
      if (Wait('T'))                //等待一个字节数据传送完成    
          return 1;                 //没有传送成功,读一个字节失败    
      if (Wait('A'))                //等待从机应答信号   
          return 1;                 //没有等到应答信号,读一个字节失败    
      I2C_IIC1C &= ~(1 << TXBit );  //TX = 0,MCU设置为接收模式    
      *Data = I2C_IIC1D;            //读出IIC1D,准备接收数据    
      if (Wait('T'))                //等待一个字节数据传送完成        
          return 1;                 //没有传送成功,读一个字节失败    
      SendSignal('O');              //发送停止信号    
      *Data = I2C_IIC1D;            //读出接收到的一个数据    
      return 0;                     //正确接收到一个字节数据
  }

  //-------------------------------------------------------------------------*
  //函数名: IICwrite1                                                        *
  //功  能: 向从机写1个字节数据                                              *
  //参  数: (1) DeviceAddr:设备地址                                          *
  //        (2) AccessAddr:访问地址                                          *
  //        (3) Data:要发给从机的1个字节数据                                 *
  //返  回: 为0,成功写一个字节;为1,写一个字节失败                            *
  //说  明: 内部调用SendSignal,Wait                                          *                   
  //-------------------------------------------------------------------------*
  uint8 IICwrite1(uint8 DeviceAddr, uint8 AccessAddr, uint8 Data)
  {
      I2C_IIC1C |= 1 << TXBit;      //TX = 1,MCU设置为发送模式 
      SendSignal('S');              //发送开始信号
      I2C_IIC1D = DeviceAddr & 0xFE;//发送设备地址,并通知从机接收数据
      if (Wait('T'))                //等待一个字节数据传送完成
          return 1;                 //没有传送成功,写一个字节失败
      if (Wait('A'))                //等待从机应答信号
          return 1;                 //没有等到应答信号,写一个字节失败   
      I2C_IIC1D = AccessAddr;       //发送访问地址
      if (Wait('T'))                //等待一个字节数据传送完成
          return 1;                 //没有传送成功,写一个字节失败
      if (Wait('A'))                //等待从机应答信号
          return 1;                 //没有等到应答信号,写一个字节失败   
      I2C_IIC1D = Data;             //写数据
      if (Wait('T'))                //等待一个字节数据传送完成
          return 1;                 //没有传送成功,写一个字节失败
      if (Wait('A'))                //等待从机应答信号
          return 1;                 //没有等到应答信号,写一个字节失败   
      SendSignal('O');              //发送停止信号
      return 0;
  }

  //-------------------------------------------------------------------------*
  //函数名: IICreadN                                                         *
  //功  能: 从从机读N个字节数据                                              *
  //参  数: (1) DeviceAddr:设备地址                                          *
  //        (2) AccessAddr:访问地址                                          *
  //        (3) Data:读出数据的缓冲区                                        *
  //        (4) N:从从机读的字节个数                                         *
  //返  回: 为0,成功读N个字节;为1,读N个字节失败                              *
  //说  明: 内部调用IICread1                                                 *
  //-------------------------------------------------------------------------*
  uint8 IICreadN(uint8 DeviceAddr, uint8 AccessAddr, uint8 Data[], uint8 N)
  {
      uint8 i, j;
      for (i = 0;i < N;i++)
      {
          for(j = 0;j < 15;j++); //最小延时(发送的每个字节之间要有时间间隔)
          if (IICread1(DeviceAddr, AccessAddr + i, &Data[i]))  
              return 1;          //其中一个字节没有接收到,返回失败标志:1
      }
      if (i >= N)
          return 0;              //成功接收N个数据,返回成功标志:0
  }

  //-------------------------------------------------------------------------*
  //函数名: IICwriteN                                                        *
  //功  能: 向从机写N个字节数据                                              *
  //参  数: (1) DeviceAddr:设备地址                                          *
  //        (2) AccessAddr:访问地址                                          *
  //        (3) Data:要写入的数据                                            *
  //        (4) N:写入数据个数                                               *
  //返  回: 为0,成功写N个字节;为1,写N个字节失败                              *
  //说  明: 内部调用IICwrite1                                                *   
  //-------------------------------------------------------------------------*
  uint8 IICwriteN(uint8 DeviceAddr, uint8 AccessAddr, uint8 Data[], uint8 N)
  {
      uint8 i, j;
      for (i = 0;i < N;i++)
      {
          for(j = 0;j < 15;j++); //最小延时(发送的每个字节之间要有时间间隔)
          if (IICwrite1(DeviceAddr, AccessAddr + i, Data[i]))
              return 1;          //其中一个字节没有发送出去,返回失败标志:1
      }
      if (i >= N)
          return 0;              //成功发送N个数据,返回成功标志:0
  }



