I2C协议靠这16张图彻底搞懂(超详细)

article/2025/8/16 23:01:46

文章目录

    • 背景
    • 硬件层
    • 数据传输协议
    • 实际上如何工作?
    • 单个主设备连接多个从机
    • 多个主设备连接多个从机
    • 如何编程?
    • 总结

背景

I²CInter-Integrated Circuit),中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,是由飞利浦公司在1980年代初设计的,方便了主板、嵌入式系统或手机与周边设备组件之间的通讯。由于其简单性,它被广泛用于微控制器与传感器阵列,显示器,IoT设备,EEPROM等之间的通信。

I²C最重要的功能包括:

  • 只需要两条总线;
  • 没有严格的波特率要求,例如使用RS232,主设备生成总线时钟;
  • 所有组件之间都存在简单的主/从关系,连接到总线的每个设备均可通过唯一地址进行软件寻址;
  • I²C是真正的多主设备总线,可提供仲裁和冲突检测;
  • 传输速度;
    • 标准模式:Standard Mode = 100 Kbps
    • 快速模式:Fast Mode = 400 Kbps
    • 高速模式: High speed mode = 3.4 Mbps
    • 超快速模式: Ultra fast mode = 5 Mbps
  • 最大主设备数:无限制;
  • 最大从机数:理论上是127;

以上是I²C的一些重要特点,下面会进一步对I²C进行介绍。

硬件层

I²C协议仅需要一个SDA和SCL引脚。SDA是串行数据线的缩写,而SCL是串行时钟线的缩写。这两条数据线需要接上拉电阻。

设备间的连接如下所示:

使用I²C,可以将多个从机(Slave)连接到单个主设备(Master),并且还可以有多个主设备(Master)控制一个或多个从机(Slave)。

假如希望有多个微控制器(MCU)将数据记录到单个存储卡或将文本显示到单个LCD时,这个功能就非常有用。

I²C总线(SDASCL)内部都使用漏极开路驱动器(开漏驱动),因此SDASCL 可以被拉低为低电平,但是不能被驱动为高电平,所以每条线上都要使用一个上拉电阻,默认情况下将其保持在高电平;

拉电阻的值取决于许多因素。德州仪器TI 建议 使用以下公式来计算正确的上拉电阻值:

R p ( m i n ) = V D D − V O L ( m a x ) I O L R_p(min)=\cfrac{V_{DD}-V_{OL}(max)}{I_{OL}} Rp(min)=IOLVDDVOL(max)

R p ( m i n ) = t r 0.8473 x C b R_p(min)=\cfrac{t_r}{0.8473xC_b} Rp(min)=0.8473xCbtr

其中 V O L V_{ OL} VOL是逻辑低电压;

I O L I_{OL} IOL是逻辑低电流;

t r t_r tr是信号的最大上升时间;

C b C_b Cb是总线(电线)电容;

具体如下所示:

从上表可知,使用I2C设备必须在 3 m A 3mA 3mA的灌电流下工作,

这里不难发现需要在做选型需要满足几个条件;

  • 灌电流 最大值为 3 m A 3mA 3mA
  • 另外I2C总线规范和用户手册还为低电平输出电压 V O L V_{OL} VOL设置了最大值为0.4V

R p ( m i n ) = V C C − 0.4 V 3 m A R_p(min) = \cfrac{VCC - 0.4V}{3mA} Rp(min)=3mAVCC0.4V

所以根据上述公式可以计算,对于5V的电源,每个上拉电阻必须至少具有1.53kΩ,而对于3.3V的电源,每个电阻必须至少具有967Ω。

如果觉得计算电阻值比较麻烦,也可以使用典型值 4.7kΩ

上述推导过程可以参考 TI的文档《I2C Bus Pullup Resistor Calculation》 https://www.ti.com/lit/an/slva689/slva689.pdf

最终在调试的时候,当我们测量SDA或SCL信号并且逻辑LOW上的电压高于0.4V时,我们就知道可以知道灌电流太高了;

当然,这并不意味着每当灌电流超过3mA时,设备就会立即停止工作。但是,在操作超出其规格的设备时,应始终小心,因为它可能导致通信故障,缩短其使用寿命甚至甚至永久损坏设备。

数据传输协议

主设备和从设备进行数据传输时遵循以下协议格式。数据通过一条SDA数据线在主设备和从设备之间传输01的串行数据。串行数据序列的结构可以分为,开始条件,地址位,读写位,应答位,数据位,停止条件,具体如下所示;

