I2C学习笔记
前言
我一直不是特别喜欢读文档,习惯了通过视频学习,因为视频能更直观地展现信息,给人一种更生动、形象的感觉。然而,随着学习的内容逐渐增多,我发现并不是所有的知识点都能在视频中找到,或者视频中展示的内容往往存在不准确或错误的情况。于是,我开始尝试通过阅读文档来学习,认为这是理解开发者思路和协议本质的最直接途径。
学习 I2C 协议是这种尝试的一部分。作为最简单的通信协议之一,I2C协议相较于更复杂的协议(例如 BLE5.3 的 Core 部分就有三千多页文档),无疑是一个更合适的入门选择。在此过程中,除了参考协议的官方文档外,我还阅读了多个设备的技术手册,力图从多个角度全面理解I2C协议的各个方面。通过这一学习过程,我总结了这篇笔记,希望它能对你有所帮助。如果在阅读过程中发现任何错误,敬请指正。
参考文档:
I2C-bus specification and user manual — NXP Semiconductor
A Basic Guide to I2C — Texas Instruments
ADXL345 Data Sheet — ADI
ADS111x Data Sheet — Texas Instruments
Atmel AT24C01C and AT24C02C Data Sheet — MICROCHIP
文中出现的图片来源于网络,如有侵权,请联系我进行删除
文章目录
- I²C
- 简介
- 物理层
- 双线通信
- 设备连接方式
- 通信模式
- 速度模式
- 开漏连接
- 非破坏性总线争用
- I2C 通信协议
- 通信开始和停止
- 逻辑 1/0
- 数据帧
- 写操作
- 从指定寄存器读取数据
- 保留地址
- 通用调用地址
- START 字节
- C-Bus 地址、不同的总线格式、未来用途
- Hs 模式控制器代码
- 设备 ID
- 10 位目标地址
- 高级特性
- 时钟同步和仲裁
- SCL 同步
- 总线仲裁
- 时钟拉伸
- 工作原理
- 特点与注意事项
- 电气规格
- 电压和逻辑电平
- 电压电平转换
- 电流
- 时序
- 上拉电阻
- 上拉电阻阻值
- 最小上拉电阻阻值
- 最大上拉电阻
- 总线电容
- 其他电气特性
I²C
简介
MCU 与外围设备之间的通信需要通过某种数字协议,而 I²C 就是这些协议之一
I²C 是一种使用串行数据线SDA
和串行时钟线SCL
的双线串行通信协议,支持在一个总线上连接多个设备,且支持多个控制器在总线上进行数据收发
通信以字节包发送,每个设备在总线上具有唯一地址
发展历史
I²C 通常被称为I two C
,代表内部集成协议,在 1982 年由 Philips Semiconductor (飞利浦半导体,现在的 NXP Semiconductor 恩智浦半导体) 发明,作为一种低速通信协议,它用于将控制器设备(如 MCU 等)和外围设备连接起来
I2C 是一个被广泛运用的协议,原因如下:
- 只需要两条通信线路
SDA
和SCL
即可进行通信 - 以总线的形式连接多个设备,且控制器可以与总线上的任一设备进行通信
- 制造成本低
总线是电子系统中用于传输数据、地址和控制信号的通信路径。它连接着系统中的不同部件,使得数据能够在多个设备之间进行交换和传递。总线通常包括数据线、地址线和控制线,支持多种通信协议,如 I2C、SPI 等。通过总线,多个设备能够共享同一条信号路径,有效地提高了系统的连接效率和扩展性
物理层
双线通信
设备连接方式
I2C 协议使用两条线路来进行所有设备之间的通信:
-
SDA(Serial Data Line)
数据线,用于向目标设备传输数据 -
SCL(Serial Clock Line)
时钟线,主要由控制器控制的串行时钟,用于同步数据的传输
这两条线是共享的,即所有连接到I2C总线的设备都通过这两条线进行通信,同时,这两条线都需要连接上拉电阻
上拉电阻是电子电路中常用的一种电阻配置,它将信号线连接到电源电压(通常是 Vcc),确保信号线在没有驱动信号时能够稳定地保持在高电平状态
在像 I2C 这样的开漏连接系统中,上拉电阻非常重要,因为信号线在某些情况下会处于悬空状态,无法自动拉高。上拉电阻通过提供一定的电流,保证信号线能够从低电平(接地)拉回到高电平,确保数据传输稳定并且符合逻辑要求
通信模式
-
I2C 是一种半双工通信,每次通信只有一个控制器或目标设备在总线上发送数据
-
主设备(Controller)负责启动和停止通信
- 主设备控制通信的开始(发送起始信号)和结束(发送停止信号),从而避免了总线上的总线争用(Bus Contention)问题(在多个设备共享同一总线时,如果没有明确的控制信号,可能会出现多个设备同时试图发送数据的冲突情况)
-
在 I2C 总线中,每个设备都被分配了一个唯一的地址
- 当主设备需要与某个从设备通信时,会通过这个唯一的地址来选定目标设备进行数据传输,这使得 I2C 能够在同一总线中支持多个控制器和多个目标设备,每个设备只会响应自己地址对应的命令或数据传输,避免了设备间的干扰
-
I2C 总线中的数据线(SDA)和时钟线(SCL)采用的是开漏连接
- 这意味着这些信号线通过晶体管与地连接,只有当设备需要传输信号时,才能拉低线路至地电平
- 设备不会主动将信号线拉高,信号线处于悬空状态时需要外部电路来将其拉高(上拉电阻的作用)
半双工通信(Half-Duplex)
在半双工模式下,数据传输是双向的,但不能同时进行,也就是说,设备在同一时刻只能发送或接收数据,而不能同时进行这两项操作
- 比如两个人传纸条,只有一张纸,一个人写完以后另一个人才能写
全双工通信(Full-Duplex)
在全双工模式下,数据可以同时双向传输,即设备可以在同一时间同时发送和接收数据,通信效率更高
- 电话通话就是全双工通信,双方可以同时说话和听对方说话
速度模式
I2C 有多种速度模式:
-
Standard-mode 标准模式 — 100kbps
-
Fast-mode 快速模式 — 400kbps
- 要求:总线电容和驱动能力允许使用快速模式
-
Fast-mode Plus 快速模式+ — 1Mbps
- 为了实现这一速度,设备中的驱动器需要提供更强的驱动能力,以确保信号的上升时间和下降时间(即信号从低电平到高电平或从高电平到低电平的变化速度)足够快
以上三种模式使用了相同的通信结构,但时间规格不同,硬件实现也有区别;I2C 还有另外两种支持更高速率的模式:
-
High-speed mode 高速模式 — 3.4 Mbps
- 为了启用这种高速度传输,控制器设备必须首先使用控制代码来激活目标设备的高速度模式
- 可能需要使用主动拉高电阻(一个具有更强驱动能力的电阻),它能帮助提升信号线的电压,从而确保信号能在较高的数据速率下稳定传输
- 较高的传输速率要求信号的上升和下降时间更短,因此需要更强的电流来驱动信号线
-
Ultra-fast mode 超快模式 — 5Mbps
- 该模式为只写模式,无法从设备接收数据
- 了实现更高的传输速度,Ultra-Fast 模式省略了 I2C 协议中的一些功能,可能包括某些校验、错误处理或其他通信协议的细节,这会提高通信效率,但也可能会降低通信的可靠性,特别是在较长距离或噪声较多的环境中
开漏连接
在 I2C 总线的 SDA 和 SCL 信号线中,采用的是开漏连接,这意味着信号线通过一个 NMOS 晶体管连接到地
-
当 NMOS 晶体管导通时,信号线被拉低(连接到地),此时为低电平
- 它将信号线连接到地,从而将 SDA 或 SCL 信号线拉低到逻辑“0”电平,这个过程非常快速,因为 NMOS 直接将信号线拉低,过渡从高电平到低电平的速度很快
- 从高到低的过渡速度主要由 NMOS 的驱动强度和总线电容(即 SDA 和 SCL 线的电气特性)共同决定,总线电容越大,信号的过渡时间就越长
-
当 NMOS 晶体管关闭时,信号线处于悬空状态,此时信号线被上拉电阻上拉至高电平
- 当 NMOS 关闭时,上拉电阻将信号线拉回到高电平(VDD),这时,信号线的过渡会受总线电容影响,较慢
- 选择较小的上拉电阻可以实现更快的上升时间,从而提高通信速度,但这会导致更高的功耗
- 较大的上拉电阻会使信号的上升时间变慢,从而降低通信速度,但相对较低的功耗
- 当 NMOS 关闭时,上拉电阻将信号线拉回到高电平(VDD),这时,信号线的过渡会受总线电容影响,较慢
NMOS(N型金属氧化物半导体)是一种场效应晶体管,它通过电场控制源极和漏极之间的导电通道,NMOS 具有低导通电阻和快速开关特性,广泛应用于数字电路和开关电路中
总线电容是指 PCB 上信号线与地、相邻导线或其他电路之间形成的电容。它影响信号的传播速度,尤其在 I2C 等总线通信中,当信号从低电平过渡到高电平时,较大的总线电容会使过渡速度变慢,影响数据传输的效率和稳定性。设计时通常会尽量减少总线电容,以提高信号传输的速度和质量
非破坏性总线争用
-
开漏输出的优势
- 总线争用不会导致破坏性状态:当0多个设备连接到同一条信号线时,如果其中任何一个设备将信号线拉低,信号线会被拉到低电平。这种
有线与(Wired-AND)
连接的方式保证了信号线的电平是多个设备输出的逻辑与(AND),不会导致破坏性争用,因为信号线的电平是由多个设备共同控制的 - 即使多个设备同时拉低信号线,信号线的状态仍然是有效的,且不会导致设备损坏或数据丢失
- 总线争用不会导致破坏性状态:当0多个设备连接到同一条信号线时,如果其中任何一个设备将信号线拉低,信号线会被拉到低电平。这种
-
推挽输出的风险
- 推挽输出(如SPI通信中常见的输出方式)使用了互补的 NMOS 和 PMOS 晶体管来分别驱动信号线的高电平和低电平。在多个设备使用推挽输出并连接在一起时,如果两个设备同时试图驱动信号线到不同的电平(例如,一个设备试图拉高,另一个设备试图拉低),就会发生冲突,导致破坏性状态,可能损坏设备或导致数据丢失
- 推挽输出(如SPI通信中常见的输出方式)使用了互补的 NMOS 和 PMOS 晶体管来分别驱动信号线的高电平和低电平。在多个设备使用推挽输出并连接在一起时,如果两个设备同时试图驱动信号线到不同的电平(例如,一个设备试图拉高,另一个设备试图拉低),就会发生冲突,导致破坏性状态,可能损坏设备或导致数据丢失
推挽输出(Push-Pull Output)是一种常见的信号输出方式,它使用互补的 NMOS 和 PMOS 晶体管来主动驱动信号线的高电平和低电平。与开漏输出不同,推挽输出可以快速且准确地切换信号的电平,不需要外部上拉电阻,适用于需要高速和较强电流驱动的应用。然而,多个推挽输出设备不能同时连接到同一信号线上,因为不同电平的输出会导致总线冲突,从而损坏设备或产生错误信号
开漏输出相当于所有设备共用一个 VDD,而推挽输出每个设备都有一个 VDD,当一个设备输出高电平,另一个设备输出低电平,相当于输出低电平的设备直接对 VDD 短路,可能会造成设备烧毁
I2C 通信协议
通信开始和停止
-
I2C 通信的启动(START Condition)
- I2C 通信由主设备(Controller Device)发起,使用 START 条件来开始总线上的通信。
- 首先将 SDA 拉低,然后将 SCL 拉低,这个顺序的变化表示主设备想要占用 I2C 总线进行通信,并且强制其他设备保持通信
-
I2C 通信的结束(STOP Condition)
- 当主设备完成通信时,它会通过发送 STOP 条件来释放总线,允许其他设备进行通信
- 首先将 SCL 拉高,然后将 SDA 拉高,表示通信结束,总线被释放
- 这个操作之后,总线被释放,允许其他控制器进行通信,或是同一控制器与不同的设备进行通信
逻辑 1/0
I2C 使用串行通信来传输数据。每个数据位(0或1)都通过SDA线(数据线)传输,而 SCL 线(时钟线)则控制数据位的传输时序,每一位数据的传输是同步的,SCL时钟在每个时钟周期中标记数据的读取和传输
-
逻辑 1 的传输
- 逻辑 1 是通过 SDA 释放线来实现的:当 SDA 线没有被设备拉低时,外部的上拉电阻将 SDA 线拉高,形成高电平,从而表示逻辑 1
-
逻辑 0 的传输
- 逻辑 0 是通过 SDA 拉低线来实现的:当 SDA 被设备拉低时,信号线的电压会降到接近地电平,表示逻辑 0
-
时序同步
- 当 SCL 产生脉冲时,逻辑 1 和逻辑 0 被接收。对于有效的位,SDA 在该位的 SCL 上升沿和下降沿之间保持不变。如果在 SCL 的上升沿和下降沿之间 SDA 发生变化,则可以将其解释为 I2C 总线上的 START 或 STOP 条件
- 当 SCL 产生脉冲时,逻辑 1 和逻辑 0 被接收。对于有效的位,SDA 在该位的 SCL 上升沿和下降沿之间保持不变。如果在 SCL 的上升沿和下降沿之间 SDA 发生变化,则可以将其解释为 I2C 总线上的 START 或 STOP 条件
数据帧
I2C 协议被分为多个帧
通信开始时,控制器设备在发送 START 信号后发送地址帧;地址帧后跟着一个或多个数据帧,每个数据帧由一个字节组成;每个帧还包含一个应答位,用来通知控制器目标设备或控制器设备已经接收到通信
-
在地址帧的开始,控制器设备发起一个 START 信号
- 控制器设备首先将 SDA 拉低,然后将 SCL 拉低来生成 START 信号
- 这允许控制器设备在总线上占用总线,而不受其他控制器设备的争用
-
每个 I2C 目标设备都有一个唯一的 I2C 地址,当与某个特定目标设备开始通信时,控制器使用目标设备的地址来发送或接收数据,在随后的 I2C 帧中进行传输,I2C 地址一般由 7 位组成,总线上的设备每个都有一个唯一的地址
- 7 位地址意味着可以有128(2^7) 个唯一的地址
- I2C 协议有一些保留地址,进一步限制了可用设备的数量
-
该帧中的第 8 位是读写位(R/W)
- 如果该位为 1,表示控制器要求从目标设备读取数据
- 如果该位为 0,表示控制器要求向目标设备写入数据
-
在每个通信字节后,会使用额外的第 9 位来验证通信是否成功。在地址字节通信结束时,目标设备在 SCL 脉冲期间将 SDA 拉低,表示目标设备已接收到地址,称为确认(ACK)位
- 如果该位为高电平,表示没有目标设备接收到地址,通信失败
- 如果该位为低电平,表示ACK(确认),即接收方已成功接收数据
-
地址帧之后会跟随一个或多个数据帧。每个数据帧一次发送一个字节。在每个数据字节传输后,会进行一个 ACK 确认
- 如果数据字节是写操作,则目标设备将 SDA 拉低以确认传输
- 如果数据字节是读取操作,则控制器将 SDA 拉低以确认数据已被接收
-
通信完成后,控制器发出 STOP 条件。首先释放 SCL,然后释放 SDA
- 控制器使用 STOP 信号表示通信已完成,并释放 I2C 总线
写操作
-
以 START 信号开始
-
写入目标设备地址
- 如果目标设备的地址匹配,该设备会发送一个 ACK,表示已接收到有效地址,并且设备准备好接收数据
-
当控制器发送带有写命令的地址后,控制器接着告诉设备正在写入哪个寄存器
- 第二个发送的字节是指向数据寄存器的寄存器指针
-
作为响应,目标设备通过拉低 SDA 发送一个 ACK ,表示目标设备向控制器确认已接收到地址指针数据,并且已知道正在写入哪个寄存器
-
接下来,寄存器的值被逐字节发送到目标设备
- 目标设备拉低 SDA 表示收到数据
-
传输完成后,此控制器通过发出 STOP 条件释放总线
有关连续读取/写入,需要根据目标设备的技术手册,查看是否支持单个或多个字节的读取/写入
从指定寄存器读取数据
先写入后读取
-
以 START 信号开始
-
写入目标设备地址
- 在此时,读/写位(R/W) 被设置为低,表示通信以向设备写入开始
- 目标设备通过拉低 SDA 发送一个 ACK
-
当控制器发送带有写命令的地址后,控制器接着告诉设备要读取哪个寄存器
- 目标设备通过拉低 SDA 发送一个 ACK ,表示目标设备向控制器确认已接收到地址指针数据
-
控制器发送 STOP 信号
-
再次发送 START 信号
-
控制器再次写入 I2C 目标设备地址
- 控制器已经指示了要读取哪个寄存器,现在控制器向设备发送读取命令,以便读取数据
- 此时,R/W 位被设置为高,表示读取
-
在地址帧完成后,目标设备发送 ACK 确认地址
-
目标设备向控制器发送数据
- 单字节读取:控制器应在接收到数据后发送 NACK,然后发送 STOP
- 多字节读取:控制器应在每个中间字节发送 ACK,最后一个字节发送 NACK,然后发送 STOP
-
控制器发送 STOP 停止读取
保留地址
在I2C协议中,向目标设备写入和读取数据需要使用I2C地址,用于识别控制器希望与之通信的设备
通常,这个地址通过一个字节传输,其中地址本身占用7位,第8位用于指示是从设备读取数据还是向设备写入数据
并非所有7位地址都可以用于目标设备,一些地址被保留用于其他用途:I2C拥有多个保留地址集,这些地址的使用基于特定的应用场景受到限制。使用这些保留地址调用的功能是设备的可选项,并不一定在所有I2C设备中都可用
X = don’t care; 1 = HIGH; 0 = LOW
目标地址 | R/W | 功能描述 |
---|---|---|
000 0000 | 0 | 通用调用地址 |
000 0000 | 1 | START 字节 |
000 0001 | X | C-Bus 总线地址 |
000 0010 | X | 保留用于不同的总线格式 |
000 0011 | X | 保留用于未来用途 |
000 01XX | X | Hs 模式控制器代码 |
111 11XX | 1 | 设备 ID |
111 10XX | X | 10 位目标地址 |
通用调用地址
向通用调用地址进行写操作用于同时向连接到 I2C 总线的所有设备发送命令,并非所有设备都设计为响应通用调用地址,如果有设备响应,那么目标设备可以处理通用调用后的第二个字节及后续字节
设备的响应取决于紧随通用调用之后的字节的最低有效位,这决定了两种不同的情况
-
第二个字节(B)的最低有效位为 0
- 第二个字节可用于向接收通用调用的设备发送命令
- 例如,通过 I2C 发送的常见命令之一是通用调用复位(General Call Reset):如果第二个字节是06h,表示控制器设备正在向I2C总线上的所有设备发送通用调用复位命令
-
第二个字节(B)的最低有效位为 1
- 控制器正在以硬件通用调用(Hardware General Call)的形式发送两字节序列
- 第二个字节用于发送硬件控制器的地址,以便在系统中标识自身1011。 其他控制器设备可以识别该地址,并将信息定向到充当目标设备的硬件控制器
START 字节
在I2C通信中,数据传输通常以一个“START”条件开始,并非所有微处理器都内置有I2C控制器。这意味着这些微处理器无法自动处理I2C通信(比如 STC89C52RC),需要通过软件来手动管理数据传输
此外,这些微处理器可能没有专门的中断机制来检测I2C总线上的通信活动,因此无法依赖硬件中断来通知处理器有新的数据传输
为了监控I2C总线上的通信活动,缺乏内置控制器和中断机制的微处理器必须通过不断地检查(轮询)SDA和SCL线路的状态来检测是否有通信发生
- 这种方法需要处理器以较高的频率轮询,以确保不会错过任何通信活动。这会消耗大量的处理能力,降低系统的整体效率
为了减少处理器的负担,可以在通信开始前发送一个特殊的START字节。具体方法是,控制器在START字节中使用7个零作为地址(即地址为00)
-
目标设备(接收方)在检测到这个特殊的START字节时,可以暂时降低轮询SDA和SCL线路的频率。这意味着在未检测到通信开始前,设备不需要频繁检查线路状态,从而节省处理能力
-
当目标设备检测到在START字节期间SDA线路发送了零(即检测到START信号),它会切换到更高的轮询速率,以便迅速检测接下来的I2C传输地址和数据
-
一旦I2C传输以STOP条件结束,目标设备会恢复到较低的轮询速率,继续节省处理能力
普通的 START 是将两根线拉低,告诉总线上的所有设备要开始通信了
这个特殊的 START 是将两根线拉低,发送 7 个 Byte 后拉高 1 Byte 再拉低
C-Bus 地址、不同的总线格式、未来用途
-
C-Bus 地址
- 用于允许 C-Bus 协议的设备连接到I2C总线
- 主要用于家庭和建筑自动化,在部分地区广泛使用
- 大多数 I2C 设备不会响应此地址,因而忽略该地址
-
不同的总线格式
- 用于支持不同协议之间的通信,促进多协议环境中的设备互操作性
- 仅限那些设计用于跨协议通信的 I2C 设备
-
未来用途
- 预留给未来可能的功能扩展或新协议
- 当前尚未定义具体用途,保留以供未来使用
跨协议通信的 I2C 设备指的是能够在不同通信协议之间进行数据交换和互操作的设备,这类设备通常充当桥梁或转换器,将 I2C 协议与其他协议(如SPI、UART、CAN等)连接起来,从而实现不同系统或组件之间的无缝通信
C-Bus(Control Bus)是一种用于家庭和建筑自动化系统的通信协议和网络技术。由施耐德电气(Schneider Electric)开发,C-Bus 旨在实现多设备之间的可靠、灵活和高效的控制与通信,广泛应用于智能家居、办公楼、商场、酒店等各种建筑环境中
Hs 模式控制器代码
高速控制器代码(High-Speed Controller Code)代码范围从 04 到 07(通常用于读写指示的第 8 位被用作高速控制器代码的一部分),这些高速控制器代码是保留的 8 位代码,不用于目标地址或其他用途
每个高速控制器都有一个唯一的控制器代码,I2C 总线上最多有八个高速控制器,高速模式控制器设备的控制器代码是软件可编程的,由系统设计师选择
高速控制器代码与标准设备地址分离,避免干扰正常的设备通信
因此每个设备和它对应的高速控制器其实相当于是“两个设备”
支持高速模式的设备在标准模式或快速模式下开始运行,控制器代码启用高速模式,高速控制器代码允许高速控制器之间的仲裁,并指示高速模式传输的开始。该代码启用内部电流源,使 I2C 通信总线比仅使用上拉电阻更快
启用后,高速数据传输在数据传输过程中持续进行,重复的 START 条件继续高速模式的数据传输(可以在不释放总线控制权的情况下,继续进行数据的传输,能够在一次通信会话中完成多步操作,如先设置寄存器指针再读取数据,从而优化整体的通信流程),而 STOP 条件将 I2C 总线返回到快速或标准模式
启用高速模式的通信过程
-
通信开始
- 设备以标准模式或快速模式启动
- 控制器发送 START 条件
-
发送保留地址
- 第一个字节使用为高速控制器代码保留的地址发送
- 控制器代码启用所有支持高速模式的设备的高速模式,并启用控制器内部用于高速模式的电路
-
发送目标地址和读写位
- 控制器随后发送高速模式设备的目标地址,并跟随一个读/写位以进行通信
- 数据由控制器或目标设备传输,每个数据字节后都有 ACK 确认,类似于标准的 I2C 通信
-
持续通信
- 目标设备继续通信,直到接收到 STOP 条件或接收到用于新目标地址的重复 START
设备 ID
保留地址7C到7F的用途
- 地址7C到7F专门用于设备ID的识别和读取
- 这些地址不是用于常规的读写操作,而是用于获取设备的制造商ID、部件识别码和芯片版本信息
- 允许控制器识别多个设备,并通过设备ID来区分和验证每个设备的具体信息
注意:这里的
7C到7F
是 7 位二进制数字,前三位和后四位的值,不含读写位
通信过程
-
发送 START 条件
-
发送保留的设备 ID 地址(7C 到 7F)并写入
- 控制器发送一个字节,其中前 7 位是保留的设备 ID 地址(例如,7C),第 8 位(R/W位)设置为 0,表示写操作
- 多个设备响应:保留地址可能被多个设备响应,多个设备会在收到这个地址后发送 ACK 信号,表示它们准备好接收后续数据
-
发送目标设备地址
- 控制器发送目标设备的具体地址,用于标识需要读取设备ID的特定设备
- 只有一个设备会对这个具体地址发送 ACK,确认它是目标设备
-
控制器发送重复 START 条件,保持总线控制权,继续进行下一步操作,而不释放总线
- 这里的开头必须是重复的 START,STOP 后跟 START 条件,或 STOP 后跟重复的 START 条件,然后访问不同的目标设备,将重置目标设备状态机,无法执行设备 ID 读取
-
发送保留的设备 ID 地址并读取
- 控制器再次发送保留的设备 ID 地址(7C 到 7F),这次第 8 位(R/W位)设置为 1,表示读操作
- 目标设备确认接收到读取命令,发送 ACK 信号
-
设备发送设备 ID 数据
-
数据帧结构
- 制造商 ID:12 位,用于标识设备的制造商
- 部件识别码:9 位,用于标识设备的具体部件或型号
- 芯片版本:3 位,用于标识设备的芯片版本或修订号
-
数据传输:设备通过三个 I2C 数据帧依次发送上述数据
-
-
-
-
发送 NACK 并结束通信
- 控制器 NACK 最后一个字节并以 STOP 结束设备 ID 读取
- 控制器可以随时通过发送 NACK 停止读取设备 ID
- 如果控制器在第三个字节之后继续确认字节,则目标将回滚到第一个字节并继续发送设备 ID 序列,直到检测到 NACK
控制器发送保留地址,相当于发送一条需要读取制造商信息的命令给设备,设备在接收到这个消息后,如果有相应的处理方式,则回应控制器
部分制造商对应ID
11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | Company |
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | NXP Semiconductors |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | NXP Semiconductors (reserved) |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | NXP Semiconductors (reserved) |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | NXP Semiconductors (reserved) |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | Ramtron International |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | Analog Devices |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | STMicroelectronics |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | ON Semiconductor |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | Sprintek Corporation |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 1 | ESPROS Photonics AG |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | Fujitsu Semiconductor |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 | Flir |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | O₂Micro |
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | Atmel |
尝试对 ADXL345 和 AT24C02 使用这种方式读取制造商 ID,但似乎这两个设备都不支持该种方式
虽然 ADXL345 的数据手册中提到了:
“ADXL345符合《UM10204 I2C总线规范和用户手册》03版(2007年6月19日,NXP Semiconductors提供)”
10 位目标地址
在使用 7 位目标设备地址时,能够挂载在总线上的设备有限,为了扩展设备数量,保留设备地址可以用于将目标设备地址扩展至 10 位
在保留地址 111 10XX 中,最后两位地址作为 10 位地址的开头两位,最后一位依旧为读/写位,第二个字节则为完整的 8 位地址,总体通信过程类似于使用 7 位地址时
在写入时,控制器发送使用 10 位地址需要的两个字节,第一个字节后为 0(写),随后直接发送需要写入的数据
在读取时,控制器在发送使用 10 位地址需要的两个字节,第一个字节后为 0(写),重新发送 START 后再次发送使用 10 位地址的第一个字节,后跟 1(读),之后再进行数据读取
高级特性
时钟同步和仲裁
在 I2C 通信中,同一条总线上可以有多个控制器,因此可能有两个或多个设备试图同时占用总线进行通信,这需要多个活动控制器来解决哪个设备控制总线
SCL 同步
-
I²C 使用开漏(open-drain)连接方式将 SCL 和 SDA 线路与多个控制器连接,形成有线与(wired-AND)结构
- 任何一个控制器将 SCL 拉低,整个 SCL 线路即被拉低;只有所有控制器都释放 SCL 时,线路才能被拉高
当两个控制器均将 SCL 拉低时,每个 SCL 脉冲的低电平由拉低 SCL 时间最长的控制器决定,高电平由拉高时间最短的控制器决定,只有在所有控制器都释放 SCL 之后,线路才能被释放为高电平以进行串行时钟脉冲(当一个控制器释放 SCL 使其拉高时,由于另一控制器仍然将 SCL 拉低,此时 SCL 仍处于低电平状态,同时控制器 1 仍在监控 SCL,此时控制器 1 不能推进 SCL 脉冲,必须等待其他控制器释放时钟),这同步了所有控制器的串行时钟的开始
总线仲裁
串行时钟同步后
- 仲裁过程在 SDA 上进行,采用有线与(wired-AND)连接方式
- 当多个控制器同时传输数据时,SDA 线的实际状态决定最终的通信结果
在总线仲裁中,通信会持续进行,直到发送的数据出现差异。两个设备同时发送 I²C START,在传输的数据相同时,两个设备共同发送,当数据不同时,发送高电平的设备释放总线,成功赢得仲裁的控制器将继续完成数据传输,而失败的控制器则会停止传输并可能重试通信
-
检测差异
- 在每个数据位传输时,若出现不同控制器发送不同数据位(如一个发送0,另一个发送1),SDA 线路的实际状态将反映有线与的结果(例如0)
-
冲突检测与处理
- 发送1的控制器会检测到 SDA 实际为0,从而识别到冲突
- 检测到冲突的控制器(发送1的控制器)会立即释放总线,停止进一步传输
- 保持SDA为0的控制器(发送0的控制器)继续保持总线控制权,完成通信
仲裁不仅在发送 START 条件时发生,而是在整个数据传输过程中,每个数据位传输时都可能发生仲裁,这意味着即使在传输过程中后续的数据位也可能导致设备释放总线
在图中,两个设备同时发送 I²C START。在传输的前两位数据相同。到第三位时,出现了差异,因为控制器 1 发送了 0,而控制器 2 发送了 1;由于两个控制器都监控 SDA 和 SCL 线路,争用被发现。控制器 2 发现 SDA 是低电平,尽管它发送的是 1。为了保持总线上通信的正确有线与结果,控制器 2 释放总线,而控制器 1 赢得了仲裁
总线仲裁通过有线与结构,天然实现冲突检测与解决,无需额外的硬件或复杂协议,保证只有一个控制器能够控制总线,避免了数据冲突和通信错误,保证了通信的稳定性和可靠性
时钟拉伸
时钟拉伸(Clock Stretching)是 I²C 协议 中的一种可选功能,允许从设备(Slave)在需要时延长 SCL 时钟线的低电平时间,从而暂停数据传输,主要用于以下情况:
-
从设备需要更多时间来处理数据或准备数据
- 当从设备接收到一个字节并确认(ACK)后,可以将 SCL 线拉低,迫使主设备(Master)进入等待状态,直到从设备准备好进行下一个字节传输
-
从设备减慢总线时钟速度
- 具有有限硬件(比如处理器速度慢、操作耗时等)的微控制器可以通过延长每个时钟周期的低电平时间,来减慢总线时钟
工作原理
-
主设备控制时钟线
- 在正常情况下,主设备 负责控制 SCL 时钟线
-
从设备触发时钟拉伸
- 当从设备需要时钟拉伸时,会在确认(ACK)期间将 SCL 线拉低
-
SCL 保持低电平
- 由于 I²C 总线的 SCL 线采用 线与(Wired-AND)连接,SCL 线将保持低电平,直到从设备释放
-
主设备等待 SCL 高电平
- 主设备会监视 SCL 线,并等待其变为 高电平。在从设备释放 SCL 线之前,主设备无法继续传输
-
恢复通信
- 一旦从设备准备好,它会释放 SCL 线,允许其变为 高电平,从而恢复正常通信
主要还是与 I2C 的开漏连接的特点有关
特点与注意事项
-
可选功能
- 并非所有从设备都支持时钟拉伸
-
无限时钟拉伸
- 根据 I²C 规范,从设备可以无限期地保持 SCL 线为低电平
-
单主设备系统
- 如果总线上没有支持时钟拉伸的设备,则主设备可以忽略时钟拉伸处理
-
唯一控制 SCL 的场景
- 时钟拉伸是从设备唯一可以控制 SCL 线的情况
-
UFm 模式不支持
- 在 超快速模式(Ultra Fast-mode, UFm)中,不支持时钟拉伸
电气规格
I²C(Inter-Integrated Circuit)总线的电气规格主要涉及电压、电流、时序和上拉电阻等方面,这些参数对于确保总线正常运行至关重要
电压和逻辑电平
I²C 总线使用开漏输出,这意味着设备只能将线路拉低,而不能主动拉高,线路的拉高是通过上拉电阻实现的
-
逻辑低电平 (VIL) 和逻辑高电平 (VIH) 的阈值不是固定的,而是取决于供电电压 (VDD)
-
输入参考电平通常设置为 VDD 的 30% 和 70%
- VIL (逻辑低电平输入电压) 最大值为 0.3 × VCC
- VIH (逻辑高电平输入电压) 最小值为 0.7 × VCC
-
一些旧设备可能具有固定的输入电平,如 VIL = 1.5V 和 VIH = 3.0V,但新的设备需要符合 30%/70% 的规范
-
-
输出低电平电压 (VOL)
- 在标准模式和快速模式下,VOL 通常为 0.4V
- 在快速模式增强 (Fm+) 下,VOL 可能为 0.4V 或 0.2 × VCC (当 VCC ≤ 2V 时)
电压电平转换
I²C 总线的电压电平转换主要涉及在不同供电电压下工作的 I²C 设备之间进行通信时,如何匹配逻辑电平的问题
逻辑低电平 (VIL) 和 逻辑高电平 (VIH) 的阈值不是固定的,而是取决于供电电压 (VDD),不同 VDD 的设备之间的电压不匹配可能导致通信问题,因此当总线上存在具有不同 VDD 的设备时,需要进行电压电平转换:
- 如果一个 3.3V 的控制器尝试与一个 5V 的目标设备通信,控制器可能无法将总线拉到足够高的电压,以被目标设备识别为逻辑高电平
- 反之,如果一个 5V 的控制器与一个 3.3V 的目标设备通信,控制器可能会将总线电压拉得过高,超出目标设备的最大输入电压范围,从而损坏设备
电平转换方法
-
使用电平转换器:最常见的做法是使用专门的 I²C 电平转换器 IC
- 这些器件可以双向转换电压电平,使得不同电压的设备能够正确通信
- 例如,PCA9306 等器件可以用于电平转换
电压不匹配时可能存在问题
- 通信失败:设备无法正确识别逻辑高电平或低电平,导致数据传输错误
- 设备损坏:过高的输入电压可能会损坏设备的 I/O 引脚
- 系统不稳定:不稳定的信号电平可能导致系统出现意想不到的行为
某些 I²C 设备,例如 ADS1115,其 SDA 和 SCL 引脚具有特殊的电压耐受能力,即使上拉电阻连接到比设备自身供电电压更高的电源电压,这些引脚也能正常工作
ADS1115 的数据手册中明确指出,其数字输入引脚(包括 SDA 和 SCL)的最大输入电压可以达到 5.5V,而不受其自身供电电压的影响
电流
-
低电平输出电流 (IOL):指设备在输出低电平时能够吸收的最大电流。
- 标准模式和快速模式下,IOL 通常为 3mA
- 快速模式增强 (Fm+) 下,IOL 可能为 20mA 或 6mA
-
输入电流 (Ii):指输入引脚的电流,通常很小,例如 ±10μA
时序
I²C 的时序参数定义了 SCL 和 SDA 信号的上升和下降时间、建立时间和保持时间,这些参数对于确保数据传输的正确性和可靠性至关重要,不同的 I²C 速度模式具有不同的时序要求
-
标准模式 (Sm)
- 时钟频率 (fSCL) 最高为 100 kHz
- 上升时间 (tr) 最大为 1000 ns
- 下降时间 (tf) 最大为 300 ns
- 数据建立时间 (tSU;DAT) 最小为 250 ns
-
快速模式 (Fm)
- 时钟频率 (fSCL) 最高为 400 kHz
- 上升时间 (tr) 最大为 300 ns
- 数据建立时间 (tSU;DAT) 最小为 100 ns
-
快速模式+ (Fm+)
- 时钟频率 (fSCL) 最高为 1 MHz
- 上升时间 (tr) 最大为 120 ns
-
高速模式 (Hs-mode)
- 时钟频率 (fSCLH) 最高为 3.4 MHz
- 在总线电容为 100pF 时,上升和下降时间都很快,具体参数可参考表12
- 当总线电容为 400pF 时,时钟频率最大为 1.7 MHz,具体的时序参数需要进行线性插值计算
-
超快速模式 (UFm)
- 时钟频率 (fUSCL) 最高为 5 MHz
- 上升时间和下降时间需要根据器件的电气特性和总线负载来评估
上拉电阻
-
SDA 和 SCL 线上需要 上拉电阻,以确保总线空闲时线路为高电平。
-
电阻值的选择 会影响总线速度和功耗。
- 过大的电阻值 会导致上升时间过长,限制通信速度。
- 过小的电阻值 会增加功耗。
-
上拉电阻的最小值取决于设备的拉低电流和 VOL,最大值取决于上升时间和总线电容。
上拉电阻阻值
正常的上拉电阻建议为 1 kΩ 至 10 kΩ。电阻越高,I2C 通信越慢
电阻越低,I2C 通信需要更多功率。基于几个不同的参数,可以计算出 I2C 总线速度的最小和最大电阻
最小上拉电阻阻值
最小上拉电阻值 (Rp(min)) 的计算基于以下三个关键因素:
- 电源电压 (VCC):这是上拉电阻连接到的电压源
- 器件的输出低电平电压 (VOL):当器件将线路拉低时,线路的电压会下降到接近地电平,但会有一个最小的输出低电平电压 (VOL)
- 器件的下拉电流 (IOL):当器件将线路拉低时,会有一个下拉电流 (IOL) 流过器件
R P ( min ) = VCC − V O L ( max ) I O L R_{P(\text{min})} = \frac{\text{VCC} - V_{OL(\text{max})}}{I_{OL}} RP(min)=IOLVCC−VOL(max)
为了确保设备能够有效地将总线拉低到可被识别为逻辑低的电平 (低于VOL),上拉电阻的值不能太小,如果电阻太小,设备下拉时的电流会过大,导致电压降不够低,无法被接收端识别为低电平
最大上拉电阻
在开漏连接释放输出电流后,上拉电阻通过对总线电容( C B C_B CB)充电,将总线电压拉高至逻辑高电平,由于电容的充电特性,总线上的电压随时间呈现指数上升波形,其上升时间 t RISE t_{\text{RISE}} tRISE 由上拉电阻 R p R_p Rp 和总线电容 C B C_B CB 决定,具体表现为:
由于 I2C 标准规定了最大上升时间,因此最大上拉电阻受到总线电容的限制,电阻越大,上拉输出上升越慢,不能足够快地达到逻辑高电平
上升时间定义为从数字输入低电平电压 (VIL) 的 0.3 倍电源电压过渡到数字输入高电平电压 (VIH) 的 0.7 倍电源电压的时间
随时间变化的指数稳定方程式:
V ( t ) = ( 1 − e − t R C ) × V CC V(t) = \left(1 - e^{-\frac{t}{RC}}\right) \times V_{\text{CC}} V(t)=(1−e−RCt)×VCC
对于上升时间和下降时间,有公式:
V I L = 0.3 × V CC = ( 1 − e − t 1 R p C b ) × V CC V_{IL} = 0.3 \times V_{\text{CC}} = \left(1 - e^{-\frac{t_1}{R_p C_b}}\right) \times V_{\text{CC}} VIL=0.3×VCC=(1−e−RpCbt1)×VCC
V I H = 0.7 × V CC = ( 1 − e − t 2 R p C b ) × V CC V_{IH} = 0.7 \times V_{\text{CC}} = \left(1 - e^{-\frac{t_2}{R_p C_b}}\right) \times V_{\text{CC}} VIH=0.7×VCC=(1−e−RpCbt2)×VCC
由上面两个公式可以得到:
t 1 = − R p C b ⋅ ln ( 0.7 ) t_1 = -R_p C_b \cdot \ln(0.7) t1=−RpCb⋅ln(0.7)
t 2 = − R p C b ⋅ ln ( 0.3 ) t_2 = -R_p C_b \cdot \ln(0.3) t2=−RpCb⋅ln(0.3)
t RISE = t 2 − t 1 = 0.8473 × R p × C b t_{\text{RISE}} = t_2 - t_1 = 0.8473 \times R_p \times C_b tRISE=t2−t1=0.8473×Rp×Cb
R p ( max ) = t RISE 0.8473 × C b R_p(\text{max}) = \frac{t_{\text{RISE}}}{0.8473 \times C_b} Rp(max)=0.8473×CbtRISE
- 当通信速率提高(如进入快速模式或高速模式)时,需要减小 R p R_p Rp 以保证信号满足上升时间的要求
推导过程
-
V ( t ) = V CC ⋅ ( 1 − e − t R p C b ) V(t) = V_{\text{CC}} \cdot \left(1 - e^{-\frac{t}{R_p C_b}}\right) V(t)=VCC⋅(1−e−RpCbt) (电容充电的基本公式,描述随时间 ( t ) 的电压变化)
-
V I L = 0.3 × V CC , V I H = 0.7 × V CC V_{IL} = 0.3 \times V_{\text{CC}}, \quad V_{IH} = 0.7 \times V_{\text{CC}} VIL=0.3×VCC,VIH=0.7×VCC (定义低电平 ( V_IL ) 和高电平 ( V_IH}),分别为 ( V_CC ) 的 30% 和 70%)
-
V I L = V CC ⋅ ( 1 − e − t 1 R p C b ) V_{IL} = V_{\text{CC}} \cdot \left(1 - e^{-\frac{t_1}{R_p C_b}}\right) VIL=VCC⋅(1−e−RpCbt1) (在时间 ( t_1 ) 时,电容电压达到 ( V_IL ))
-
0.3 = 1 − e − t 1 R p C b 0.3 = 1 - e^{-\frac{t_1}{R_p C_b}} 0.3=1−e−RpCbt1 (将 ( V_IL= 0.3 cdot V_textCC ) 代入公式)
-
e − t 1 R p C b = 0.7 e^{-\frac{t_1}{R_p C_b}} = 0.7 e−RpCbt1=0.7 (整理得出指数部分)
-
t 1 = − R p C b ⋅ ln ( 0.7 ) t_1 = -R_p C_b \cdot \ln(0.7) t1=−RpCb⋅ln(0.7) (解出时间 ( t_1 ))
-
V I H = V CC ⋅ ( 1 − e − t 2 R p C b ) V_{IH} = V_{\text{CC}} \cdot \left(1 - e^{-\frac{t_2}{R_p C_b}}\right) VIH=VCC⋅(1−e−RpCbt2) (在时间 ( t_2 ) 时,电容电压达到 ( V_IH ))
-
0.7 = 1 − e − t 2 R p C b 0.7 = 1 - e^{-\frac{t_2}{R_p C_b}} 0.7=1−e−RpCbt2 (将 ( V_IH = 0.7 cdot V_CC ) 代入公式)
-
e − t 2 R p C b = 0.3 e^{-\frac{t_2}{R_p C_b}} = 0.3 e−RpCbt2=0.3 (整理得出指数部分)
-
t 2 = − R p C b ⋅ ln ( 0.3 ) t_2 = -R_p C_b \cdot \ln(0.3) t2=−RpCb⋅ln(0.3) (解出时间 ( t_2 ))
-
t RISE = t 2 − t 1 t_{\text{RISE}} = t_2 - t_1 tRISE=t2−t1 (上升时间定义为从 ( V_{IL} ) 到 ( V_{IH} ) 的时间差)
-
t RISE = R p C b ⋅ ln ( 0.7 0.3 ) t_{\text{RISE}} = R_p C_b \cdot \ln\left(\frac{0.7}{0.3}\right) tRISE=RpCb⋅ln(0.30.7) (通过整理 ( t_2 - t_1 ) 推导得到)
-
t RISE = 0.8473 ⋅ R p ⋅ C b t_{\text{RISE}} = 0.8473 \cdot R_p \cdot C_b tRISE=0.8473⋅Rp⋅Cb (计算 ( ln(2.3333)) 得到最终公式)
上升时间取决于 I2C 模式
即使 V C C V_{CC} VCC 发生变化,只要门限比例( 0.3 × V C C 0.3 \times V_{CC} 0.3×VCC 和 0.7 × V C C 0.7 \times V_{CC} 0.7×VCC)不变,公式依然成立,因为充电时间由 R p R_p Rp 和 C b C_b Cb 决定,而不是 V C C V_{CC} VCC 的绝对值
如果 V I L V_{IL} VIL 和 V I H V_{IH} VIH 的门限比例改变,公式中的 0.8473 0.8473 0.8473 系数需要重新计算(可能会有这种情况,但是我没找到)
当使用 Vcc = 3.3V 标准模式时,将 1000 纳秒的上升时间除以 0.8473 × 400 pF 0.8473 \times 400 \, \text{pF} 0.8473×400pF,得出最大上拉电阻为 2.95 kΩ,最小电阻 967 Ω
R p ( max ) = 1000 ns 0.8473 ⋅ 400 pF ≈ 2.95 k Ω R_p(\text{max}) = \frac{1000 \, \text{ns}}{0.8473 \cdot 400 \, \text{pF}} \approx 2.95 \, \text{k}\Omega Rp(max)=0.8473⋅400pF1000ns≈2.95kΩ
R P ( min ) = VCC − V O L ( max ) I O L = 3.3 V − 0.4 V 3 mA = 2.9 V 3 mA = 967 Ω R_{P(\text{min})} = \frac{\text{VCC} - V_{OL(\text{max})}}{I_{OL}} = \frac{3.3 \, \text{V} - 0.4 \, \text{V}}{3 \, \text{mA}} = \frac{2.9 \, \text{V}}{3 \, \text{mA}} = 967 \, \Omega RP(min)=IOLVCC−VOL(max)=3mA3.3V−0.4V=3mA2.9V=967Ω
对于最小电阻 967 Ω 和最大电阻 2.95 kΩ,这些值看起来为电阻提供了一个较窄的范围。然而,这个小范围是因为上拉电阻的大小是基于最大标准模式总线电容 400 pF 计算的。而 400 pF 的总线电容实际上非常大,尤其对于板上的寄生电容来说。如果设计中总线电容较低(这更常见),则最大电阻可以增加,从而减少 I2C 总线上消耗的功率。
对于标准模式,上升时间为 1000 纳秒,使用 400 pF 的最大总线电容,最大电阻计算结果约为 2.95 kΩ
实际应用中,总线电容通常小于最大值,因此可以使用更大的电阻以降低功耗
总线电容
-
I²C 总线上的 总电容 限制了可以连接到总线的设备数量
- 总线电容 (Cb) 指的是 SDA 和 SCL 线上所有连接设备的电容之和,以及 PCB 走线和其他寄生电容
-
不同的 I²C 速度模式有不同的最大总线电容限制
- 标准模式和快速模式下,最大总线电容为 400 pF
- 快速模式增强 (Fm+) 下,最大总线电容为 550 pF
- 高速模式下,最大总线电容可达 400 pF,但时序参数会受到影响。
其他电气特性
-
输入电容 (Ci): 每个 I/O 引脚的电容,通常为 10pF
-
噪声容限: 总线上噪声的容限范围,分为低电平噪声容限 (VnL) 和高电平噪声容限 (VnH)
- VnL 为 0.1 × VDD
- VnH 为 0.2 × VDD
不同的设备对电气特性的要求可能不同,具体需要查阅设备的技术手册
相关文章:
I2C学习笔记
前言 我一直不是特别喜欢读文档,习惯了通过视频学习,因为视频能更直观地展现信息,给人一种更生动、形象的感觉。然而,随着学习的内容逐渐增多,我发现并不是所有的知识点都能在视频中找到,或者视频中展示的…...
JetPack——ViewModel
前提阅读 JetPack——Lifecycle Jetpack——LiveData ViewModel是什么? ViewModel 类是一种业务逻辑或屏幕级状态容器。它用于将状态公开给界面,以及封装相关的业务逻辑。 它的主要优点是,它可以缓存状态,并可在配置更改后持久…...
【Java 学习】对象赋值的艺术:Java中clone方法的浅拷贝与深拷贝解析,教你如何在Java中实现完美复制
💬 欢迎讨论:如对文章内容有疑问或见解,欢迎在评论区留言,我需要您的帮助! 👍 点赞、收藏与分享:如果这篇文章对您有所帮助,请不吝点赞、收藏或分享,谢谢您的支持&#x…...
【计算机网络】课程 实验四 配置快速生成树协议(RSTP)
实验四 配置快速生成树协议(RSTP) 一、实验目的 1.理解快速生成树协议RSTP的工作原理。 2.掌握如何在交换机上配置快速生成树。 二、实验分析与设计 【背景描述】 某学校为了开展计算机教学和网络办公,建立了一个计…...
SpringBootWeb案例-1(day10)
准备工作 需求 & 环境搭建 需求说明 环境搭建 步骤: 准备数据库表(dept、emp)创建 springboot 工程,引入对应的起步依赖(web、mybatis、mysql 驱动、lombok)配置文件 application.properties 中引入 mybatis 的配置信息&…...
攻防世界 Web_php_wrong_nginx_config
打开题目地址,显示为登录页面。尝试用御剑扫描一下,发现了admin页面,点进去显示如下 点开控制台,发现如下 isLogin参数为0。尝试抓包并该islogin参数为1,返回依旧不变。 再扫描,发现robots.txtÿ…...
【VUE+ElementUI】通过接口下载blob流文件设置全局Loading加载进度
下载Blob流文件,并以服务形式显示文件下载进度 1、下载接口 增加 config参数,并用...config将该属性加入到请求中; xxapi.js文件中设置downloadFile下载接口 // 下载文件 export function downloadFile(data, config) {return request({ur…...
行为树详解(6)——黑板模式
【动作节点数据共享】 行为树中需要的参数可以来自游戏中的各个模块,如果仅需从多个模块获取少量参数,那么可以直接在代码中调用其他模块的单例继而层层调用获取数据。 如果获取的参数量很大,从架构上看,我们需要通过加一个中间…...
【prometheus】Pushgateway安装和使用
目录 一、Pushgateway概述 1.1 Pushgateway简介 1.2 Pushgateway优点 1.3 pushgateway缺点 二、测试环境 三、安装测试 3.1 pushgateway安装 3.2 prometheus添加pushgateway 3.3 推送指定的数据格式到pushgateway 1.添加单条数据 2.添加复杂数据 3.SDk-prometheus-…...
耗时一天,我用AI开发了AI小程序
小码哥从事前后端开发近十年,但是随着技术的更新迭代,有时候没有时间和精力去优化UI、实现一些前后端功能,以及解决一些bug。特别是我想开发小码哥AI的移动端,但觉得自己没有那么多时间去研究移动端了,准备放弃了&…...
Java 日期时间格式化标准
文章目录 Java日期时间格式化符号ISO 8601中的日期时间ISO 8601标准的定义ISO 8601日期时间格式 周数年份ISO 8601中的周数年份Java中的周数年份 Java跨年日期格式化BUG注意事项 Java日期时间格式化符号 JDK官网截图: 格式化符号梳理: 符号描述符号用…...
undolog,redolog,binlog分别是做什么的?
在数据库系统中(尤其是 MySQL),Undo log、Redo log 和 Binlog 是用于实现数据持久性和一致性的重要日志机制。 1. Undo Log(回滚日志) 功能: 用于事务回滚:记录事务开始前的状态,以…...
NRF24L01模块STM32-接收端
前言 在调试接收端时,建议先看下下篇文章NRF24L01调试心得 环境: 芯片:STM32F103C8T6 Keil:V5.24.2.0 一、接收端初始化 void NRF24l01_rx_mode(void) {NRF24L01_CE(0);NRF24l01_write_buf(NRF_WRITE_REG TX_ADDR, (uint8_t *)TX_ADDRE…...
核磁机器学习 | 机器学习和深度学习算法在fMRI中的应用
摘要 功能磁共振成像(fMRI)是目前应用最广泛的脑图像动态分析技术之一,通常结合多种算法来分析复杂的动态数据。近年来,机器学习和深度学习算法在分析fMRI数据方面的应用呈指数级增长。然而,由于文献中存在大量算法,选择合适的机器…...
【数据结构-堆】力扣3296. 移山所需的最少秒数
给你一个整数 mountainHeight 表示山的高度。 同时给你一个整数数组 workerTimes,表示工人们的工作时间(单位:秒)。 工人们需要 同时 进行工作以 降低 山的高度。对于工人 i : 山的高度降低 x,需要花费 workerTimes…...
web前端-html
HTML部分 HTML:超文本标记语言。是万维网web编程的基础,web是建立在超文本基础上的。HTML 是万维网的基石 打开www.baidu.com的页面源代码可见 超文本标记超的含义 1.最重要的标签,超链接标签,可跳转页面,关联所有页…...
单片机-定时器中断
1、相关知识 振荡周期1/12us; //振荡周期又称 S周期或时钟周期(晶振周期或外加振荡周期)。 状态周期1/6us; 机器周期1us; 指令周期1~4us; ①51单片机有两组定时器/计数器,因为既可以定时,又可以计数,故称之为定时器…...
计算机网络 (31)运输层协议概念
一、概述 从通信和信息处理的角度看,运输层向它上面的应用层提供通信服务,它属于面向通信部分的最高层,同时也是用户功能中的最低层。运输层的一个核心功能是提供从源端主机到目的端主机的可靠的、与实际使用的网络无关的信息传输。它向高层用…...
【学Rust开发CAD】2 创建第一个工作空间、项目及库
文章目录 一、 创建工作空间二、新建项目(可执行文件)三、 新建库(库文件)四、更新项目依赖五、编写代码七、总结 在 Rust 中,工作空间(workspace)允许你管理多个相关的包(crate&…...
使用GitLab+Jenkins搭建CICD执行环境
使用GitLabJenkins搭建CI\CD执行环境 前言什么是DevOps?什么是CI/CD?使用GitLabJenkins搭建CI\CD执行环境GitLab安装1. 安装和配置所需的依赖2. 下载并安装极狐GitLab3. 登录极狐GitLab 实例4.常用gitlab指令5.修改密码 Jenkins安装1.Jenkins 的主要特点…...
微信小程序——创建滑动颜色条
在微信小程序中,你可以使用 slider 组件来创建一个颜色滑动条。以下是一个简单的示例,展示了如何实现一个颜色滑动条,该滑动条会根据滑动位置改变背景颜色。 步骤一:创建小程序项目 首先,使用微信开发者工具创建一个…...
Mac中配置vscode(第一期:python开发)
1、终端中安装 xcode-select --install #mac的终端中安装该开发工具 xcode-select -p #显示当前 Xcode 命令行工具的安装路径注意:xcode-select --install是在 macOS 上安装命令行开发工具(Command Line Tools)的关键命令。安装的主要组件包括:C/C 编…...
Next.js 实战 (七):浅谈 Layout 布局的嵌套设计模式
业务场景 在目前常见的中后台管理系统中,比较常见的是固定的布局方式包裹页面,但一些特殊页面,比如:登录页面、注册页面、忘记密码页面这些页面是不需要布局包裹的。 但在 Next.js AppRouter 中,必须包含一个根布局文…...
Linux环境下确认并操作 Git 仓库
在软件开发和版本控制中,Git 已成为不可或缺的工具。有时,我们需要确认某个目录是否是一个 Git 仓库,并在该目录中运行脚本。本文将详细介绍如何确认 /usr/local/src/zcxt/backend/policy-system-backend 目录是否是一个 Git 仓库,…...
海陵HLK-TX510人脸识别模块 stm32使用
一.主函数 #include "stm32f10x.h" // Device header #include "delay.h" #include "lcd.h" #include "dht11.h" #include "IOput.h" #include "usart.h" //#include "adc.h" …...
MATLAB语言的正则表达式
MATLAB 中的正则表达式使用指南 引言 在数据处理和文本分析中,正则表达式是一种强大而灵活的工具。MATLAB 作为一种广泛应用于科学计算和数据分析的编程语言,提供了对正则表达式的支持,使得用户可以方便地进行字符串匹配与处理。本文将深入…...
【CVPR 2024】【遥感目标检测】Poly Kernel Inception Network for Remote Sensing Detection
0.论文摘要 摘要 遥感图像(RSIs)中的目标检测经常面临几个日益增加的挑战,包括目标尺度的巨大变化和不同范围的背景。现有方法试图通过大核卷积或扩张卷积来扩展主干的空间感受野来解决这些挑战。然而,前者通常会引入相当大的背…...
笔记-使用ffmpeg产生rtsp视频流,然后用进行VLC播放
笔记-使用ffmpeg产生rtsp视频流,然后用进行VLC播放 1.软件配置1.1下载安装好**ffmpeg**1.2使用EasyDarwin创建RTSP服务器 2.FFmpeg找本地摄像头名字3.FFmpeg推流命令3.1使用VLC实现拉流 1.软件配置 1.1下载安装好ffmpeg ffmpeg官网 本地下载 1.2使用EasyDarwin创…...
Ubuntu20.04中EasyConnect启动报错
安装路径 /usr/share/sangfor/EasyConnect 方法 通过 ./EasyConnect获得错误代码,其中‘Failed to load module "canberra-gtk-module"’可以忽略,主要是‘Harfbuzz version too old (1.3.1)’这个问题,后边的版本号可能因系统不…...
计算机毕业设计Python中华古诗词知识图谱可视化 古诗词智能问答系统 古诗词数据分析 古诗词情感分析模型 自然语言处理NLP 机器学习 深度学习
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
Excel | 空格分隔的行怎么导入excel?
准备工作:windows,一个记事本程序和微软的Excel软件。 打开记事本,选中所有内容,按CtrlA全选,然后复制(CtrlC)。 在Excel中,定位到你想粘贴的单元格,按CtrlV进行粘贴。粘贴后,你会在…...
【形式篇】年终总结怎么写:PPT如何将内容更好地表现出来
——细节满满,看完立马写出一篇合格的PPT 总述 形式服务于内容,同时合理的形式可以更好地表达和彰显内容 年终总结作为汇报型PPT,内容一定是第一位的,在内容篇(可点击查看)已经很详细地给出了提纲思路,那如何落实到…...
Python生日祝福烟花
1. 实现效果 2. 素材加载 2个图片和3个音频 shoot_image pygame.image.load(shoot(已去底).jpg) # 加载拼接的发射图像 flower_image pygame.image.load(flower.jpg) # 加载拼接的烟花图 烟花不好去底 # 调整图像的像素为原图的1/2 因为图像相对于界面来说有些大 shoo…...
(六)CAN总线通讯
文章目录 CAN总线回环测试第一种基于板载CAN测试第一步确认板载是否支持第二步关闭 CAN 接口将 CAN 接口置于非活动状态第三步 配置 CAN 接口第一步 设置 CAN 接口比特率第二步 设置 CAN 启用回环模式第三步 启用 CAN 接口 第四步 测试CAN总线回环捕获 CAN 消息发送 CAN 消息 第…...
python.exe无法找到程序入口 无法定位程序输入点(Anaconda Prompt报错)
参考 总结: (1)pythoncom36.dll是pywin32的一个文件,位于路径Anaconda3\envs\pytorch(你的虚拟环境)\Lib\site-packages\pywin32_system32中; (2)但在Anaconda3\envs\pytorch\Library\bin中也…...
C++网络程序设计
在C网络编程中,使用Berkeley Sockets API是一种常见的方法来实现跨平台的TCP通信。Berkeley Sockets API最初是在UNIX系统上开发的,但它已经被广泛移植到其他操作系统,包括Windows。 示例代码 client.cpp #include <iostream> #incl…...
【快速实践】深度学习 -- 数据曲线平滑化
希望对你有帮助呀!!💜💜 如有更好理解的思路,欢迎大家留言补充 ~ 一起加油叭 💦 欢迎关注、订阅专栏 【深度学习从 0 到 1】谢谢你的支持! 在观察数据结果时,我们通常希望获得整体趋…...
【强化学习】演员评论家Actor-Critic算法(万字长文、附代码)
📢本篇文章是博主强化学习(RL)领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅…...
Kubernetes Gateway API-5-后端协议和网关基础设置标签
1 后端协议 自 v1.2.0 开始支持 并非所有网关API实现都支持自动协议选择。在某些情况下,协议在没有明确选择加入的情况下被禁用。 当 Route 的后端引用Kubernetes Service 时,应用程序开发人员可以使用 ServicePort appProtocol 字段指定协议。 例如…...
鸿蒙 ArkUI实现地图找房效果
常用的地图找房功能,是在地图上添加区域、商圈、房源等一些自定义 marker,然后配上自己应用的一些筛选逻辑构成,在这里使用鸿蒙 ArkUI 简单实现下怎么添加区域/商圈、房源等 Marker. 1、开启地图服务 在华为开发者官网,注册应用&…...
前后端分离架构设计与实现:构建现代Web应用的基石
前后端分离架构设计与实现:构建现代Web应用的基石 引言 随着互联网技术的发展,Web应用变得越来越复杂和多样化。传统的单体式架构难以满足快速迭代、团队协作以及性能优化的需求。前后端分离架构应运而生,它不仅提高了开发效率,…...
【51单片机】02LED流水灯实验
点亮你的LED 一、点亮第一个LED1.GPIO介绍2.P1、P2、P3端口 二、LED实验2.尝试点亮LED3.LED流水灯4.利用库函数实现流水灯的移动 一、点亮第一个LED 1.GPIO介绍 这块内容这里可以做简单的了解,与数电知识强相关。后续可以再回过头来学习 GPIO (general purpose in…...
【简博士统计学习方法】第1章:4. 模型的评估与选择
4. 模型的评估与选择 4.1 训练误差与测试误差 假如存在样本容量为 N N N的训练集,将训练集送入学习系统可以训练学习得到一个模型,我们将这么模型用决策函数的形式表达,也就是 y f ^ ( x ) y\hat{f}(x) yf^(x),关于模型的拟合…...
GitLab创建用户,设置访问SSH Key
继上一篇 Linux Red Hat 7.9 Server安装GitLab-CSDN博客 安装好gitlab,启用管理员root账号后,开始创建用户账户 1、创建用户账户 进入管理后台页面 点击 New User 输入用户名、邮箱等必填信息和登录密码 密码最小的8位,不然会不通过 拉到…...
flutter 专题二十四 Flutter性能优化在携程酒店的实践
Flutter性能优化在携程酒店的实践 一 、前言 携程酒店业务使用Flutter技术开发的时间快接近两年,这期间有列表页、详情页、相册页等页面使用了Flutter技术栈进行了跨平台整合,大大提高了研发效率。在开发过程中,也遇到了一些性能相关问题和…...
RAFT:随机退火森林
RAFT:随机退火森林 RAFT(Randomized Annealed Forests)是一种机器学习算法,主要用于分类和回归任务。以下是对它的介绍及原理举例说明: 一、RAFT简介 RAFT是一种基于随机森林的集成学习方法,它结合了随机森林的优点和退火算法的思想。随机森林通过构建多个决策树并综…...
上下游服务间解耦的技术与管理
一、解耦为何至关重要 在当今软件研发的复杂生态中,耦合问题如影随形,困扰着众多开发者与企业。当多个模块、系统或团队紧密交织,相互依赖程度不断攀升,仿佛一张错综复杂的网,牵一发而动全身。就拿电商系统来说&#…...
[桌面运维]windows自动设置浅深色主题
设置自动浅色/深色主题 我看很多up主的教程过于繁琐,需要添加四个功能,并且有些还不能生效! 大多数都是教程: 自动任务栏浅色 add HKCUSOFTWAREMicrosoftWindowsCurrentVersionThemesPersonalize/v SystemUsesLightTheme /t …...
【Spring】Spring DI(依赖注入)详解——注入参数的细节处理-内部Bean的注入
引言 在现代Java开发中,Spring框架已经成为了构建企业级应用的标准工具之一。Spring的核心特性之一就是依赖注入(Dependency Injection,DI),它通过将对象的依赖关系从代码中解耦出来,提升了代码的可维护性…...
Docker: 教程07 - ( 如何对 Docker 进行降级和升级)
如果我们使用 docker 来管理容器,那么保持 docker 引擎的更新将会是十分重要的,这一篇文章我们将会讨论如何对Docker 进行降级和升级。 准备工作 - docker 环境 我们需要拥有一个安装好 docker 的运行环境。 如果你需要了解如何安装 docker 可以通过如…...