详解I2C

I2C(也常写作 I I C IIC IIC I 2 C I^2C I2C),全称为Inter-Integrated Circuit(“互连集成电路”),用于在集成电路之间进行短距离数据传输。它由Philips(现在的NXP半导体)公司于1980年代初开发,并成为一种广泛应用于电子设备之间通信的标准。I2C协议简单、灵活且广泛支持,常用于连接传感器、存储器、显示屏和其他外设到微控制器、微处理器或其他集成电路上。这是一种简单的双向双线总线,非常适合用于微控制器与外设之间,或者多个微控制器之间的高效互连控制。

其名称反映了最初的设计目的:它专为“集成电路”间的通信设计。I2C的两条线包括SDA(串行数据线),用于传输信息;和SCL(串行时钟线),负责同步。I2C的一个优点是它只需要这两根线进行通信,这可以在复杂系统中有效地利用资源。

它也是一种在许多产品中广泛使用的标准,扩展和集成相对简单。

I2C的主要特点包括:

  • 通信方式:I2C采用主从式通信方式。一个主设备(通常是微控制器或处理器)控制总线并发起通信,而一个或多个从设备被动地响应主设备的命令或请求。
  • 总线结构:I2C使用两根线路进行通信:
    • SCL(Serial Clock):时钟线由主设备提供,用于同步通信速度。
    • SDA(Serial Data):数据线用于传输数据和控制信号。
  • 信号电平:I2C使用双向开漏(open-drain)输出,这意味着信号线可以被拉低(逻辑0)但不能被主动拉高,只能通过外部上拉电阻回到高电平(逻辑1)。
  • 地址和帧格式:I2C使用7位或10位的设备地址来唯一标识每个从设备。通信帧包括设备地址、读/写位、数据字节和应答位(ACK)。
  • 速率和模式:I2C支持不同的通信速率,通常有标准模式(100 kbit/s)和快速模式(400 kbit/s)。还有更高速的模式如高速模式(3.4 Mbit/s)和超高速模式(5 Mbit/s)。
  • 启动和停止条件:I2C通信的开始由主设备发送启动信号(SDA从高电平切换到低电平,同时SCL保持高电平)表示。通信结束时,主设备发送停止信号(SDA从低电平切换到高电平,同时SCL保持高电平)表示。
  • 多主设备支持:I2C协议允许多个主设备共享同一条总线,通过仲裁机制来解决总线竞争问题。
  • 应用领域:I2C广泛应用于各种设备和应用领域,例如传感器、存储器(如EEPROM)、显示屏、温度传感器、实时时钟(RTC)、扩展IO芯片等。

I2C是一种简单、灵活且广泛支持的串行通信协议,适用于在电子设备之间进行短距离数据传输。它具有较低的硬件复杂性和通信开销,因此在许多嵌入式系统和电子设备中被广泛采用。

I2C协议还有一些其他的特性和扩展,如高速模式、高容量模式、地址扩展等,以满足更复杂的应用需求。虽然I2C并不适合所有情况(例如,它并不适用于长距离或高速应用),但它是一种常见的、实用的选择,适用于简单的内部通信。当希望许多从设备共享通信线并由一个(或多个)主设备管理时,它特别有用。

I2C总线通用连接框图:

I2C总线互联系统示意图

在单主机系统中,可以抽象为:

单主机I2C总线

典型的多主机系统则为:

多主机I2C总线

电气特性

I2C使用开漏/开集电极结构,同时在同一数据线上使用输入缓冲器,这允许单个数据线用于双向数据流。

双向通信的开漏结构

开漏指的是一种输出类型,可以将总线拉低到某个电压(通常是地线),或者"释放"总线,让其被上拉电阻拉高。当总线被主设备或从设备释放时,上拉电阻(RPU)负责将总线电压拉高到电源电平。由于没有设备可以强制将线路拉高,这意味着总线永远不会遇到通信问题,其中一个设备尝试传输高电平,而另一个设备传输低电平,导致短路(电源电平到地)。I2C要求在多主设备环境中,如果主设备发送高电平,但检测到线路低电平(另一个设备将其拉低),则停止通信,因为另一个设备正在使用总线。推挽接口不允许此类自由,这是I2C的一个优点。