开始条件

当主设备决定开始通讯时,需要发送开始信号,需要执行以下动作;

  • 先将SDA线从高压电平切换到低压电平;
  • 然后将SCL从高电平切换到低电平;

在主设备发送开始条件信号之后,所有从机即使处于睡眠模式也将变为活动状态,并等待接收地址位

具体如下图所示;

地址位

通常地址位占7位数据,主设备如果需要向从机发送/接收数据,首先要发送对应从机的地址,然后会匹配总线上挂载的从机的地址;

I2C还支持10位寻址;

读写位

该位指定数据传输的方向;

  • 如果主设备需要将数据发送到从设备,则该位设置为 0
  • 如果主设备需要往从设备接收数据,则将其设置为 1

ACK / NACK

主机每次发送完数据之后会等待从设备的应答信号ACK

  • 在第9个时钟信号,如果从设备发送应答信号ACK,则SDA会被拉低;
  • 若没有应答信号NACK,则SDA会输出为高电平,这过程会引起主设备发生重启或者停止;

数据块

传输的数据总共有8位,由发送方设置,它需要将数据位传输到接收方。

发送之后会紧跟一个ACK / NACK位,如果接收器成功接收到数据,则设置为0。否则,它保持逻辑“ 1”。

重复发送,直到数据完全传输为止。

停止条件

当主设备决定结束通讯时,需要发送开始信号,需要执行以下动作;

  • 先将SDA线从低电压电平切换到高电压电平;
  • 再将SCL线从高电平拉到低电平;

具体如下图所示;

实际上如何工作?

第一步:起始条件

主设备通过将SDA线从高电平切换到低电平,再将SCL线从高电平切换到低电平,来向每个连接的从机发送启动条件 :

第二步:发送从设备地址

主设备向每个从机发送要与之通信的从机的7位或10位地址,以及相应的读/写位

第三步:接收应答

每个从设备将主设备发送的地址与其自己的地址进行比较。如果地址匹配,则从设备通过将SDA线拉低一位以表示返回一个ACK位

如果来自主设备的地址与从机自身的地址不匹配,则从设备将SDA线拉高,表示返回一个NACK位

第四步:收发数据

主设备发送或接收数据到从设备;

第五步:接收应答

在传输完每个数据帧后,接收设备将另一个ACK位返回给发送方,以确认已成功接收到该帧:

第六步:停止通信

为了停止数据传输,主设备将SCL切换为高电平,然后再将SDA切换为高电平,从而向从机发送停止条件;

单个主设备连接多个从机

I2C总线上的主设备使用7位地址对从设备进行寻址,可以使用128( 2 7 2^7 27)个从机地址。

请使用4.7K上拉电阻将SDA和SCL线连接到Vcc;

多个主设备连接多个从机

多个主设备可以连接到一个或多个从机;

当两个主设备试图通过SDA线路同时发送或接收数据时,同一系统中的多个主设备就会出现问题。

为了解决这个问题,每个主设备都需要在发送消息之前检测SDA线是低电平还是高电平

  • 如果SDA线为低电平,则意味着另一个主设备可以控制总线,并且主设备应等待发送消息。

  • 如果SDA线为高电平,则可以安全地发送消息。

    要将多个主设备连接到多个从机,请使用下图,其中4.7K上拉电阻将SDA和SCL线连接到Vcc:

如何编程?

Talk is cheap. Show me the code.

参考了STM32的HAL库中I2C驱动,主设备发送函数HAL_I2C_Master_Transmit()具体如下:

