news 2026/9/26 1:14:44

I2C多主机仲裁与时钟延展:开漏输出、线与逻辑及总线冲突调试实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
I2C多主机仲裁与时钟延展:开漏输出、线与逻辑及总线冲突调试实战

1. 为什么多主机仲裁是 I2C 的灵魂设计

I2C 总线最容易被低估的部分,不是读写时序,也不是 ACK/NACK,而是它天生支持多主机共享同一组信号线。你想想看,一根 SDA、一根 SCL,挂上几个甚至十几个主控芯片,谁想发数据就发数据,居然不会把总线烧掉,也不会出现两个主机同时输出高电平打架的情况。这背后靠的就是多主机仲裁和时钟延展这两套机制。

我第一次认真研究这部分,是因为一个项目里两块 MCU 都要访问同一片 EEPROM。当时想得很简单,分时复用不就行了?结果发现一块 MCU 在复位释放后偶尔会误判总线空闲,直接开始发 START,和另一块 MCU 撞在一起。示波器抓下来一看,SDA 上出现了半高电平的毛刺,但两块 MCU 都没有损坏,其中一个自动退出了发送。这就是仲裁在起作用。

I2C 的多主机仲裁之所以精妙,是因为它不需要额外的仲裁线、不需要令牌、不需要主机地址。它把仲裁和时钟同步都“藏”在了两根线的电气特性里。理解这一点,你才能真正明白为什么 I2C 用两根线就能撑起一个多主多从的系统,也才能在实际调试中快速定位“总线锁死”“数据错乱”“某个主机莫名丢失”的问题。

这篇文章我会从开漏输出讲起,把线与逻辑、时钟同步、逐位仲裁、时钟延展、仲裁失败后的处理,以及实际调试中踩过的坑,全部拆开讲清楚。适合已经会写 I2C 读写代码、但想搞明白底层为什么这么设计的嵌入式工程师,也适合正在调试多主机 I2C 系统、被总线冲突折磨的同行。

2. 开漏输出与线与逻辑:仲裁的物理基础

2.1 开漏输出到底解决了什么问题

很多人学 I2C 第一课就是“I2C 的 SDA 和 SCL 必须接上拉电阻,因为它们是开漏输出”。但为什么必须是开漏?推挽输出不行吗?

推挽输出的结构是上下两个 MOS 管,上管导通输出高,下管导通输出低。问题在于,如果两个主机同时推挽输出,一个输出高、一个输出低,那就等于电源和地之间直接串了一条低阻通路,瞬间大电流,芯片轻则发热,重则烧毁。你可以把它想象成两个人同时抢一扇门,一个往里推、一个往外拉,门没坏是运气,坏了是常态。

开漏输出只保留了下管,上管永远关闭。输出高电平时,实际上是把引脚“释放”掉,让上拉电阻把线拉高;输出低电平时,下管导通,把线拉到地。这样一来,任何一方输出低电平,总线就是低;只有所有方都释放,总线才被上拉电阻拉高。这就是线与逻辑。

用一句话总结:开漏输出让“低电平”具有压倒性优先级,任何设备都能安全地把总线拉低,而不会和别的设备产生电源冲突。

2.2 上拉电阻选型:不是随便放一个 4.7k 就完事

上拉电阻的取值直接决定了总线能否正常工作。很多人抄参考设计,看到 4.7k 就跟着用,结果在高速模式或者长走线下频繁出错。

上拉电阻的上限由上升时间决定。I2C 标准里,标准模式 100kHz 下,上升时间 tr 最大 1000ns;快速模式 400kHz 下,最大 300ns。总线电容 Cb 包括引脚电容、走线电容、器件电容,通常按 10pF 到 400pF 估算。上升时间近似为:

tr ≈ 0.847 × Rp × Cb

假设 Cb = 200pF,快速模式要求 tr ≤ 300ns,那么 Rp ≤ 300ns / (0.847 × 200pF) ≈ 1.77kΩ。如果你还用 4.7k,上升时间会到约 800ns,边沿太缓,接收端可能采样错误。