SDA/SCL内部基本结构

上图显示了在SDA/SCL线上的从设备或主设备的内部结构的简化视图,包括用于读取输入数据的缓冲器和用于传输数据的下拉场效应晶体管(FET)。设备只能将总线线路拉低(与地短接)或释放总线线路(对地高阻抗),并允许上拉电阻将电压拉高。这是在处理I2C设备时需要了解的重要概念,因为没有设备可以将总线保持高电平。这个特性是实现双向通信的关键。

拉低总线

如前所述,开漏结构只能将总线拉低,或者"释放"总线并由电阻将其拉高。下图展示了将总线拉低时的电流流动。希望传输低电平的逻辑会激活下拉场效应晶体管,提供对地的短路,将线路拉低。

拉低总线

释放总线

当从设备或主设备希望传输逻辑高时,它只能通过关闭下拉场效应晶体管来释放总线。这将使总线悬空,而上拉电阻将把电压拉高到电源电平,被解释为高电平。下图展示了通过上拉电阻的电流流动,将总线拉高。

释放总线

通信速率模式

速率模式

常规模式

高速模式

超快模式

接口规范

一般操作

I2C总线是一种标准的双向接口,使用控制器(即主设备)与从设备进行通信。除非被主设备寻址,否则从设备不能传输数据。I2C总线上的每个设备都有一个特定的设备地址,以区分其他在同一I2C总线上的设备。许多从设备在启动时需要进行配置,以设置设备的行为。这通常在主设备访问从设备的内部寄存器映射时完成,这些寄存器具有唯一的寄存器地址。一个设备可以有一个或多个寄存器,用于存储、写入或读取数据。

物理的I2C接口由串行时钟(SCL)线和串行数据(SDA)线组成。SDA和SCL线都必须通过上拉电阻连接到VCC电源。上拉电阻的大小取决于I2C线路上的电容量。只有当总线处于空闲状态时,才能启动数据传输。如果在停止条件之后,SDA和SCL线都保持高电平,总线将被认为是空闲的。

主设备访问从设备的一般过程如下:

  1. 如果主设备想要向从设备发送数据:

    • 主设备-发送器发送起始条件并寻址从设备-接收器
    • 主设备-发送器向从设备-接收器发送数据
    • 主设备-发送器通过停止条件终止传输
  2. 如果主设备想要接收/读取从设备的数据:

    • 主设备-接收器发送起始条件并寻址从设备-发送器
    • 主设备-接收器向从设备-发送器发送要读取的寄存器
    • 主设备-接收器从从设备-发送器接收数据
    • 主设备-接收器通过停止条件终止传输

起始和停止条件

I2C通信通过主设备发送起始条件(START condition)来初始化,并通过主设备发送停止条件(STOP condition)来终止。在SCL线为高电平时,SDA线上的高至低的跳变定义了起始条件。在SCL线为高电平时,SDA线上的低至高的跳变定义了停止条件。

起始和停止条件示例

重复起始条件

重复的起始条件(Repeated START condition)类似于起始条件(START condition),用作连续的停止条件和起始条件的替代。它在外观上与起始条件相同,但与起始条件不同,因为它发生在停止条件之前(总线不处于空闲状态)。这在主设备希望启动新的通信,但不希望通过停止条件使总线空闲,从而可能失去对总线的控制权(在多主设备环境中)时非常有用。

数据有效性和字节格式

在每个SCL时钟脉冲期间传输一个数据位。一个字节由SDA线上的八个位组成。一个字节可以是设备地址、寄存器地址或从从设备写入或读取的数据。数据以最高有效位(MSB)优先的顺序传输。在START和STOP条件之间,可以从主设备向从设备传输任意数量的数据字节。在时钟周期的高电平期间,SDA线上的数据必须保持稳定,因为当SCL为高电平时,数据线的变化被解释为控制命令(START或STOP)。

