IIC通讯协议

一、IIC基本特征

两线通讯:数据线(SDA)和时钟线(SCL)。
IIC可以挂多个设备,有主从机之分(主机访问从机)。IIC总线上的器件都有一个唯一器件地址,主机通过器件地址确定对应从机。
IIC采用半双工通讯,硬件上需要上拉电阻一般是4.7K~10K典型值为4.7K。总线上最大电容400pF限制。
在这里插入图片描述

二、IIC通讯时序

IIC空闲时为高电平。
主机写数据到从机
起始和停止信号在这里插入图片描述
起始信号:SCL为高电平时,SDA从高变低
停止信号:SCL为高电平时,SDA从低变高

void I2C_Start(void)   //起始信号函数
{
 SDA_Out(1);   //SDA输出高
 SCL_Out(1);   //SCL输出高
 delay_us(5);
 SDA_Out(0);   //SDA输出低
 delay_us(5);
 SCL_Out(0);
 delay_us(3);
}
void I2c_Stop(void)   //停止信号函数
{
 SDA_Out(0);    //SDA输出低
 SCL_Out(0);    //SCL输出低
 delay_us(5);
 SCL_Out(1);    //SCL输出高
 delay_us(5);
 SDA_Out(1);
 delay_us(3);
}

数据变化只能在SCl为低电平时进行

 ****主机发送数据到从机****

在这里插入图片描述
阴影部分为主机发送给从机的数据,空白为从机返回的数据。
主机先发送 :起始信号 + 从机地址【高7bit 为地址,最低位为读写bit(0:对从机写操作;1:对从机读操作)】+读ACK(从机发送给主机)+写数据 + 读ACK +…+ 写数据 + 读ACK + 停止信号。
主机发送数据到从机的ACK都是从机发给主机的。
主机接收数据到从机
在这里插入图片描述
阴影部分为主机发送给从机的数据,空白为从机返回的数据。
主机先发送 :起始信号 + 从机地址【高7bit 为地址,最低位为读写bit(0:对从机写操作;1:对从机读操作)】+读ACK(从机发送给主机)+ 读数据 + 写ACK +…+ 读数据 + 写ACK + 停止信号。
ACK总结:ACK都是数据接收器件发给数据发送器件的。

void Ack(void)  //主机读ACK
{ 
    SCL_Out(0);  
    delay_us(2); 
 SDA_Out(1);
 SDA_IN(); 
 delay_us(2);
 SCL_Out(1);
 SDA_Out(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7));  
    delay_us(4);
 SCL_Out(0);
    SDA_OUT();
 delay_us(2);
}
void Nack(uint8_t ack)  //主机写ACK
{
 SCL_Out(0);
 delay_us(2); 
 if(ack == 1)
    SDA_Out(1);
 else
   SDA_Out(0); //写应答信号
  delay_us(2);   
  SCL_Out(1);                    //拉高时钟线
  delay_us(4);                 //延时
  SCL_Out(0);                   //拉低时钟线
  delay_us(2);                 //延时

}

主机发送数据用Ack函数,主机接收数据时用Nack函数且最后一个Nack为高

void I2c_SendByte(uint8_t _ucByte)  //主机发送8bit数据
{
  uint8_t i;
  for (i = 0; i < 8; i++)
 {  
   if (_ucByte & 0x80)
    SDA_Out(1);
  else
    SDA_Out(0); 
 delay_us(2);
  SCL_Out(1);
  delay_us(2);
  _ucByte <<= 1;   //左移一个bit 
  SCL_Out(0);
 }
 SDA_Out(0);
 delay_us(1);
 SCL_Out(0);
 delay_us(1);
}
uint8_t I2c_ReadByte(void)    //主机接收8bit数据
{
  uint8_t i;
  uint8_t value;
  /* 读到第1个bit为数据的bit7 */
 value = 0;
 for (i = 0; i < 8; i++)
 {
  value<<=1;
  SCL_Out(0);
  SDA_IN(); 
  delay_us(2);
  if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7))
   value |= 0x01 ;
  else
   value &= 0xfe;
  SCL_Out(1);
  delay_us(2);
 }
 SCL_Out(0);
 SDA_OUT();
 delay_us(2);
 SDA_Out(0);
 delay_us(2);
 return value;
}
int I2C_Write(uint8_t addr , uint8_t* buff, uint8_t size)  //主机发数据
{
 uint8_t i; 
 I2C_Start();
  I2c_SendByte(addr);
  Ack();
  for(i = 0; i < size; i++)
 {
 I2c_SendByte(buff[i]);
  Ack();
 }
  I2c_Stop(); 
 return 0;
}
int I2C_Read(uint8_t addr , uint8_t* buff, uint8_t size,uint8_t bus_bit) //主机接收数据
{
 uint8_t i,busy; 
 I2C_Start();
  I2c_SendByte(addr+1);
 delay_us(2);
 Ack(); 
  for(i = 0; i< (size-1); i++)
 {
      buff[i] = I2c_ReadByte();
   delay_us(2);
    Nack(0);
  } 
  buff[size-1] = I2c_ReadByte();
 delay_us(2);
  Nack(1);
 delay_us(10);
  I2c_Stop(); 
 return 0;
}
发布了1 篇原创文章 · 获赞 0 · 访问量 16

猜你喜欢

转载自blog.csdn.net/qq_37387733/article/details/104786198