驱动之路#41:为什么 I2C 要上拉电阻?

描述

前面一篇文章,我们简单了解了 I2C 是怎么通信的:两根线,SDA 负责数据,SCL 负责时钟;主控通过起始信号、地址、ACK、停止信号,完成一次完整通信。

但刚接触 I2C 的朋友,通常还会遇到另一个问题:为什么 I2C 总线一定要加上拉电阻?

明明 SDA、SCL 已经接到芯片引脚了,为什么还要额外接两个电阻到电源?

这篇就来聊聊这个问题。

上拉电阻

1. 先说结论

I2C 之所以需要上拉电阻,核心原因是:I2C 设备的输出结构是开漏 / 开集输出,只能主动拉低,不能主动输出高电平。

也就是说,I2C 设备可以把总线拉成低电平,但没办法自己把总线推成高电平。

所以,高电平从哪里来?答案就是:靠外部上拉电阻拉上去。

上拉电阻

 

想象一下这种情况:多个I2C设备挂在同一条总线上,当所有设备都不主动拉低总线时,总线相当于“悬空”。在数字电路中,悬空意味着不确定的电平状态,极易受到噪声干扰,导致通信失败。


2. 开漏输出是什么?

要理解 I2C 为什么要上拉,先得理解一个概念:开漏输出

I2C 规范要求总线上的设备采用开漏或开集输出结构。

简单理解就是:引脚内部只有一个负责“拉低”的管子,没有负责“拉高”的管子。

当这个管子导通时,引脚被拉到 GND,总线为低电平。当这个管子关闭时,引脚并不会输出高电平,而是进入高阻态,相当于“松手了”。

这就像一个人只能把绳子往下拉,不能把绳子往上推。那绳子怎么回到高处?只能靠外部有个东西把它往上拽。

在 I2C 里,这个“往上拽”的东西,就是上拉电阻


3. 上拉电阻作用

作用 1: 提供高电平

I2C 通信需要高低电平来表达信号。

比如:

  •  
  •  
高电平:总线释放 / 空闲 / 数据 1低电平:设备拉低 / 数据 0 / ACK

但由于 I2C 设备只能主动拉低,不能主动拉高,因此必须通过上拉电阻,把 SDA / SCL 默认拉到高电平。

所以在总线空闲时,SDA 和 SCL 通常都是高电平。当某个设备需要发送低电平时,就把总线拉低。当设备释放总线时,总线又通过上拉电阻回到高电平。

这个逻辑非常关键——没有上拉电阻时,设备一旦释放总线,SDA / SCL 就会悬空,电平不确定,后面的 Start、Stop、ACK 都可能识别异常。


作用 2: 支持“线与”逻辑

I2C 是总线结构,一条线上可以挂多个设备。比如 RK3576 的某一路 I2C 总线上,可能挂着触摸芯片、PMIC、RTC 或其他外设。

那问题来了:多个设备都接在同一根 SDA 上,谁说了算?答案就是靠 I2C 的开漏结构和上拉电阻实现“线与”逻辑。

规则很简单:

  •  
  •  
只要有一个设备拉低,总线就是低电平;只有所有设备都释放,总线才是高电平。
举个 RK3576 调触摸芯片 GT911 的例子。

当 RK3576 给 GT911 发送地址后,如果 GT911 识别到这个地址,就会在第 9 个时钟周期拉低 SDA,表示 ACK 应答。

此时 RK3576 其实是释放 SDA 的,但因为 GT911 把 SDA 拉低了,所以总线电平就是低。这就是 I2C 能实现多设备共享总线的关键。

如果没有上拉电阻,所有设备释放总线时就没有明确的高电平,“点名—应答”这套机制也就玩不起来了。


作用 3: 稳定总线状态

数字电路最怕什么?最怕电平不确定。

如果 SDA / SCL 没有上拉,设备释放后总线就是悬空的。悬空状态很容易受到外部噪声、电磁干扰、邻近信号串扰影响。

结果就是:

  •  
  •  
  •  
本来应该是高电平,结果被干扰成低电平;本来应该保持稳定,结果出现毛刺;本来应该通信正常,结果偶发 ACK 失败。

这类问题在调试时特别折磨人。因为它不一定每次都复现,有时候冷启动正常,热启动异常;有时候短线正常,接上转接板就不行。

所以,上拉电阻不仅是为了“拉高”,也是为了让总线在释放状态下有一个明确、稳定的默认电平。


 

4. 上拉电阻是不是越大越好?

既然上拉电阻负责把总线拉高,那是不是电阻越大越好?

也不是。上拉电阻太大,会导致上升沿太慢。