单字节传输示例

应答(ACK)和非应答(NACK)

接收器在每个数据字节(包括地址字节)后发送一个ACK位。ACK位允许接收器向发送器传达字节已成功接收,并且可以发送另一个字节。

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

当SDA线在ACK/NACK相关的时钟周期中保持高电平时,这被解释为非应答(NACK)。有几种情况会导致产生NACK:

  1. 接收器由于执行某些实时功能并且尚未准备好与主设备开始通信,因此无法接收或发送。
  2. 在传输过程中,接收器接收到无法理解的数据或命令。
  3. 在传输过程中,接收器无法接收更多的数据字节。
  4. 主设备接收器完成数据读取,并通过NACK向从设备表示这一点。

NACK波形示例

I2C数据

必须通过读取或写入从设备的寄存器来发送和接收数据。寄存器是从设备内存中包含信息的位置,无论是配置信息还是一些采样数据用于发送回主设备。主设备必须向这些寄存器中写入信息,以指示从设备执行任务。

虽然在I2C从设备中常见的是寄存器,但请注意,并非所有的从设备都会有寄存器。一些设备非常简单,只包含一个寄存器,可以通过在从设备地址之后立即发送寄存器数据来直接写入该寄存器,而无需寻址寄存器。单寄存器设备的一个例子是8位I2C开关,它通过I2C命令进行控制。由于它只有一个位来启用或禁用通道,因此只需要一个寄存器,主设备只需在从设备地址之后写入寄存器数据,跳过寄存器编号。

向I2C总线上的从设备写入数据

要在I2C总线上写入数据,主设备将在总线上发送一个带有从设备地址的起始条件,并将最后一位(R/W位)设置为0,表示写入操作。在从设备发送应答位后,主设备将发送要写入的寄存器地址。从设备再次发送应答位,通知主设备它已准备好。然后,主设备将开始向从设备发送寄存器数据,直到主设备发送完所有需要的数据(有时仅为一个字节),然后通过发送停止条件终止传输。

下图显示了向从设备寄存器写入单个字节的示例:

向从设备寄存器写数据示例

从I2C总线上的从设备读取数据

从从设备读取数据与写入数据非常相似,但有一些额外的步骤。为了从从设备读取数据,主设备首先必须告知从设备它希望从哪个寄存器读取数据。主设备通过类似写入操作的方式开始传输,发送带有R/W位为0(表示写入)的地址,然后是要从中读取数据的寄存器地址。一旦从设备确认了寄存器地址,主设备将再次发送起始条件,然后发送带有R/W位为1(表示读取)的从设备地址。这次,从设备将确认读取请求,主设备释放SDA总线,但仍向从设备提供时钟。在此事务的这个阶段,主设备将变为主设备接收器,而从设备将变为从设备发送器。

主设备将继续发送时钟脉冲,但会释放SDA线,以便从设备可以传输数据。在每个数据字节结束时,主设备将向从设备发送一个ACK,表示主设备准备好接收更多数据。一旦主设备接收到了所期望的字节数,它将发送一个NACK,告知从设备停止通信并释放总线。主设备随后发送停止条件。

下图显示了从从设备寄存器读取单个字节的示例:

从从设备寄存器读数据示例

实例

这两天调试 【开源】调试利器:高速 USB 转 UART、SPI、I2C、JTAG 这个模块时捕捉了一些波形,可以结合前文一起理解:

实例1

对应代码:

result = ch347_driver.i2c_set(device_index, 1)
if result:
    print("Success to set I2C speed.")
else:
    print("Failed to set I2C speed.")

result = ch347_driver.i2c_set_delay_ms(device_index, 1)
if result:
    print("Success to set I2C delay.")
else:
    print("Failed to set I2C delay.")