上拉电阻的下限由灌电流决定。I2C 规定器件拉低时,VOL 最大 0.4V,灌电流在标准模式下最大 3mA,快速模式下 6mA。如果电源 3.3V,Rp 最小为 (3.3 - 0.4) / 3mA ≈ 967Ω。所以 1k 到 2.2k 是比较稳妥的范围,具体要看总线电容和速率。

我一般会这样选:先按 100pF 估算,标准模式用 4.7k,快速模式用 2.2k,高速模式用 1k 以内。如果走线长、挂载多,先用示波器测上升时间,再决定是否减小电阻。注意,减小电阻会增加功耗,电池供电的设备要权衡。

2.3 线与逻辑如何支撑仲裁

有了线与逻辑,仲裁就变得非常自然。每个主机在发送每一位时,都会先输出自己想要的位,然后读回 SDA 的实际电平。如果自己输出的是高,但读回来是低,说明有别的设备把它拉低了,自己就输了仲裁,立刻退出。

这里的关键是:仲裁只发生在主机之间,而且输的一方不会破坏赢的一方的数据。因为输的一方在发现自己输出高但读回低的那一刻,就停止驱动 SDA 和 SCL,转为接收状态。赢的一方甚至不知道发生过仲裁,数据继续正常发送。

你可以把仲裁想象成一群人在同一根绳子上拉低电平,谁想拉高谁就松手。松手的人发现绳子还是低的,就知道有人还在拉,自己主动退出。整个过程没有碰撞、没有重传、没有数据损坏。

3. 时钟同步:SCL 上的分布式协商

3.1 时钟同步是怎么发生的

多主机系统中,每个主机都有自己的 SCL 时钟。如果两个主机同时开始发送,它们的时钟频率和相位可能不同。I2C 没有中央时钟,那 SCL 上的时钟是谁的?

答案是:所有主机的 SCL 叠加后的结果。因为 SCL 也是开漏线与,任何一个主机拉低,SCL 就是低;只有所有主机都释放,SCL 才被上拉电阻拉高。

这就形成了一个天然的同步机制。假设主机 A 的时钟周期比主机 B 短,A 想更快地拉高 SCL,但只要 B 还在低电平阶段,SCL 就保持低。A 必须等 B 释放 SCL 后,才能看到 SCL 变高。反过来,B 拉低 SCL 时,A 也会被拉低。最终 SCL 的低电平时间是所有主机中低电平最长的那个,高电平时间是最短的那个。

用示波器看,SCL 的波形像是所有主机时钟的“与”结果。低电平被拉长,高电平被缩短,整体频率由最慢的主机决定。这就是时钟同步。

3.2 时钟同步对仲裁的影响

时钟同步保证了所有主机在相同的 SCL 节拍下采样 SDA。如果没有时钟同步,两个主机各自按自己的时钟采样,仲裁就会乱套。比如 A 在第 3 个时钟沿采样,B 在第 5 个时钟沿采样,它们对同一位的判断可能不一致。

有了时钟同步,所有主机都在 SCL 高电平期间采样 SDA。仲裁的规则是:在 SCL 高电平期间,SDA 必须稳定;如果某个主机输出高但读回低,它就在这个高电平期间退出。这样所有主机对仲裁结果的判断是一致的。

我实测过一个场景:两块 MCU 分别用 100kHz 和 400kHz 的时钟同时发起传输。示波器上 SCL 的低电平明显被 100kHz 那块拉长,高电平被 400kHz 那块缩短,最终总线速率介于两者之间。仲裁在第一个字节的地址位就完成了,400kHz 那块因为地址位不匹配主动退出,100kHz 那块继续完成传输。

3.3 时钟延展:从机的“暂停键”

时钟延展是 I2C 另一个精妙设计,它允许从机在需要更多时间处理数据时,主动拉低 SCL,迫使主机等待。

典型场景:主机发送一个字节后,从机需要时间把数据写入内部 EEPROM。EEPROM 的写周期可能长达 5ms,而从机在 ACK 之后如果立即释放 SCL,主机可能马上开始下一个字节。从机来不及处理,就会丢数据。有了时钟延展,从机可以在 ACK 之后继续拉低 SCL,主机检测到 SCL 还是低,就会等待,直到从机释放。