因为 I2C 总线有电容,比如 PCB 走线、电缆、芯片引脚都会带来总线电容。上拉电阻和总线电容会形成 RC 充电过程。

电阻越大,充电越慢,上升沿越缓。如果通信速率比较高,上升沿太慢,就可能导致设备还没识别到稳定高电平,下一个时钟已经来了。这就容易出通信错误。

但上拉电阻太小也不行。

因为当设备拉低总线时,电流会从 VCC 通过上拉电阻流入拉低管子到 GND。电阻越小,电流越大。

如果电流超过器件引脚的灌电流能力,就可能导致低电平拉不够低,甚至长期工作影响器件可靠性。

所以,上拉电阻不是越大越好,也不是越小越好,而是要在“上升沿速度”和“器件驱动能力”之间折中。

常见 I2C 总线可以先用 4.7kΩ 作为经验起点,具体还要结合速率、总线电容、供电电压和器件手册来判断。


5. 实际项目里最容易踩的坑

问题 1:忘记加上拉电阻

这是最基础、也最容易犯的错误。

表现通常是:

  •  
  •  
  •  
  •  
i2cdetect 扫不到设备;示波器看 SDA / SCL 波形异常;总线无法形成稳定高电平;设备一直不 ACK。

这种情况不要急着改驱动,先看原理图。


问题 2:上拉电阻值不合适

电阻过大,上升沿慢,高速通信容易出错。

电阻过小,电流过大,设备可能拉不动低电平。

工程上常见起点是 4.7kΩ,但不是所有场景都固定用它。

如果总线较长、挂载设备较多、通信速率较高,就要重新评估。


问题 3:多个上拉电阻并联

这个坑在实际项目里真不少。比如主板上已经给 SDA / SCL 加了上拉,结果屏幕转接板、触摸板、小模块上也各自加了一组上拉。

看起来每个板子都“很规范”,但接到一起就变成多个上拉电阻并联

并联后的总电阻会变小。比如两个 4.7kΩ 并联,大约就变成 2.35kΩ;如果三四个板子都加,上拉会更强,电流也更大。

我实际工作中就遇到过类似问题:设计屏幕转接板时,触摸电路上加了一组 I2C 上拉;而使用这个屏幕的主板上,同一条 I2C 总线也加了一组上拉。两边一并联,结果反而导致通信异常。

上拉电阻

所以,I2C 上拉不是每个设备旁边都来一组,而是要站在整条总线的角度看。


 

6. 工程上怎么处理?

实际设计时,可以按下面几个原则来:

  •  
  •  
  •  
  •  
  •  
  •  
[ ] 同一条 I2C 总线通常只保留一组上拉电阻;[ ] 常规场景可先用 4.7kΩ 作为起点;[ ] 总线较长、负载电容较大时,要关注上升沿;[ ] 多个模块拼接时,要检查是否重复上拉;[ ] 通信异常时,用示波器看 SDA / SCL 波形;[ ] 不要只看软件日志,I2C 问题很多时候在硬件层。

如果要更严谨,可以结合 I2C 规范中的公式估算:

  •  
  •  
Rmax ≤ tr / (0.8473 × Cb)Rmin > (VDD - VOL) / IOL

简单理解:

  •  
  •  
Rmax:保证上升沿不能太慢;Rmin:保证拉低电流不能超过器件能力。

不过大多数普通低速 I2C 场景,先从 4.7kΩ 开始,再结合波形和实际通信情况调整,通常是比较稳妥的做法。


7. 总结

I2C 为什么要上拉?

一句话总结:因为 I2C 是开漏 / 开集输出结构,设备只能主动拉低,不能主动拉高,所以必须靠外部上拉电阻提供稳定高电平。

上拉电阻主要有三个作用:

  •  
  •  
  •  
1. 给总线提供默认高电平;2. 支持多设备共享总线的“线与”逻辑;3. 稳定 SDA / SCL 电平,减少悬空和干扰问题。

调 I2C 时,如果设备不 ACK、i2cdetect 扫不到、波形上升沿异常,不要一上来就怀疑驱动。

先回头看看:

  •  
  •  
  •  
  •  
上拉有没有?上拉值对不对?有没有重复上拉?SDA / SCL 波形是否正常?

很多时候,I2C 调不通,不是协议没懂,也不是驱动太难,而是这两个小小的上拉电阻没有处理好。

(完)

下期继续聊: I2C协议与SMBus 是什么关系?


本人专注 Linux 嵌入式全栈开发,可提供从硬件方案评估与设计、Linux/Android BSP 适配、驱动开发、外设调试、系统移植到产品交付的全流程技术支持。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分