1. 程式人生 > >微控制器GPIO軟體模擬I2C通訊程式

微控制器GPIO軟體模擬I2C通訊程式

文章原始地址:http://feotech.com/?p=98

本程式主要用於使用可程式設計晶片自身的IO管腳,模擬I2C通訊的協議,實現I2C匯流排資料的傳輸.

/**
  ******************************************************************************
  * @file    Virtual_I2C.C 
  * @author  Ryan Zhao
  * @version V1.0.0
  * @date    2017-04-20
  * @brief   軟體I/O模擬I2C匯流排通訊.
  ******************************************************************************
  * @attention   Null
  * 
  ******************************************************************************
  */


/**
* @brief  I2C引腳初始化.
* @param  None.
* @retval None.
*/
void I2C_Init(void)
{                        
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );//使能GPIOB時鐘
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推輓輸出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
  GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); //PB6,PB7 輸出高
}

/**
* @brief  產生I2C開始訊號.
* @param  None.
* @retval None.
*/
void I2C_Start(void)
{
  SDA_OUT();     //SDA引腳設定為輸出模式
  I2C_SDA_H;     //SDA引腳設定為高電平      
  I2C_SCL_H;    //SCL引腳設定為高電平    
  Delay();  //軟體延時
  I2C_SDA_L;
  Delay();  //軟體延時
  I2C_SCL_L;    //準備傳送或接收資料 
}     

/**
* @brief  產生I2C停止訊號.
* @param  None.
* @retval None.
*/
void I2C_Stop(void)
{
  SDA_OUT();//SDA引腳設定為輸出模式
  I2C_SCL_l;
  I2C_SDA_l;
  Delay();      //軟體延時
  I2C_SCL_H; 
  I2C_SDA_H;
  Delay();              
}


/**
* @brief  等待ACK訊號.
* @param  None.
* @retval 1:接收應答成功;
          0:接收應答失敗;
*/
unsigned char I2C_Wait_Ack(void)
{
  unsigned char ucErrTime=0;
  SDA_IN();      //SDA引腳設定為輸入模式 
  I2C_SDA_H;
  Delay();         
  I2C_SCL_H;
  Delay();       
  while(READ_SDA)//讀取SDA引腳電平狀態
  {
    ucErrTime++;
    if(ucErrTime>250)
    {
      I2C_Stop();
      return 0; //接收應答失敗
    }
  }
  I2C_SCL_L;  
  return 1;     //接收應答成功
} 

/**
* @brief  產生ACK訊號.
* @param  None.
* @retval None.
*/
void I2C_Ack(void)
{
  I2C_SCL_L;
  SDA_OUT();    //SDA引腳設定為輸出模式
  I2C_SDA_L;
  Delay();  
  I2C_SCL_H;
  Delay();  
  I2C_SCL_L;
}


/**
* @brief  不產生ACK訊號.
* @param  None.
* @retval None.
*/          
void I2C_NAck(void)
{
  I2C_SCL_L;
  SDA_OUT();
  I2C_SDA_H;
  Delay();
  I2C_SCL_H;
  Delay();
  I2C_SCL_L;
}                           

/**
* @brief  I2C傳送一個位元組.
* @param  None.
* @retval None.
*/    
void I2C_Send_Byte(unsigned char txd)
{                        
  unsigned char i;   
  SDA_OUT();        
  I2C_SCL_L;
  for(i=0;i<8;i++)
  {              
    if((txd&0x80)>>7)
    {
      I2C_SDA_H;
    }
    else
    {
      I2C_SDA_L;
    }
    txd = txd<<1;     
    Delay();
    I2C_SCL_H;
    Delay();
    I2C_SCL_L;  
    Delay();
  }  
}       



/**
* @brief  I2C讀取一個位元組.
* @param  None.
* @retval 讀取到的資料
*/  
unsigned char I2C_Read_Byte(unsigned char ack)
{
  unsigned char i,receive=0;
  SDA_IN();//SDA設定為輸入

  for(i=0;i<8;i++ )
  {
    I2C_SCL=0; 
    Delay();
    I2C_SCL=1;
    receive<<=1;
    if(READ_SDA)
    {
      receive++;   
    }
    Delay();
  }                  
  if (!ack)
  {
    I2C_NAck();//傳送nACK
  }
  else
  {
    I2C_Ack(); //傳送ACK   
  }
    return receive;
}