时钟延展的实现很简单:从机在需要延展时,把 SCL 引脚配置为开漏输出并输出低。主机在释放 SCL 后,会读回 SCL 电平,如果发现还是低,就知道从机在延展,继续等待。主机不需要知道从机要延展多久,只需要等 SCL 真正变高。

这里有个容易踩的坑:不是所有主机都支持时钟延展。有些硬件 I2C 控制器在发送完一个字节后,会强制拉高 SCL 一段时间,如果从机还在拉低,控制器可能报总线错误或者超时。我在用某款国产 MCU 的硬件 I2C 时就遇到过,从机是软件模拟的,写 EEPROM 时延展了 3ms,结果主机直接报 NACK 超时。后来改成软件模拟 I2C,问题消失。

所以,如果你的系统里有从机会做时钟延展,选主机时一定要确认它的 I2C 控制器支持时钟延展,或者干脆用 GPIO 模拟。

4. 逐位仲裁的完整过程拆解

4.1 仲裁的启动条件

仲裁只在多个主机同时发起传输时发生。如果总线上只有一个主机,或者两个主机错开了时间,就不会有仲裁。

两个主机同时发起传输的条件是:它们都在总线空闲时检测到 SDA 和 SCL 为高,然后都在规定的保持时间后拉低 SDA 发出 START。由于传播延迟和检测时间的微小差异,两个主机可能几乎同时发出 START。这时候,仲裁从 START 之后的第一个位开始。

注意,START 本身不参与仲裁。两个主机都拉低 SDA,总线就是低,大家都认为 START 有效。仲裁从地址位开始。

4.2 地址位仲裁

假设主机 A 要访问地址 0x50,主机 B 要访问地址 0x52。地址是 7 位,加上读写位,共 8 位。两个主机同时发送地址。

第一位:A 发 0,B 发 0,SDA 为低,双方读回都是低,继续。 第二位:A 发 1,B 发 1,SDA 被释放,上拉为高,双方读回都是高,继续。 第三位:A 发 0,B 发 0,继续。 第四位:A 发 1,B 发 1,继续。 第五位:A 发 0,B 发 0,继续。 第六位:A 发 0,B 1?这里要看具体地址。0x50 是 1010000,0x52 是 1010010。从高位到低位:A 的地址位是 1,0,1,0,0,0,0;B 是 1,0,1,0,0,1,0。

前五位相同:1,0,1,0,0。第六位:A 发 0,B 发 1。A 拉低 SDA,B 释放 SDA。总线为低。B 读回 SDA 发现是低,但自己输出的是高,B 知道自己输了仲裁,立即退出,转为接收状态。A 继续发送第七位和读写位。

整个过程,A 甚至不知道 B 存在过。B 退出后,A 的传输不受任何影响。

4.3 数据位仲裁

如果两个主机的地址相同,仲裁会继续到数据位。比如两个主机都要写同一个从机,但写的数据不同。仲裁会在数据位继续,直到某一位出现差异。

这里有一个重要规则:仲裁可以发生在地址位,也可以发生在数据位,但不能发生在 ACK 位。因为 ACK 是由从机拉低的,如果两个主机都发送完地址后,从机拉低 SDA 表示 ACK,这时候两个主机都读回低,但这不是仲裁,而是从机的响应。如果某个主机在 ACK 位输出了高,但读回低,它不会认为自己输了仲裁,因为 ACK 位本来就应该由从机拉低。

所以,仲裁失败的主机在退出时,必须确保自己不再驱动 SDA 和 SCL。如果它继续驱动 SCL,可能会干扰赢的主机的时钟。好在 I2C 规范要求仲裁失败的主机立即释放总线,转为从机接收模式。

4.4 仲裁失败后的处理

仲裁失败的主机不会丢失数据,但它需要重新发起传输。通常的做法是:仲裁失败的主机切换到从机模式,接收赢的主机的完整传输,然后在总线空闲后重新尝试发送。

这里有一个实际调试中的经验:仲裁失败的主机如果立即重试,可能会再次冲突。因为赢的主机可能还在传输,总线还没空闲。正确的做法是等待一个总线空闲周期,或者等待一个随机退避时间。有些 I2C 控制器硬件会自动处理重试,有些需要软件干预。