/*** @brief  Transmits in master mode an amount of data in blocking mode.* @param  hi2c Pointer to a I2C_HandleTypeDef structure that contains*                the configuration information for the specified I2C.* @param  DevAddress Target device address: The device 7 bits address value*         in datasheet must be shifted to the left before calling the interface* @param  pData Pointer to data buffer* @param  Size Amount of data to be sent* @param  Timeout Timeout duration* @retval HAL status*/
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint8_t *pData, uint16_t Size, uint32_t Timeout){uint32_t tickstart = 0x00U;/* Init tickstart for timeout management*/tickstart = HAL_GetTick();if(hi2c->State == HAL_I2C_STATE_READY){/* Wait until BUSY flag is reset */if(I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_BUSY, SET, I2C_TIMEOUT_BUSY_FLAG, tickstart) != HAL_OK){return HAL_BUSY;}/* Process Locked */__HAL_LOCK(hi2c);/* Check if the I2C is already enabled */if((hi2c->Instance->CR1 & I2C_CR1_PE) != I2C_CR1_PE){/* Enable I2C peripheral */__HAL_I2C_ENABLE(hi2c);}/* Disable Pos */hi2c->Instance->CR1 &= ~I2C_CR1_POS;hi2c->State     = HAL_I2C_STATE_BUSY_TX;hi2c->Mode      = HAL_I2C_MODE_MASTER;hi2c->ErrorCode = HAL_I2C_ERROR_NONE;/* Prepare transfer parameters */hi2c->pBuffPtr    = pData;hi2c->XferCount   = Size;hi2c->XferOptions = I2C_NO_OPTION_FRAME;hi2c->XferSize    = hi2c->XferCount;/* Send Slave Address */if(I2C_MasterRequestWrite(hi2c, DevAddress, Timeout, tickstart) != HAL_OK){if(hi2c->ErrorCode == HAL_I2C_ERROR_AF){/* Process Unlocked */__HAL_UNLOCK(hi2c);return HAL_ERROR;}else{/* Process Unlocked */__HAL_UNLOCK(hi2c);return HAL_TIMEOUT;}}/* Clear ADDR flag */__HAL_I2C_CLEAR_ADDRFLAG(hi2c);while(hi2c->XferSize > 0U){/* Wait until TXE flag is set */if(I2C_WaitOnTXEFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK){if(hi2c->ErrorCode == HAL_I2C_ERROR_AF){/* Generate Stop */hi2c->Instance->CR1 |= I2C_CR1_STOP;return HAL_ERROR;}else{return HAL_TIMEOUT;}}/* Write data to DR */hi2c->Instance->DR = (*hi2c->pBuffPtr++);hi2c->XferCount--;hi2c->XferSize--;if((__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BTF) == SET) && (hi2c->XferSize != 0U)){/* Write data to DR */hi2c->Instance->DR = (*hi2c->pBuffPtr++);hi2c->XferCount--;hi2c->XferSize--;}/* Wait until BTF flag is set */if(I2C_WaitOnBTFFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK){if(hi2c->ErrorCode == HAL_I2C_ERROR_AF){/* Generate Stop */hi2c->Instance->CR1 |= I2C_CR1_STOP;return HAL_ERROR;}else{return HAL_TIMEOUT;}}}/* Generate Stop */hi2c->Instance->CR1 |= I2C_CR1_STOP;hi2c->State = HAL_I2C_STATE_READY;hi2c->Mode = HAL_I2C_MODE_NONE;/* Process Unlocked */__HAL_UNLOCK(hi2c);return HAL_OK;}else{return HAL_BUSY;}
}

总结

本文主要介绍I2C的入门基础知识,从I2C协议的硬件层,协议层进行了简单介绍;作者能力有限,难免存在错误和纰漏,请大佬不吝赐教。


http://chatgpt.dhexx.cn/article/yugrQgB5.shtml

相关文章

奇安信SSL VPN详细配置步骤

1、网络接口配置(GE2接口配置,GE1调试接口) 2、静态路由配置(网络配置-网络路由-IPv4路由) 3、NC的IP地址池添加(SSL-VPN-应用设置-IP地址池-虚拟地址池添加) 4、用户和组的添加 5、NC设置 6、…

防火墙之IPSec VPN实验

防火墙IPSec VPN实验 原理概述: 指采用IPSec协议来实现远程接入的一种VPN技术,IPSec全称为Internet Protocol Security,是由Internet Engineering Task Force (IETF) 定义的安全标准框架,在公网上为两个私有网络提供安全通信通道,通过加密通道…

如何使用Xshell7连接学校虚拟机(保姆级)

如何使用Xshell7连接学校虚拟机(保姆级) 文章目录 如何使用Xshell7连接学校虚拟机(保姆级)一、前言二、连接学校VPN三、使用学校平台建立虚拟环境四、配置OpenVPN客户端五、使用Xshell连接虚拟机1、新建会话2、设置新建会话属性2、…

密码应用体系建设(政务方向)

一、背景 密码是保障网络与信息安全的核心技术和基础支撑,是解决网络与信息安全问题最有效、最可靠、最经济的手段。《密码法》的颁布实施,从法律层面为开展商用密码应用提供了根本遵循,《国家政务信息化项目建设管理办法》的颁布实施&#…

OSI七层网络协议

在前一篇博客运维往事 一次负载均衡坏点检测事故中我提到了在生产环境中在第四层和第七层做healthCheck,这个第四层和第七层到底是什么意思呢?除了第四层第七层之外,其他的几层到底是什么?这几层到底做了啥?   OSI把…

