单片机GPIO软件模拟I2C通讯程序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SheepTech/article/details/82696989

文章原始地址: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;
}

猜你喜欢

转载自blog.csdn.net/SheepTech/article/details/82696989