我在一个多主机项目里,两块 MCU 都会周期性写 EEPROM。一开始没做退避,结果两块 MCU 频繁仲裁,虽然数据没丢,但总线利用率很低。后来加了一个简单的退避:仲裁失败后等待 1ms 到 5ms 的随机时间再重试,冲突概率大幅下降。

5. 时钟延展的实操细节与常见误区

5.1 从机如何正确实现时钟延展

从机实现时钟延展,关键是在正确的时间拉低 SCL。通常是在 ACK 阶段之后,从机需要处理数据时,把 SCL 拉低。具体步骤:

  1. 从机接收完一个字节,准备发送 ACK。
  2. 从机拉低 SDA 表示 ACK。
  3. 从机在 SCL 的下降沿之后,继续拉低 SCL。
  4. 主机释放 SCL,但发现 SCL 还是低,开始等待。
  5. 从机处理完数据,释放 SCL。
  6. 主机检测到 SCL 变高,继续下一个时钟。

注意,从机拉低 SCL 的时机必须在 SCL 低电平期间。如果在 SCL 高电平期间拉低,可能会被主机误判为 START 或 STOP 条件。

5.2 主机如何应对时钟延展

主机在释放 SCL 后,必须读回 SCL 电平。如果 SCL 还是低,说明从机在延展,主机需要继续等待。等待时间没有上限,但实际实现中通常会加一个超时,防止从机故障导致总线死锁。

硬件 I2C 控制器通常会自动处理时钟延展,但有些控制器的超时时间很短,比如 25ms。如果从机延展超过这个时间,控制器会报错。软件模拟 I2C 则完全由代码控制,可以灵活设置超时。

我一般会在软件模拟 I2C 里加一个循环计数,比如等待 SCL 变高最多 10000 次循环。如果超时,就报错并复位总线。这样既能支持正常的时钟延展,又能防止死锁。

5.3 时钟延展与仲裁的交互

时钟延展和仲裁可以同时发生。比如两个主机在仲裁,其中一个从机在延展 SCL。这时候 SCL 的低电平时间会被从机拉长,仲裁的节奏也会变慢。但仲裁逻辑不受影响,因为仲裁是在 SCL 高电平期间采样 SDA。

有一个细节:如果仲裁失败的主机在退出时,从机还在延展 SCL,失败的主机必须释放 SCL,让从机继续延展。如果失败的主机继续拉低 SCL,会干扰赢的主机和从机的通信。

6. 多主机仲裁的典型问题与排查技巧

6.1 总线锁死:最常见也最头疼

总线锁死的表现是 SDA 或 SCL 被某个设备持续拉低,总线无法空闲。原因可能是:

  • 某个从机在传输过程中复位,SDA 保持低。
  • 主机在仲裁失败后没有正确释放总线。
  • 时钟延展超时,从机一直拉低 SCL。

排查方法:先断电,用万用表测 SDA 和 SCL 对地电阻。如果某个线对地短路,说明有器件损坏。如果电阻正常,上电后用示波器看波形。如果 SDA 一直低,尝试发送 9 个时钟脉冲,让从机完成当前字节并释放 SDA。如果 SCL 一直低,检查从机的时钟延展逻辑。

我遇到过一次总线锁死,原因是从机在写 EEPROM 时被复位,SDA 保持低。后来在主机初始化时加了一个总线恢复流程:先发送 9 个 SCL 脉冲,再发送 STOP 条件,总线就恢复了。

6.2 仲裁失败导致的数据错乱

仲裁失败的主机如果处理不当,可能会把赢的主机的数据当成自己的数据。比如,失败的主机在退出后没有切换到接收模式,继续按自己的节奏采样 SDA,结果读到的数据是赢的主机的数据,导致状态机错乱。

解决方法:仲裁失败后,立即复位本地 I2C 状态机,清空发送缓冲区,等待总线空闲后重新发起传输。不要试图从当前传输中恢复。

6.3 时钟同步导致的速率下降

多主机系统中,SCL 的实际频率由最慢的主机决定。如果有一个主机用 100kHz,另一个用 400kHz,总线实际速率会接近 100kHz。这不是故障,而是时钟同步的正常结果。

