ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

IIC上拉电阻怎么选?4.7K与10K的电气差异与工程实践

IIC上拉电阻怎么选?4.7K与10K的电气差异与工程实践 1. 为什么IIC上拉电阻不是随便选的先看懂IIC的开漏结构1.1 开漏输出和“线与”逻辑决定了必须上拉IIC习惯上写成I2C二者一回事的物理层设计比较特殊SCL和SDA引脚都是开漏结构。这意味着芯片内部只能把引脚拉低不能主动拉高。拉高动作实际上要靠外部上拉电阻接到电源电压来完成。为什么IIC要采用这种看似别扭的设计因为总线上可能挂多个从机如果每个芯片的引脚都是推挽输出一个芯片输出高、另一个芯片输出低两条输出路径会直接“打架”轻则通信乱码重则把芯片引脚烧掉。开漏输出天然实现了“线与”任何一个设备都可以把总线拉低只有所有设备都不拉低时上拉电阻才能把总线重新恢复到高电平。所以IIC上拉电阻不是“可选项”而是“必选项”。很多刚接触IIC的人遇到波形一直趴在低电平或者高电平只有零点几伏第一反应是查芯片寄存器、查程序初始化结果绕了很大一圈才发现是上拉电阻没焊、焊错位置或者把上拉接到了地而不是电源。遇到这类问题先量一下上拉电阻两端电压往往比啃半天代码更快。1.2 上拉电阻阻值影响的是三个点上升沿、灌电流、抗干扰上拉电阻的阻值直接决定总线从低到高的恢复速度。可以把总线看成很多寄生电容的集合每个引脚、每段走线、每根连接线都有分布电容加起来就是总线负载电容 C_b。上拉电阻 R_p 和 C_b 组成了一个RC充电回路R_p 越大充电越慢上升沿越缓。上升沿变缓之后最直接的影响是从机采样SCL高电平的时刻可能滞后或不确定导致建立时间、保持时间超标。尤其对于硬件I2C控制器时序是固定不变的如果SCL迟迟达不到高电平阈值主控接收到的状态就完全可能出错。上拉电阻还影响低电平灌电流。总线被拉低时电流从 VCC 经过 R_p 流入芯片灌电流引脚阻值越小灌电流越大。4.7K和10K在3.3V供电下的灌电流差别并不大分别约为0.70mA和0.33mA。但如果有人为了追求更陡的上升沿直接上1K甚至更小的电阻就必须核实器件灌电流能力是否受得了。还有一个容易被忽略的点上拉电阻越大总线高电平的“带载”能力越弱越容易被外部噪声拉低。这也是为什么很多人把4.7K换成10K之后波形看起来还行但一靠近电机、继电器或者加长线就偶发通信失败。IIC本身并不是为长线传输设计的长线场景下用10K会非常吃亏。2. 4.7K和10K的电气差异用计算先做个预估2.1 上升时间估算R 和总线电容直接决定速度IIC规范里通常用上升时间 t_r 来衡量上拉是否合格。工程上估算从30%到70%的上升时间可以用一个近似公式t_r ≈ 0.85 × R_p × C_b举个例子如果总线上挂了一块MCU、一片EEPROM和一个传感器引脚电容加上板级走线电容C_b 凑到100pF是非常常见的情况。那么4.7K上拉t_r ≈ 0.85 × 4700 × 100e-12 ≈ 0.4us10K上拉t_r ≈ 0.85 × 10000 × 100e-12 ≈ 0.85us而I2C规范对上升时间有明确要求标准模式100kHz要求 t_r ≤ 1us快速模式400kHz要求 t_r ≤ 300ns。在100pF总线电容下10K勉强够100kHz但离400kHz差了将近三倍4.7K在100kHz下很安全但在400kHz下同样踩线余量不大。我把不同电容下的估算结果列成一张表方便大家对照总线电容 C_b2.2K 上升时间4.7K 上升时间10K 上升时间50pF约93ns约200ns约425ns100pF约187ns约400ns约850ns200pF约374ns约800ns约1.69us注意这是理论估算实际测量还要加探头电容和PCB寄生参数数值通常会略高一点。但趋势已经很明显在400kHz快速模式下想要留够时序余量4.7K都不太够用很多设计会直接用2.2K只有跑100kHz并且总线电容不大时4.7K和10K才有的比。2.2 低电平灌电流和功耗对比有人为了省电特意选10K这个思路可以理解但实际IIC静态功耗差异没有想象中那么大。总线空闲时SCL和SDA都是高电平上拉电阻上没有电流只有在总线被拉低期间电流才从 VCC 经上拉电阻流过。一次读写在100kHz下持续几毫秒平均功耗其实很低。具体看灌电流3.3V供电下阻值单线上拉灌电流SCLSDA两条线同时被拉低时4.7K约0.70mA约1.40mA10K约0.33mA约0.66mA如果系统只有IIC一个外设4.7K和10K的功耗差一般可以忽略。但如果从机长时间处于busy状态比如某类传感器在内部处理数据时把SCL拉低几百微秒或者总线因为故障一直卡在低电平10K确实比4.7K少耗一半电流。电池产品可以为了功耗选10K前提是把通信速率和线长控制在一个很保守的范围。2.3 噪声容限10K在恶劣环境下更吃亏上拉电阻越大把总线电平维持在“高”的能力越弱。外部噪声耦合到总线上时相当于给高电平线注入一个下拉干扰阻值越大干扰引起的电压跌落越明显。这跟用一根细水管维持水压是一个道理水管越细旁边有人一挤水压就撑不住。实际表现就是10K在干净整洁的板内短走线上可能跟4.7K一样稳定但当你把传感器板用30cm杜邦线连出来或者旁边有电机驱动器、开关电源偶发通信失败的概率会明显上升。4.7K虽然不能完全消除干扰但至少把高电平的维持能力提升了一倍多这是稳定性上一个很大的差别。3. 实测方案与数据同样条件下对比4.7K和10K3.1 测试平台搭建纸上谈兵没有说服力我专门搭了一个测试平台。主控用STM32F103的硬件I2C1挂在SCL和SDA上的从机有一片AT24C256 EEPROM、一个BME280外加一颗0.96寸OLED算是比较典型的板内多从机场景。VDD取3.3V上拉电阻分别焊在SCL和SDA到VDD之间。我先估了一下总线电容MCU引脚、三颗从机芯片的引脚电容加在一起大约30pF到40pFPCB走线长度不长加起来可能在10pF左右额外加了示波器探头后整体C_b大概率落在50pF到100pF区间。示波器用的100MHz带宽无源探头10倍衰减地线用最短的弹簧接地尽量减小探头带来的测量误差。测试分两轮第一轮用100kHz通信第二轮用400kHz通信。每轮分别焊接4.7K和10K电阻用示波器抓SCL的30%到70%上升沿同时跑压力读写。EEPROM那里连续执行“写入64字节、读回64字节、比较结果”的循环共跑10000次BME280则连续读1000次统计NACK和总线卡死的次数。3.2 压力测试代码思路STM32的HAL库写起来比较直观核心逻辑大概是这样uint32_t err_cnt 0; uint8_t tx_buf[64]; uint8_t rx_buf[64]; for (uint32_t addr 0; addr 10000; addr) { for (uint32_t i 0; i sizeof(tx_buf); i) { tx_buf[i] (uint8_t)(addr i); } if (HAL_I2C_Mem_Write(hi2c1, 0xA0, addr, I2C_MEMADD_SIZE_16BIT, tx_buf, sizeof(tx_buf), 100) ! HAL_OK) { err_cnt; HAL_I2C_DeInit(hi2c1); HAL_I2C_Init(hi2c1); } if (HAL_I2C_Mem_Read(hi2c1, 0xA0, addr, I2C_MEMADD_SIZE_16BIT, rx_buf, sizeof(rx_buf), 100) ! HAL_OK) { err_cnt; HAL_I2C_DeInit(hi2c1); HAL_I2C_Init(hi2c1); } if (memcmp(tx_buf, rx_buf, sizeof(tx_buf)) ! 0) { err_cnt; } if (addr % 128 0) { printf(addr%lu err%lu\r\n, addr, err_cnt); } }这里每次出错后我先把I2C外设重新初始化是为了让系统能从总线卡死里恢复继续测下一轮。如果出错后什么都不做很多情况下程序会一直卡在等待标志位那里压力测试根本走不下去。3.3 实测结果4.7K和10K差别有多大实测数据我整理成了下面这张表。因为探头会引入额外寄生电容上升沿的绝对值比纯理论计算稍微大一点但趋势完全一致。通信模式阻值实测上升沿(30%-70%)10000次压力测试结果100kHz4.7K约0.45us全部通过波形稳定100kHz10K约0.95us全部通过边缘略软400kHz4.7K约0.5us全部通过但余量一般400kHz10K约1.05us偶发NACK出现过总线卡死最典型的是400kHz 10K这一组刚上电的前几百次读写没问题后面开始随机出现NACK而且总线偶发卡在低电平必须重新初始化I2C外设才能恢复。这种偶发故障比直接完全不通更难查很容易让人怀疑是程序问题还是硬件问题。为了做对照我又在同样条件下试了2.2K。400kHz时上升沿约0.22us压力测试非常干净而且SCL高电平明显更“硬”。这个对照组告诉我们4.7K在这些场景里属于“能跑但余量不大”10K则是“能用但千万别在400kHz下赌人品”。4. 为什么4.7K比10K稳但不代表可以无脑用4.7K4.1 从波形看上升沿才是IIC稳定的关键把10K上拉的SCL波形放大了看信号不是在高低电平之间干脆地跳变而是斜斜地爬上去。IIC从机在采样时靠的是在SCL高电平期间判断SDA数据有效如果SCL爬得太慢高电平有效时间被压缩SDA数据的建立时间和保持时间就会不够。特别是400kHz时一个时钟周期本来只有2.5us10K上拉占掉超过1us的上升时间留给稳定高电平的时间少得可怜。一旦某个从机内部时钟偏差大一点或者主控的I2C外设时序余量小一点采样就容易乱。硬件I2C控制器的时序是定死的它不会因为你的信号烂就自动多等所以表现出来就是“偶尔收发失败”非常折磨人。4.2 从机数量和线缆长度会把问题放大你可能会想“我板子上就一个传感器走线只有2cm用10K应该也没问题”。确实很多简单场景下10K是能工作的尤其只有一两个从机、走线很短、速度跑100kHz的情况。但随着总线电容增加问题会迅速放大。举个实际例子我把TCA9548A后面接了四路传感器扩展总线上等效电容大约能到200pF。此时10K上拉在100kHz的理论上升时间已经接近1.7us超出标准模式1us的要求。实测也是同样的结论开始能通信线用手一碰或者温度稍微升高马上开始丢数据。换上4.7K之后上升时间降到约0.8us总算稳定一些但余量依然不算充裕。所以选阻值之前一定要估算总线上有多少电容。别迷信“板内短走线没事”一旦从机数量超过3个或者用了二三十厘米以上的杜邦线总线电容会迅速超过你的预期。4.3 4.7K不是万能解快速模式请认真算很多人的第一反应是既然4.7K比10K稳定那我直接用4.7K或者再小一点不就行了其实不然。阻值太小会带来两个新问题一是低电平灌电流变大可能导致设备的低电平电压超过规范也就是低电平不够低二是边沿过陡会产生振铃和过冲在长线条件下反而干扰自己。I2C规范对上拉电阻有一个最小值约束R_min (VCC - VOL) / IOL。比如某MCU引脚在灌电流20mA时VOL0.4V3.3V供电那么理论最小上拉约为(3.3-0.4)/0.02145Ω这是比较极端的情况。实际设计为了安全很少用低于1K的外部上拉除非总线电容很大而且产品有明确的特殊要求。对通用IIC设计选型更多是在最大电阻限制内取一个靠左的值。400kHz下如果总线电容100pF理论上要求上拉不超过约3.5K所以2.2K或2.7K才是合理区间4.7K已经踩线10K基本不合格。别拿100kHz的经验去套400kHz两者时序完全不是一个级别。5. 不同场景下的上拉电阻选型方案5.1 先用公式框定范围再结合实际调整这里给出一个我常用的两步法先估算总线电容 C_b。芯片引脚电容一般5-10pF板上走线按1-2pF/cm估算线缆按50-100pF/m估算把所有从机的引脚电容累加再加20%-30%余量。再根据通信速率查规范要求的最大上升时间 t_r,max。用 R_max ≈ t_r,max / (0.85 × C_b) 算出上拉电阻上限。最后检查灌电流是否超过端口能力得到电阻下限。拿100kHz标准模式举例如果算出来 C_b100pFt_r,max1us那么 R_max 1us / (0.85×100pF) ≈ 11.8K。所以你看到很多资料说“100kHz短总线用10K没问题”这不是凭空说的是算出来的。但同样的100pF总线跑400kHzt_r,max300nsR_max直接降到3.5K10K自然就出局了。我把常见组合整理成一张速查表总线电容100kHz可用上限400kHz可用上限实际推荐50pF约23.5K约7.1K100k用10K400k用2.2K/3.3K100pF约11.8K约3.5K100k用4.7K/10K400k用2.2K200pF约5.9K约1.8K100k用4.7K400k建议1.5K/2.2K或降速当然这是理论边界实际设计不要卡着上限用。温度、电压、芯片批次都会让时序余量发生变化没必要为了省零点几毫安去牺牲整机的可靠性。5.2 我的默认方案能选4.7K就不先想10K在大多数嵌入式项目里我的默认做法是只要没有特别严格的低功耗约束板内IIC上拉直接按4.7K来。即使在100kHz短总线下10K也能工作4.7K带来的额外上升沿余量是实打实的能让你少踩“换了一颗传感器就不稳定”、“从机多一点就卡死”的坑。如果跑400kHz我会直接换2.2K优先保证上升沿余量。有人担心2.2K灌电流太大其实3.3V下2.2K的单线灌电流才1.5mA远没有到多数器件的极限不必一看到小阻值就害怕。如果对功耗极其敏感比如电池供电并且IIC只在低功耗唤醒后偶尔读一次数据可以选10K但要把IIC频率降到100kHz甚至更低走线尽量短。这不是电路不能用而是你拥有的余量很少任何一个变量发生变化都可能引出问题。5.3 上拉电源和电平转换别忘了总线电平匹配上拉电阻的另一头必须接到正确的电源。MCU是3.3V传感器也是3.3V那就统一接到3.3V如果传感器是5V供电而MCU引脚不支持5V不能直接把上拉接到5V否则会在MCU引脚上形成漏电甚至损坏。正确做法是加I2C电平转换芯片或者用支持双向电平转换的MOSFET方案上拉分别接各自电源侧。很多开发板为了方便会把上拉电阻做成可焊可不焊的焊盘或者使用非常弱的内部上拉。我调试时经常遇到有人问“为什么开发板IIC能通自己画完板子就不通”很大比例就是板子上忘了留上拉焊盘或者把上拉接到了错误的电源。6. 常见问题与排查技巧实录6.1 通信不稳定时先看示波器别先改阻值遇到IIC偶发读写失败我第一个动作永远是拿示波器看SCL和SDA波形而不是盲目减小上拉电阻。因为总线不稳定可能有很多原因某颗从机没复位、SDA被拉死、地址错误、时钟拉伸没处理好、引脚配置成推挽输出、外部干扰耦合等等。上拉电阻只是其中一个常见嫌疑。先看三件事SCL和SDA空闲时是不是稳定的高电平如果只有1V左右说明上拉太弱或者有设备把它拉低。通信时上升沿是不是明显倾斜倾斜到400kHz下高电平占空比都不正常上拉嫌疑最大。高电平和低电平是否在合理范围内如果低电平高于0.4V太多反而可能是上拉过小或者灌电流超了。把这几项排除之后再用替换法换阻值验证比盲目换电阻要快得多。6.2 同一块板4.7K稳定、10K偶发死锁的一个案例我之前帮朋友排查一个户外采集板原来用的是4.7K通信一直正常。后来为了把功耗降下去他把两个上拉都换成10K常温下测了几分钟没发现问题就交付了。结果设备在户外温度升高后开始偶发死锁需要断电重启。示波器一看10K上拉时SCL上升沿已经超过1us在100kHz标准模式下勉强合规但高电平部分颤颤巍巍。用手摸一下排线波形都会抖动温度升高后器件阈值变化偶尔触发NACK然后总线卡死。把4.7K换回去之后同样的环境连续跑了一周问题再也没出现过。这个案例说明当总线余量不足时问题通常不是必现的而是条件触发式的。你必须在设计阶段给时序留足余地不能靠“试几天没问题”下结论。6.3 模拟IIC和硬件IIC对上拉电阻的要求不太一样模拟IIC用GPIO按延时翻转对上升沿的要求往往比硬件IIC宽松因为你可以把延时写得很长电平慢一点也能被读到。但如果GPIO配置成推挽输出就没有“开漏”这一说了它会主动驱动高低电平外部上拉反而可能影响电平判断。总线上挂了多个设备时推挽输出还会有灌电流冲突风险所以我更建议模拟IIC也把GPIO配置成开漏模式再配上拉电阻这样才和硬件IIC保持一致的电气行为。不过模拟IIC还有一个天然优势你可以在代码里加入滤波和重试机制。比如连续读两次SDA确认电平稳定后再当作有效值这样能弥补一部分硬件上拉的不足。但这属于“软件补救”不能当成不选合适上拉电阻的借口。我个人在这件事上的体会是IIC上拉电阻的选型本质上是在上升沿、灌电流、抗干扰和功耗之间做平衡。没有哪个阻值能通吃所有场景4.7K在大多数板内场景是个很好的折中10K适合低功耗和极短总线而一旦上到400kHz或者线缆加长别犹豫往2.2K方向走。最后再分享一个小技巧改完上拉电阻后不要只跑一遍例程就验收最好用压力脚本长时间跑几百上千次读写同时用手碰一下线路、开关一下附近的电机或继电器把最恶劣的情况试出来。能撑得住这种折腾的阻值才是放到产品里敢睡觉的阻值。
返回列表