瑞萨CPU平台的GPIO模拟I2C之一:开始、停止、写数据

      GPIO模拟I2C在不同的平台上有不同的做法。以下是我在瑞萨DVP-C3平台上经过验证的代码。此种实现方式,较为晦涩,不是很好理解,特记录如下。用pvSDA2和pvSCL2表示I2C两根线的GPIO方向控制(ON输出,OFF输入),poSCL2和poSDA2表示I2C两根线的GPIO数据控制(ON置高,OFF置低)。

SI dtv_i2c_start( U8 OutputData )

{
      U8 RoopCt;                 //计数器,用来对操作进行一定的循环,不成功就返回失败
      DTV_IICBusInitial();    //完成I2C的两个GPIO的功能配置

      IntDisableWithPush;  //后面类似的此种语句全都是临界区操作     
      pvSDA2 = OFF;
      pvSCL2 = OFF;   
      IntEnableByPop;        //后面类似的此种语句全都是临界区操作

      for( RoopCt=0; RoopCt<12; RoopCt++ )
     {
             pvSDA2 = OFF;       
             pvSCL2 = OFF;       //如果设置I2C两根线为输入方向,则默认置高


             if((poSDA2 ==ON) && (poSCL2==ON))    //则默认为高的前提下
             {
                    IntDisableWithPush;    //拉 低 SDA 

                    pvSDA2 = ON;
                    poSDA2  = OFF;      
                    IntEnableByPop;

                    BusWait( _15us ); 

 

                    IntDisableWithPush;    //拉 低SCL 

                    pvSCL2 = ON;
                    poSCL2 = OFF;
                    IntEnableByPop; 

                    BusWait( _15us );        //以上行程一个I2C START波形

 

                    return (dtv_i2c_data( OutputData ));  //在start函数中就默认写一个字节

             }
      }
      return (WRONG);                      //如果没有写字节成功,就返回失败
}

 

SI dtv_i2c_data( U8 OutputData )   //写字节要收到应答信号

{
         U8 RoopCt;      //8位计数器
         UI I2cCt;          //应答延时时限

         for( RoopCt=0; RoopCt<8; RoopCt++ )
         {
                IntDisableWithPush;      
                poSCL2 = OFF;       
                pvSCL2 = ON;
                IntEnableByPop;      //SCL拉低,只有SCL为低时SDA才能改变

  

                if((OutputData&0x80)!=0)
                {
                       pvSDA2 = OFF;   /// 1   //SDA输出高,只要把SDA设置成输入方向,即相当于对外部没有控制,即被拉高
                }
                else
                {
                       IntDisableWithPush;    
                       poSDA2  = OFF;
                       pvSDA2 = ON;   //"0"   //SDA输出高
                       IntEnableByPop;
                }

                pvSCL2 = OFF;        //保持SCL为高,形成一个周期

                BusWait( _15us );
                OutputData = OutputData << 1;     //从MSB向LSB次序输出
          }
          IntDisableWithPush;       
          poSCL2 = OFF;        
          pvSCL2 = ON;        

          IntEnableByPop; 

          pvSCL2 = OFF;       //开始一个新周期,配置SCL输入
 
          I2cCt = WAIT_5ms;
          BusWait( _15us  );
          pvSDA2 = OFF;      //SDA不控制

          do
         {
                if( poSCL2 == ON )    //因为SCL已释放,该条件一定成立

                {
                       if(poSDA2 ==OFF)    //SDA为低,才是应答有效
                       {
                              IntDisableWithPush;       
                              poSCL2 = OFF;        
                              pvSCL2 = ON;        
                              IntEnableByPop;    //说明应答有效,该周期完毕
                              return (TRUE);       //ack ok 写字节成功
                        }
                        break;
                 }
                 --I2cCt;
          }while(I2cCt!=0);    //在规定时间内

          pvSCL2 = OFF;        //释放SCL
          return (WRONG);    //写字节失败
}

 

void dtv_i2c_end(void)
{
       IntDisableWithPush;       
       poSCL2 = OFF;        
       pvSCL2 = ON;
       IntEnableByPop;    //SCL拉低

 

       IntDisableWithPush;       
       poSDA2  = OFF;        
       pvSDA2 = ON;        
       IntEnableByPop;    //SDA拉低

 

       BusWait( _15us );
       pvSCL2 = OFF;       //if set as input port ,default high

       BusWait( _25us );
       pvSDA2 = OFF;      //if set as input port ,default high  形成STOP条件
}

你可能感兴趣的:(数据通讯和网络)