网络七层协议,五层协议概述

一、七层协议: 1、应用层: 针对特定应用的协议(如:电子邮件协议E-mail、远程登录协议SSH,文本传输协议FTP、网络请求协议HTTP) 2、表示层: 信息的语法语义以及它们的关联,如加密…

简洁易懂——网络七层协议

国际标准化组织ISO于1984年提出了OSI(Open Ssystem Interconnection Reference Model,开放系统互联参考模型)。OSI很快成为计算机网络通信的基础模型。 OSI依层次结构来划分:第一层,物理层;第二层,数据链路…

计算机网络七层协议osi

OSI(open system interconnect开放系统互联)七层模型:物理层,数据链路层,网络层,传输层,会话层,表示层,应用层。 OSI七层模型功能对应的网络协议TCP/IP四层概念模型应用层…

1分钟看懂网络七层协议/OSI七层模型

网络七层协议用一张图表示,大概是这样的: 物理层: 解决两个硬件之间怎么通信的问题,常见的物理媒介有光纤、电缆、中继器等。它主要定义物理设备标准,如网线的接口类型、光纤的接口类型、各种传输介质的传输速率等。 …

OSI网络七层协议

OSI(Open System Interconnect),即开放式系统互联参考模型,一般都叫OSI参考模型,是ISO(国际标准化组织)在1985年提出的一个试图将各种计算机或者通信系统在世界范围内互联为网络的标准框架模型。在这一框架下详细的规定…

(知识点)TCP/IP协议(网络七层协议)

OSI参考模型 实际上,分组通信协议很复杂,OSI参考模型将其分为了易于理解的七个分层,如下图: OSI参考模型中每个分层的作用 下图表述了简单的每个分层的作用: 1. 应用层 为应用程序提供服务并规定应用程序中通信相…

网络七层模型及各层协议

网络七层模型作用应用层 (Application)网络服务与最终用户的一个接口。表示层(Presentation Layer)主要进行对接收数据的解释、加密与解密、压缩与解压缩。确保一个系统的应用层发送的数据能被另一个系统的应用层识别。(在五层模型里面已经合并到了应用层)会话层(Session Layer…

网络协议基础01-七层网络协议

前言:为什么学? 1.避不开:几乎所有的程序运行都会涉及到网络协议 2.不过时:越基础知识越不容易过时,值得花时间深入学习和积累。 容器技术、大数据、云计算、人工智能、区块链...等技术更新迭代速度很快&#xff0c…

网络七层协议结构分析图

文章目录 前言一、网络七层协议结构图详解二、TCP和UDP的区别1.TCP(打电话)1.连接稳定2.客户端,服务端3. 传输完成,释放连接,效率低,4. 三次连接四次挥手1.三次连接2.四次挥手 2.UDP(发短信&…

七层网络协议知多少

图,自然不是我的 最近太忙了,又是毕设又是春招的,忙的我都没时间看小说,所以博主我开始瞎 编小说了,学的比较浅,如有不对,还请指正。 物理层 许多年前的一天,小A和小B一块在电脑上…

网络中的七层协议与TCP/IP五层模型

socket(套接字)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址&a…

蓝牙nrf52832的架构和开发

相比TI的CC254X、DIALOG的DA1458X,nordic推出的nrf51822和nrf52832在架构和开发商都有自己独特的地方。这几颗产品都是蓝牙低功耗芯片。DA1458X使用OTP硬件架构,功耗低,成本也低,但软件开发难度是个门槛,大团队才能做到…

NORDIC nrf52833使用笔记

文章目录 一、SoftDevice命名规则(一)、通用规则(二)、特定规则 二、nRF52833关键特性三、SoftDevice目录框架四、代码目录框架五、应用代码结构六、内存分配表(一)、不带bootloader时的内存分配&#xff0…

NRF52832官方SDK介绍

SDK(Software Development Kit)是指软件开发包,一般是由官方提供,主要用来介绍开发流程,提供常用的例程代码等等。可以降低开发者使用的门槛,提高开发效率,所以在开发者在进行具体的开发前必须先…

第二章 nRF52832介绍

关注嘉友创科技公众号 源码地址:https://github.com/HX-IoTnRF52832开发指南QQ群:326941601,内有pdf版,排版整洁。 nRF52832 SoC是一款功能强大,高度灵活的超低功耗多协议SoC蓝牙单芯片,嵌入式2.4GHz收发器…