如果你需要高速传输,确保所有主机的时钟频率一致,或者至少不要相差太大。另外,从机的时钟延展也会拉低有效速率,选从机时要注意它的最大延展时间。

6.4 常见问题速查表

现象可能原因排查方法解决措施
SDA 持续低从机复位、仲裁失败未释放测对地电阻、示波器看波形发送 9 个 SCL 脉冲 + STOP
SCL 持续低从机时钟延展超时检查从机延展逻辑加超时复位、更换从机
仲裁频繁失败多主机同时发起传输逻辑分析仪抓 START 时间加随机退避、错开传输周期
数据错乱仲裁失败后未切换接收检查主机状态机失败后复位状态机
速率低于预期时钟同步、从机延展测 SCL 实际频率统一主机频率、选低延展从机
NACK 超时主机不支持时钟延展查主机手册换主机或软件模拟 I2C

7. 用逻辑分析仪抓仲裁过程:实战演示

7.1 抓取前的准备

要抓仲裁过程,你需要一个支持 I2C 解码的逻辑分析仪,至少 2 个通道,采样率建议 10MS/s 以上。探头接 SDA 和 SCL,地线接好。触发条件设为 SDA 下降沿,因为 START 条件是 SCL 高时 SDA 下降。

如果你用的是 Saleae 或者类似的逻辑分析仪,打开 I2C 解码器,设置正确的阈值电压。3.3V 系统阈值设 1.65V,5V 系统设 2.5V。

7.2 抓取多主机仲裁波形

让两个主机同时发起传输,逻辑分析仪会抓到完整的波形。你会看到:

  • START 条件:SCL 高,SDA 下降。
  • 地址位:两个主机同时发送,SDA 上的电平是线与结果。
  • 仲裁点:某一位上,一个主机输出高,另一个输出低,SDA 为低。输出高的主机退出。
  • 退出后:SDA 和 SCL 由赢的主机继续驱动。

在解码器里,你可能会看到地址被解码成赢的主机的地址。输的主机的地址不会出现在解码结果里,因为它已经退出了。

7.3 分析时钟延展

抓时钟延展时,触发条件设为 SCL 下降沿。你会看到 SCL 在某个低电平期间被拉长,超过正常的时钟周期。解码器会显示传输暂停,直到 SCL 恢复。

如果逻辑分析仪支持模拟波形,你还能看到 SCL 的上升沿变缓,这是因为上拉电阻和总线电容的影响。上升时间太长会导致采样错误,这时候需要减小上拉电阻。

7.4 实操心得

我一般会先用逻辑分析仪抓一次正常传输,确认时序参数符合预期。然后再抓多主机场景,对比波形差异。如果发现 SCL 低电平时间异常长,先怀疑时钟延展;如果发现 SDA 在非预期时间变化,先怀疑仲裁。

还有一个技巧:在代码里加调试引脚,在仲裁失败时翻转一个 GPIO。这样用逻辑分析仪同时抓 I2C 和调试引脚,就能精确知道仲裁发生在哪个位。

8. 硬件 I2C 与软件模拟 I2C 在仲裁场景下的取舍

8.1 硬件 I2C 的局限

硬件 I2C 控制器通常支持多主机仲裁,但不同厂商的实现差异很大。有些控制器在仲裁失败后会自动重试,有些需要软件清除标志位。有些控制器不支持时钟延展,遇到从机延展会报错。

我在选型时,会重点看这几个参数:是否支持多主机、是否支持时钟延展、仲裁失败后的行为、超时时间是否可配。如果手册里写得含糊,直接找 FAE 确认,或者用软件模拟。

8.2 软件模拟 I2C 的优势

软件模拟 I2C 用 GPIO 控制 SDA 和 SCL,完全由代码控制时序。仲裁和时钟延展都可以自己实现。缺点是占用 CPU 时间,高速传输时可能跟不上。

我的经验是:如果总线速率在 100kHz 以下,软件模拟完全够用,而且调试方便。400kHz 以上,建议用硬件 I2C,但一定要确认它支持你需要的特性。

8.3 混合方案

