浅谈I2c原理

i2c接口连接微控制器和串行i2c总线。支持多主和多从之间通信的协议,主设备通常叫做master,从设备叫做slaver,支持两种不同的通信速度,标准为速度(最高位100kHZ),快速(最高为400kHZ).
通信原理:
浅谈I2c原理_第1张图片
i2c接口与数据总线之间有两个引脚线,一个是SDA线,一个是SCL线。
起始条件后,紧跟从设备的地址,高七位是地址,后一位代表read/write,每传送完一个字节,相应的从设备要发送ACK和NACK来应答,ACK代表低电平,NACK代表高电平。下面我们就要GPIO来模拟i2c的通信。

void gpio_i2c_start(void)
{
  SDA_MODE_OUT;

  SCL_LOW; 
  delay_us(5);  
  SDA_HIGH;
  delay_us(10); 
  SCL_HIGH;  
  delay_us(10);

  SDA_LOW;
  delay_us(10); 
  }
  以上是发送开始信号,当scl高电平时,sda由高电平向低电平转化,表示开始条件,开始传送数据,在传送过程中scl一直都是低电平,sda才能稳定地采集数据,总线一直处于一直忙状态。
  然后开始写数据

uint8_t gpio_i2c_write_byte(uint8_t byte)
{
  int             i;
  uint8_t         rv = I2C_ACK;

  SDA_MODE_OUT;
  /* SCL为低电平时,SDA线才能改变传输的bit; SCL为高电平时,SDA线保持稳定 */
  for(i=7; i>=0; i--) /* MSB */
  {
    /*MSB: 输出相应位的电平信号 */
    if( byte&(1<<i) )
      SDA_HIGH;
    else
      SDA_LOW;
    delay_us(2);

    SCL_HIGH;
    delay_us(5);    

    SCL_LOW;
    delay_us(5);
  }

  rv = gpio_i2c_wait_ack();
  return rv;
}
uint8_t gpio_i2c_wait_ack(void)
{
  uint8_t    rv;
  uint8_t    times = 200;  

  SDA_MODE_IN;

  /* 时钟线拉高 */
  SCL_HIGH;
  delay_us(5);  

  do
  {
    times --;
  } while ( (SDA_DAT==1) && (times!=0) );

  if( !times )
  {
    /* 等待 ACK 超时,接收到NAK */
    rv = I2C_NAK;
    goto OUT;
  }

  /* 等到ACK */
  SCL_LOW;
  delay_us(5);

  rv = I2C_ACK;

OUT:  
  return rv;
}

然后发送停止信号:

void gpio_i2c_stop(void)
{
  SDA_MODE_OUT;    

  SCL_LOW;
  delay_us(5); 
  SDA_LOW;
  delay_us(10); 

  SCL_HIGH;
  delay_us(10);

  SDA_HIGH;
  delay_us(10);
}

假如我们要发送一个buf,首先发送地址:

int gpio_i2c_write(uint8_t addr, uint8_t *buf, int len)
{
  int       i;
  int       rv = I2C_OK;  

  gpio_i2c_start();

  /*低位为0表示写数据*/
  if( I2C_ACK != gpio_i2c_write_byte( (addr)|I2C_DIR_WRITE ) )
  {
    rv = I2C_ERROR;
    goto OUT;  
  }

  for (i=0; i<len; i++)  
  {
    if( I2C_ACK != gpio_i2c_write_byte(buf[i]) )
    {
      rv = I2C_ERROR;
      break;
    }
  }

OUT:  
  gpio_i2c_stop();
  return rv;  
}

你可能感兴趣的:(浅谈I2c原理)