0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

一文彻底搞懂I2C总线

冬至子 来源:阿伟玩电子 作者:Aweil 2023-11-24 10:24 次阅读

01 I2C通信协议简介

I2C通信协议在嵌入式IC中应用的特别广泛,所以今天给大家详细的讲解一下,有解释的不正确或不合理的地方欢迎大家提出意见。

IIC是一种半双工串行同步通信协议,由数据线SDA时钟线SCL构成串行总线,可用于发送和接收数据,通常是由主设备发起,从设备被动响应,实现数据的传输。

02 I2C硬件原理图

图片

SDA: 数据线(双向)
SCL: 时钟线(主机控制)

因为I2C总线接口是开漏输出(见下面的电气特性图),所以SDA和SCL必须接上拉电阻!(一般选用4.7K~10K的电阻)。

I2C总线上可以挂载多个主设备,以及多个从设备,在从机没有收到主机的地址访问信息前从机不会主动向主机发送数据。

03 I2C接口电气特性

图片

图片

04 I2C总线数据传输起始和停止条件

起始条件: 在SCL为高电平期间,SDA产生一个下降沿信号
停止条件: 在SCL为高电平期间,SDA产生一个上升沿信号

图片

模拟I2C起始和停止信号的程序(基于STM32

//程序中的宏定义
#define HIGH  1
#define LOW    0
/* IO方向设置 */
#define SDA_IN()  {GPIOA- >CRH&=0XFFFF0FFF;GPIOA- >CRH|=(uint32_t)8< < 12;}
#define SDA_OUT() {GPIOA- >CRH&=0XFFFF0FFF;GPIOA- >CRH|=(uint32_t)3< < 12;}
/* IO操作 */
#define IIC_SCL(n)  (n?HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_SET):HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_RESET)) //SCL
#define IIC_SDA(n)  (n?HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11,GPIO_PIN_SET):HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11,GPIO_PIN_RESET)) //SDA
#define READ_SDA    HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11)          //输入SDA
//产生IIC起始信号
void IIC_Start(void)
{
  SDA_OUT();//sda线输出
  IIC_SDA(HIGH);        
  IIC_SCL(HIGH);
  delay_us(4);
   IIC_SDA(LOW);//START:when CLK is high,DATA change form High to low 
  delay_us(4);
  IIC_SCL(LOW);//钳住I2C总线,准备发送或接收数据 
}


//产生IIC停止信号
void IIC_Stop(void)
{
  SDA_OUT();//sda线输出
  IIC_SCL(LOW);
  IIC_SDA(LOW);//STOP:when CLK is high DATA change form low to High
   delay_us(4);
  IIC_SCL(HIGH); 
  IIC_SDA(HIGH);//发送I2C总线结束信号
  delay_us(4);                   
}

05 数据传输格式

  1. 在SCL的每个时钟脉冲期间传输 1 个数据位;
  2. 地址由 7 bit 构成,最低位为读写命令,0:写,1:读
  3. SDA数据线上的 1 个字节由 8 个数据位组成,字节可以是设备地址、寄存器地址,也可以是写入或从从机读取的数据;
  4. 首先传输数据的是最高有效位(MSB);
  5. 在启动和停止条件之间,可以将任意数量字节的数据从主设备传输到从设备;
  6. 在时钟周期的高相位期间,SDA线上的数据必须保持稳定,因为SCL高时数据线上的变化被解释为控制命令(启动或停止);

图片

应答信号

Acknowledge (ACK) and Not Acknowledge (NACK);

数据的每个字节(包括地址字节)后面跟着来自接收器的一个ACK位,ACK位允许接收机与发射机进行通信,告知该字节已成功接收,并可发送另一个字节,这其实是I2C总线的一种数据校验方式。

在接收机发送ACK之前,发射机必须释放SDA线路。为了发送ACK位,接收器应在ACK/NACK相关时钟周期(第9个周期)的低相位期间拉低SDA线,以便在ACK/NACK相关时钟周期的高相位期间SDA线稳定在低电平,同时必须考虑设置和保持的时间。

当然,主机也有可能会接收到费应答信号NACK:

图片

接收到非应答信号NACK可能有以下原因:

1.接收器无法接收或发送,因为它正在执行某些实时功能,并且尚未准备好开始与主机通信;

2.在传输过程中,接收器获取其不理解的数据或命令;

3.在传输过程中,接收器无法再接收任何数据字节;

4.主接收器数据已经读取完毕,默认NACK信号的从机发过来的;

等待应答信号和产生应答信号程序:

//主机等待从机应答信号
uint8_t IIC_Wait_Ack(void)
{
  uint8_t ucErrTime=0;
  SDA_IN();//主机SDA设置为读取模式
  IIC_SDA(HIGH);//主机释放SDA信号线
  delay_us(1);
  IIC_SCL(HIGH);
  delay_us(1);
  while(READ_SDA)//等待并读取SDA状态
  {
    ucErrTime++;
    if(ucErrTime >250)//等待超时后结束本次数据传输
    {
      IIC_Stop();
      return 1;
    }
  }
  IIC_SCL(LOW);//时钟输出0      
  return 0;  
} 


//产生ACK应答信号
void IIC_Ack(void)
{
  IIC_SCL(LOW);
  SDA_OUT();
  IIC_SDA(LOW);
  delay_us(2);
  IIC_SCL(HIGH);
  delay_us(2);
  IIC_SCL(LOW);
}


//产生NACK非应答信号        
void IIC_NAck(void)
{
  IIC_SCL(LOW);
  SDA_OUT();
  IIC_SDA(HIGH);
  delay_us(2);
  IIC_SCL(HIGH);
  delay_us(2);
  IIC_SCL(LOW);
}

06 主机通过I2C总线向从机设备写数据

I2C总线按照如下示意图向指定设备指定寄存器发送数据:

图片

I2C总线发送数据的过程

0.主机发送一个起始信号;

1.主机发送从机设备地址,最低位为0,表示写命令,R/W=0;

2.主机等待接收从机的应答信号;

3.主机发送设备寄存器地址;

4.主机等待接收从机的应答信号;

5.主机发送一个字节数据;

6.主机等待接收从机的应答信号;

8.主机接收从机上传的一个字节数据(一般情况下只发送一个字节数据);

9.主机等待接收从机的应答信号;

10.主机继续发送数据,等待从机应答信号,重复步骤8和9;

11.主机发送一个停止信号;

主机模拟I2C发送数据代码实现(基于STM32)

//发送一个字节数据
void IIC_Send_Byte(uint8_t txd)
{                        
    uint8_t t;   
  SDA_OUT();
    IIC_SCL(LOW);
    for(t=0;t< 8;t++)
    {              
        IIC_SDA((txd&0x80) >>7);
        txd< <=1;     
    delay_us(2);                              
    IIC_SCL(HIGH);
    delay_us(2); 
    IIC_SCL(LOW);
    delay_us(2);
    }   
}
//I2C总线向设指定设备指定寄存器写一个字节数据
//devaddr:设备地址
//addr:寄存器地址
//data:待发送数据
void iicDevWriteByte(uint8_t devaddr,uint8_t addr,uint8_t data)
{                                                      
  IIC_Start();//起始信号
  IIC_Send_Byte(devaddr);//发送从机设备地址
  IIC_Wait_Ack();     
  IIC_Send_Byte(addr);//发送寄存器地址
  IIC_Wait_Ack();                                 
  IIC_Send_Byte(data);//发送数据
  IIC_Wait_Ack();               
  IIC_Stop();//停止信号
}


//I2C总线向指定设备指定地址连续写多个字节数据
//devaddr:设备地址
//addr:寄存器地址
//len:发送数据的长度
//wbuf:待发送数据缓存
void iicDevWrite(uint8_t devaddr,uint8_t addr,uint8_t len,uint8_t *wbuf)
{
  int i=0;
  IIC_Start();//起始信号
  IIC_Send_Byte(devaddr);//发送从机设备地址,发送写命令,R/W=0
  IIC_Wait_Ack();  

  IIC_Send_Byte(addr);//寄存器地址
  IIC_Wait_Ack();  

  for(i=0; i< len; i++)
  {
    IIC_Send_Byte(wbuf[i]);  
    IIC_Wait_Ack();//等待ACK信号
  }
  IIC_Stop( );//停止信号
}

07 主机通过I2C总线读取从机发送数据

I2C总线按照如下示意图从指定从机的指定寄存器读取数据:

图片

I2C总线读取数据的过程

0.主机发送一个起始信号;

1.主机发送从机设备地址,最低位为0,表示写命令,R/W=0;

2.主机等待接收从机的应答信号;

3.主机发送设备寄存器地址;

4.主机等待接收从机的应答信号;

5.主机重复发送一个起始信号;

6.主机发送从机设备地址,最低位为1,表示读命令,R/W=1;

7.主机等待接收从机的应答信号;

8.主机接收从机上传的一个字节数据;

9.若主机发送ACK应答信号,继续接收从机数据;若主机发送NACK非应答信号,停止接收数据;

10.主机发送一个停止信号;

主机模拟I2C接收数据代码实现(基于STM32)

//读取一个字节数据
//ack=1时,发送ACK,表示还有数据待继续读取
//ack=0时,发送NACK,表示停止读取数据
uint8_t IIC_Read_Byte(unsigned char ack)
{
  unsigned char i,receive=0;
  SDA_IN();//SDA设置为输入
    for(i=0;i< 8;i++ )
  {
        IIC_SCL(LOW); 
        delay_us(2);
    IIC_SCL(HIGH);
        receive< <=1;
        if(READ_SDA)receive++;   
    delay_us(1); 
    }           
    if (!ack)
        IIC_NAck();//发送nACK
    else
        IIC_Ack();//发送ACK   
    return receive;
}


//从指定设备指定寄存器地址读取一个字节数据
//ReadAddr:开始读数的地址  
//temp:读到的数据
uint8_t iicDevReadByte(uint8_t devaddr,uint8_t addr)
{          
  uint8_t temp=0;                                             
  IIC_Start();//起始信号
  IIC_Send_Byte(devaddr);//发送从机设备地址,发送写命令,R/W=0
  IIC_Wait_Ack(); 

  IIC_Send_Byte(addr);//发送寄存器地址
  IIC_Wait_Ack();  


  IIC_Start();//Repeated START
  IIC_Send_Byte(devaddr|1);//发送从机设备地址,发送读命令,R/W=1
  IIC_Wait_Ack();

  temp=IIC_Read_Byte(0);       
  IIC_Stop();//停止信号
  return temp;
}


//从指定设备指定寄存器地址连续读取多个字节数据
//devaddr:从机设备地址
//addr:寄存器地址
//len:字节总长度
//rbuf:读取数据缓存区
void iicDevRead(uint8_t devaddr,uint8_t addr,uint8_t len,uint8_t *rbuf)
{
  int i=0;
  IIC_Start();//起始信号
  IIC_Send_Byte(devaddr);//发送从机设备地址,发送写命令,R/W=0
  IIC_Wait_Ack();  

  IIC_Send_Byte(addr);//发送寄存器地址
  IIC_Wait_Ack();  


  IIC_Start();//Repeated START
  IIC_Send_Byte(devaddr|1);//发送从机设备地址,发送写命令,R/W=1
  IIC_Wait_Ack();
  for(i=0; i< len; i++)
  {
    if(i==len-1)
    {
      rbuf[i]=IIC_Read_Byte(0);//全部数据接收完毕,主机发送NACK信号,产生停止信号
    }
    else
      rbuf[i]=IIC_Read_Byte(1);//数据未全部接收完,主机发送ACK信号,继续接收数据
  }
  IIC_Stop( );//停止信号
}
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 上拉电阻
    +关注

    关注

    5

    文章

    346

    浏览量

    30259
  • 寄存器
    +关注

    关注

    30

    文章

    5032

    浏览量

    117745
  • I2C总线
    +关注

    关注

    8

    文章

    357

    浏览量

    60409
  • SDA
    SDA
    +关注

    关注

    0

    文章

    122

    浏览量

    27557
  • 开漏输出
    +关注

    关注

    0

    文章

    29

    浏览量

    7256
收藏 人收藏

    评论

    相关推荐

    i2c总线协议pdf

    I2C 总线规范目录1 序言
    发表于 08-13 17:16

    i2c总线规范

    ? 快速模式器件的斜率控制和输入滤波改善了EMC 性能注意100kbit/s 的I2C 总线系统或100kbit/s 器件都没有改变1.2 版本2.0-1998I2C 总线实际上已经成
    发表于 08-13 17:18

    I2C规范,I2C总线原理

    I2C规范,I2C总线原理1 序言
    发表于 04-09 18:34

    I2C总线彩电的检修

    中各智能芯片的总线控制,它是种高效的串行数据传输控制系统。I2C总线是双向二线制,它包含数据线SDA和时钟线SCL。彩电正常工作时各种信号,包括数据信号、同步信号、应答信号、纠错信号
    发表于 09-05 10:56

    I2C总线协议详解

    I2C总线定义 I2C(Inter-Integrated Circuit)总线种由PHILIPS公司开发的两线式串行
    发表于 02-01 09:56

    浅谈I2C总线

    I2C 接口和 SPI 接口的作用相同,但二者的使用方法有些不同。 I2C 总线用两根线来连接多支路总线中的多个设备。这种总线是双向、低
    发表于 11-30 11:50

    I2C总线冲突

    遇到总线冲突。你可能会问,为什么在地址被发送之后设置停止位?我用它作为I2C总线扫描器,我只想知道相应的地址是否有个附加的有源设备,如
    发表于 01-30 13:14

    I2C总线简介

    )和SPI(串行外围设备接口)。你需要先了解I 2 C 的基本特性,然后才能彻底理解这三个接口之间的比较,因此,我们将在本文结尾处讨论该主题。什么是
    发表于 09-06 10:16

    I2C总线是什么

    I2C总线I2C总线(读做“IC”或“I2C
    发表于 07-21 09:03

    I2C总线简介

    的数量,降低了互联成本。总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持40个组件。I2C总线的另个优点是,它支持多主控(multimastering), 其中任何
    发表于 08-20 08:25

    I2C总线的相关资料推荐

    16.1 I2C工作原理16.1.1 I2C串行总线概述I2C总线是PHLIPS公司推出的种双
    发表于 11-29 06:41

    I2C总线概述

    1I2C总线概述1.1I2C总线介绍l2C总线(InterICBus)由PHILIPS公司推出,
    发表于 12-13 06:19

    I2C总线简单介绍

    1.I2C简单介绍I2C(Inter-Integrated Circuit)总线种由PHILIPS公司开发的两线式串行总线,用于连接微控
    发表于 01-14 07:10

    I2C总线的原理是什么

    采用串行总线技术可以大大简化硬件的设计,体积减少,可靠性高。常见的总线I2C(inter IC bus),单总线,SPI总线
    发表于 01-18 07:36

    I2C总线简介

    I2C 简介I2C 是双线双向的串行总线,它为设备之间数据交换提供了种简单高效的方法。I2C 标准是
    发表于 02-22 06:55