有些项目里,我会用硬件 I2C 做正常传输,用软件模拟做总线恢复。比如总线锁死时,硬件 I2C 可能无法发送 9 个时钟脉冲,这时候切换到 GPIO 模式,手动发送脉冲,再切回硬件 I2C。

这种混合方案需要仔细处理引脚复用和状态切换,但实战中非常有效。

9. 多主机系统的设计建议与避坑清单

9.1 设计阶段的关键决策

  • 主机数量:能少则少。多一个主机,仲裁概率就高一分。如果可以用一个主机轮询多个从机,就不要用多主机。
  • 传输周期:错开各主机的传输周期,减少同时发起传输的概率。比如一个主机每 10ms 发一次,另一个每 15ms 发一次,冲突概率会低很多。
  • 优先级:如果某些数据必须优先传输,可以在软件层做优先级仲裁,避免硬件仲裁的随机性。
  • 上拉电阻:根据总线电容和速率计算,不要照抄参考设计。
  • 总线恢复:在主机初始化时加总线恢复流程,防止上电时总线锁死。

9.2 调试阶段的避坑清单

  • 先用单主机验证功能,再加第二主机。
  • 用逻辑分析仪抓波形,不要靠猜。
  • 仲裁失败后加退避,不要立即重试。
  • 从机时钟延展时间要实测,不要只看手册。
  • 总线锁死时先发 9 个时钟脉冲,再发 STOP。
  • 硬件 I2C 不支持时钟延展时,换软件模拟或换芯片。
  • 多主机系统中,SCL 实际频率由最慢的主机决定,设计时留余量。

9.3 一个真实的踩坑案例

我曾经做一个多主机采集系统,两块 MCU 通过 I2C 共享一片 FRAM。FRAM 的写周期很短,不需要时钟延展,所以我没在意。结果调试时发现,两块 MCU 偶尔会同时写 FRAM,仲裁后其中一个退出,但退出的那块 MCU 的状态机没有复位,下一次传输时地址错乱,写到了错误的地址。

后来我在仲裁失败的中断里加了状态机复位,问题解决。这个坑让我明白:仲裁失败不是简单的重试,而是需要完整的状态恢复。

10. 从仲裁和时钟延展看 I2C 的设计哲学

I2C 的多主机仲裁和时钟延展,本质上是用最简单的电气特性解决复杂的分布式协调问题。没有中央仲裁器,没有令牌,没有复杂的协议状态机,只靠开漏输出和线与逻辑,就实现了多主机共享总线。

这种设计哲学值得每个嵌入式工程师体会。它告诉我们:好的协议不一定要复杂,但一定要把物理层的特性用透。开漏输出让低电平具有压倒性优先级,线与逻辑让仲裁变成自然的逐位比较,时钟同步让所有主机在同一节拍下工作,时钟延展让从机有了反压能力。

我在实际项目中越来越倾向于用 I2C 而不是 SPI 做多设备互联,就是因为 I2C 的仲裁和时钟延展让系统更健壮。SPI 需要片选线,多主机几乎不可能;I2C 只需要两根线,多主机是原生支持。

当然,I2C 也有它的局限:速率不高、总线电容有限、上拉电阻功耗。但在大多数传感器、EEPROM、RTC 场景下,I2C 的简洁和健壮是无可替代的。

最后分享一个小技巧:如果你在调试多主机 I2C 时不确定仲裁是否发生,可以在代码里加一个计数器,每次仲裁失败就加一。跑一段时间后看计数,如果为零,说明你的传输周期错开得很好;如果频繁增加,就需要调整传输策略了。这个计数器我一般会保留在最终固件里,作为系统健康度的一个指标。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/26 1:14:13

校园一卡通系统需求设计:从状态机到对账的完整方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/26 1:13:51

MPP 2.0手写笔HID数据帧拆解与压感调试实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/26 1:13:26

Cadence SPB 24.1 安装全指南:JDK11/SQL Server 2008 R2 依赖详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/26 1:12:13

Cursor:首个AI原生IDE的工程实践与中文本地化深度解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/26 1:12:12

ORDER BY排序不生效?揭秘ASC/DESC背后的三重规则

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华