I2C总线协议深入实战:时序、地址冲突、总线挂死与排查技巧
I2C总线因为只占两根线却能挂很多设备,在EEPROM、传感器、RTC、显示屏里到处都是。但I2C又是最容易“莫名其妙不工作”的协议:卡死、地址冲突、时序不对,坑非常多。本文把I2C从原理到实战讲透。
先搞懂时序骨架。I2C靠SCL时钟和SDA数据两根线通信:起始条件是SCL高时SDA拉低,停止条件是SCL高时SDA拉高。每个字节8位,后面跟一个应答位ACK。写一个字节就是“起始→发地址→发数据→停止”,读数据要主机先发从机地址再切换方向,最后用NAK加停止结束。这些基本时序弄熟,后面什么都好办。
7位地址最多挂127个设备,但实际常遇到地址冲突。比如两块同型号EEPROM地址都是0x50,直接挂一根总线上就会冲突。解决办法:优先选带地址引脚(A0/A1/A2)的设备,把地址引脚接不同电平来区分;或者用I2C多路复用器把总线分开。选型阶段就要规划好地址分配。
总线挂死是最经典的I2C故障。现象是SCL或SDA一直拉低,读写全部超时。常见原因:从机上电时序不对导致状态机混乱、发送中途被打断、或者从机地址应答丢失。应急恢复的办法是“时钟恢复”:把SCL反复翻转9个时钟,让从机状态机复位,同时保证SDA释放。写驱动时建议在每次通信开始前做一次这种复位。
上拉电阻的选择也很关键。I2C是开漏结构,必须靠外部上拉把线拉高。电阻太小电流大伤功耗,太大上升沿变缓影响高速通信。一般4.7K到10K是常规选择,快速模式400K时建议1K到4.7K。示波器上看上升沿太缓,就是上拉偏大的信号,适当减小。
软件模拟还是硬件I2C,是个经典选择题。硬件I2C(如STM32的I2C外设)效率高、不占CPU,但初始化复杂、出问题不好排查;软件模拟就是GPIO翻转时序,灵活、可移植,51上基本都这么写。低速传感器场景,软件模拟完全够用,重点是时序函数要严谨。
最后给个调试三板斧:一是用逻辑分析仪抓总线波形,看起始停止、地址应答是否标准,这是定位I2C问题最快的办法;二是确认每个设备的地址,先用现成扫描程序把所有在线设备扫出来;三是电源和电平,3.3V和5V设备混接时一定要做电平转换。I2C的坑大多逃不出这三点,排查顺序对了,问题很快水落石出。 |
|
|
|
|
|
|
|