result = ch347_driver.stream_i2c(device_index, b'\x13', 2)
if result:
    print("Success!")
else:
    print("Failed!")

实例2

对应代码:

result = ch347_driver.i2c_set(device_index, 1)
if result:
    print("Success to set I2C speed.")
else:
    print("Failed to set I2C speed.")

result = ch347_driver.i2c_set_delay_ms(device_index, 1)
if result:
    print("Success to set I2C delay.")
else:
    print("Failed to set I2C delay.")


result = ch347_driver.stream_i2c(device_index, b'\x12\x13\x14', 8)
if result:
    print("Success!")
else:
    print("Failed!")

总结

I2C总结

公众号 | FunIO
微信搜一搜 “funio”,发现更多精彩内容。
个人博客 | blog.boringhex.top

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/99721.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DolphinDB 携手白鲸开源 WhaleStudio 打造高效敏捷的 DataOps 解决方案

浙江智臾科技有限公司(简称:DolphinDB)和北京白鲸开源科技有限公司(简称:白鲸开源)是在大数据技术领域活跃的两支专业团队。 DolphinDB 专注于为用户提供集高性能存储、复杂分析能力和流处理于一体的实时计…

Linux内核源码分析 (5)多处理器调度

Linux内核源码分析 (5)多处理器调度 文章目录 Linux内核源码分析 (5)多处理器调度注:本章节使用的内核版本为Linux 5.6.18一、 SMT和NUMA1、SMP (对称多处理器结构)2、NUMA (非一致内存访问结构) 二、多核调度三、调度域和调度组四、SMP调度详…

Power BI 连接 MySQL 数据库

Power Query 或 Power BI 只提供了对 SQL Server 的直接连接,而不支持其它数据库的直连。所以第一次连接 MySQL 数据库时,就出现下面的错误信。 这就需要我们自己去安装一个连接器组件。https://downloads.mysql.com/archives/c-net/ 错误解决方案 我一…

MySQL 8 数据清洗总结

MySQL 8 数据清洗三要素: 库表拷贝和数据备份数据清洗SQL数据清洗必杀技-存储过程 前提:数据库关联库表初始化和基础数据初始化: -- usc.t_project definitionCREATE TABLE t_project (id varchar(64) NOT NULL COMMENT 主键,tid varchar(…

Spring MVC 五 - Spring MVC的配置和DispatcherServlet初始化过程

今天的内容是SpringMVC的初始化过程,其实也就是DispatcherServilet的初始化过程。 Special Bean Types DispatcherServlet委托如下一些特殊的bean来处理请求、并渲染正确的返回。这些特殊的bean是Spring MVC框架管理的bean、按照Spring框架的约定处理相关请求&…

rtsp 拉流 gb28181 收流 经AI 算法 再生成 rtsp server (一)

1、 rtsp 工具 1 vlc 必备工具 2 wireshark 必备工具 3 自己制作的工具 player 使用tcp 拉流,不自己写的话,使用ffmpeg 去写一个播放器就行 4 live555 编译好live555, 将live555的参数修改以下,主要是缓存大小 文章使用c 来写一…

JavaScript Web APIs-01学习

复习: splice() 方法用于添加或删除数组中的元素。 **注意:**这种方法会改变原始数组。 删除数组: splice(起始位置, 删除的个数) 比如:1 let arr [red, green, blue] arr.splice(1,1) // 删除green元素 consol…

LinkedHashMap实现LRU缓存cache机制,Kotlin

LinkedHashMap实现LRU缓存cache机制,Kotlin LinkedHashMap的accessOrdertrue后,访问LinkedHashMap里面存储的元素,LinkedHashMap就会把该元素移动到最尾部。利用这一点,可以设置一个缓存的上限值,当存入的缓存数理超过…

取一个整数各偶数位上的数构成一个新的数字

1 题目 我可太难了,这题我的思路有点复杂,遇到的困难很多,总是值传递搞不清楚,地址传递总是写错。 从低位开始取出一个整数s的各奇数位上的数,剩下的偶数位的数依次构成一个新数t。 例如: 输入s&#xff…

vue自定义键盘

<template><div class"mark" click"isOver"></div><div class"mycar"><div class"mycar_list"><div class"mycar_list_con"><p class"mycar_list_p">车牌号</p>…

浪潮云海护航省联社金融上云,“一云多芯”赋能数字农业

农村金融是现代金融体系的重要组成部分&#xff0c;是农业农村发展的重要支撑力量&#xff0c;而统管全省农商行及农信社的省级农村信用社联合社&#xff08;以下简称&#xff1a;省联社&#xff09;在我国金融系统中占据着举足轻重的地位。省联社通常采用“大平台小法人”的发…

稳定性建设框架 | 京东物流技术团队

一、为什么要做稳定性建设 1、从熵增定律引出稳定性建设的必要性 物理学上&#xff0c;用“熵”来描述一个体系的混乱程度。卡尔弗里德曼提出熵增定律&#xff0c;他认为在一个封闭的系统内&#xff0c;如果没有外力的作用&#xff0c;一切物质都会从有序状态向无序状态发展。…

第一课:使用C++实现图片去水印

1.功能概述 实现图片去水印的方法有很多,下面提供一种基于OpenCV库的C++实现方法。主要思路是利用图像中不同水印区域之间的差异,进行区域提取、重构和合成,从而实现去除水印的效果。 2.具体实现 2.1.导入OpenCV库和头文件 #include <iostream> #include <o…

Vue2向Vue3过度Vuex核心概念getters

目录 1 核心概念 - getters1.定义getters2.使用getters2.1原始方式-$store2.2辅助函数 - mapGetters 2 使用小结 1 核心概念 - getters 除了state之外&#xff0c;有时我们还需要从state中筛选出符合条件的一些数据&#xff0c;这些数据是依赖state的&#xff0c;此时会用到get…

【Golang 接口自动化05】使用yml管理自动化用例

目录 YAML 基本语法 对象&#xff1a;键值对的集合(key:value) 数组&#xff1a;一组按顺序排列的值 字面量&#xff1a;单个的、不可再分的值&#xff08;数字、字符串、布尔值&#xff09; yml 格式的测试用例 定义yml文件 创建结构体 读取yml文件中的用例数据 调试…

unity pivot and center

一般采用pivot即默认的模式 选中物体的轴心 Center中心 选中多个物体&#xff0c;两咱情况下旋转的效果也不一样 围绕各自中心旋转 Center 围绕中心旋转

使用kafka还在依赖Zookeeper,kraft模式了解下

Kafka的Kraft模式 概述 ​ Kafka是一种高吞吐量的分布式发布订阅消息系统&#xff0c;它可以处理消费者在网站中的所有动作流数据。其核心组件包含Producer、Broker、Consumer&#xff0c;以及依赖的Zookeeper集群。其中Zookeeper集群是Kafka用来负责集群元数据的管理、控制器…

【Qt专栏】实现单例程序,禁止程序多开的几种方式

目录 一&#xff0c;简要介绍 二&#xff0c;实现示例&#xff08;Windows&#xff09; 1.使用系统级别的互斥机制 2.通过共享内存&#xff08;进程间通信-IPC&#xff09; 3.使用命名互斥锁&#xff08;不推荐&#xff09; 4.使用文件锁 5.通过网络端口检测 一&#xf…

通过 Jetbrains GateWay实现Remote Development

本次环境准备 环境准备&#xff1a;win10、一台安装有树莓派系统的树莓派&#xff08;也可以是其他的服务器&#xff09; 第一步&#xff1a;通过官网下载JetBrains Gateway 官网地址&#xff1a;https://www.jetbrains.com/remote-development/gateway/ 第二步&#xff1a;安装…

【Hadoop】HDFS读写流程和客户端命令使用

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,Java基础学习,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的…