单片机/C/C++八股:(二十七)IIC 专题(I²C)---- 下集

📅 发布时间:2026/7/20 13:18:41
单片机/C/C++八股:(二十七)IIC 专题(I²C)---- 下集 上一篇下一篇IIC 专题I²C---- 上集目 录5IIC 为什么要加上拉电阻6IIC 器件为什么要设计为开漏输出同上7IIC 如何实现多主机通信仲裁7.1说明7.2示例8IIC 的时钟同步和时钟拉伸是什么8.1时钟同步8.2时钟拉伸9IIC 通信中其他常见的问题及解决方案5IIC 为什么要加上拉电阻参考视频为什么为什么IIC总线为什么加上拉电阻_哔哩哔哩_bilibili本质上是为了配合IIC器件的开漏输出来实现“线与”逻辑。具体如下目标实现“线与”逻辑I²C 总线允许多个设备共享同一线路为了避免两个设备同时一个输出高、一个输出低造成短路冲突需要一种机制让所有设备只能“拉低”、不能“强制拉高”。这就是线与—— 任一设备输出低则总线为低所有设备释放后总线才为高。手段将引脚设计为开漏输出为了达到上述目标I²C 器件的 SCL 和 SDA 引脚内部仅保留下拉驱动开漏移除主动上拉驱动不使用推挽输出确保设备之间不会因为输出相反电平而直接形成电源到地的电流通路。这样无论多少个设备同时驱动都不会发生硬件损坏。配套外接上拉电阻来产生高电平由于开漏引脚只能主动输出低电平无法主动输出高电平因此必须通过外接上拉电阻连接到正电源。当所有设备都释放总线时上拉电阻将总线拉到高电平当任一设备开启下拉管时总线被拉低。这样既保证了“线与”逻辑的正常工作又为总线定义了明确的高电平状态。此外开漏 上拉的组合还顺带解决了多主机仲裁后续会介绍主机可以一边发送一边检测总线状态发现总线被其他设备拉低时就自动退出安全可靠。时钟拉伸后续会介绍从机可以直接把 SCL 拉低来强制主机等待。上拉电阻阻值选择电阻过大 → 上升沿过慢可能超出规格如快速模式上升时间要求导致数据误码。电阻过小 → 功耗增加且设备下拉可能无法拉出有效低电平。常见阻值最大范围1 kΩ ~ 10 kΩ实际常用 2.2 kΩ、4.7 kΩ。低速应用4.7kΩ-10kΩ标准速度4.7kΩ快速模式2.2kΩ-4.7kΩ高速模式1kΩ-2.2kΩ———————— 总结 ————————I²C 是一种多主机、多从机共享总线的通信协议为了实现“线与”逻辑保证任何设备都能安全地驱动总线而不会发生硬件冲突或短路若两个设备分属主从且为推挽输出若恰好在同一时刻一个输出高、一个输出低电源到地之间会形成 短路路径引发大电流烧毁器件。所以 IIC 器件的引脚都设计成了开漏输出只能输出低电平所以才需要 IIC 总线加一个上拉电阻来输出高电平。6IIC 器件为什么要设计为开漏输出同上上述最后的黄色总结字体7IIC 如何实现多主机通信仲裁7.1说明多主机仲裁有两种情况情况一在 SDA 空闲的情况下哪个主机先将 SDA 拉低谁就获得优先权。情况二在 SDA 空闲的情况下多个主机同时将 SDA 拉低分辨不出谁先拉低的此时会根据时钟同步逐位对比 SDA 上的电平首先所有主机会被动统一到同一个时钟节奏也就是俗称的时钟同步确保大家在同一个时钟沿上公平比较这些主机在同时拉低 SDA 后会立刻拉低 SCL时钟信号的第一个下降沿此时 SCL 处于低电平由于 SCL 也是线与连接的实际时钟由最慢的时钟源决定低电平持续时间时钟频率越低这个低电平就会持续越久就会越晚释放 SCL当大家都释放后SCL 变高接着时钟频率最快的主机先拉低 SCL开始下一个周期。结果所有主机的时钟被统一到同一个节奏这是公平仲裁的基础只不过这个时钟信号每个周期的高电平和低电平的持续时间不一定一致大家自己拿一快一慢的主机举个例子画个图就知道了。然后仲裁在 SDA 线上进行⟶ \longrightarrow⟶这些主机会在经过时钟同步后的 SCL 高电平期间发送自己的通讯地址并监视 SDA 线的电平地址位上第一个出现“发 1 但看到 0”的主机退出最后一个坚持发送并且地址没有被其他主机拉低的主机获胜。说白了就是谁的地址二进制值更“低”0 占比更多谁就能坚持到最后因为 0 会覆盖 1。补充一句这个仲裁和 CAN 总线的有些类似。7.2示例假设三个主机 A、B、C 都检测到总线空闲同时发起通信第一步产生 START 条件同时拉低 SDA三个主机都在 SCL 为高时把 SDA 从高拉低。由于线与特性SDA 立即变成低电平。所有主机都看到 SDA 变低但无法区分是谁拉低的因为开漏输出并联在一起。此时A、B、C 都认为自己成功产生了 START 条件都准备发送地址。第二步时钟同步SCL 线每个主机都开始驱动 SCL 线产生自己的时钟节奏。但由于 SCL 也是线与连接的实际时钟由最慢的时钟源决定低电平持续时间谁最后释放 SCL谁决定低电平宽度最慢的人拖着大家当大家都释放后SCL 变高最快的人先拉低 SCL开始下一个周期。结果所有主机的时钟被统一到同一个节奏这是公平仲裁的基础。第三步逐位仲裁这才是关键在统一时钟的每个周期所有主机在 SCL 低电平期间把各自的地址位放到 SDA 上如果 A、B、C 都发送“0”拉低 SDASDA 为低所有主机回读也是“0”保持一致。这一位无法区分胜负继续下一位。如果某一位上A 发送“1”释放 SDAB 发送“0”拉低 SDAA 期望 SDA 为高但回读发现 SDA 被 B 拉低了。A 立即意识到有人和我冲突我输掉了仲裁A立即退出切换为从机不再驱动 SCL 和 SDA。B 继续发送甚至不知道 A 曾经存在。如果 A、B 都发送“0”C 发送“1”C 回读发现 SDA 为低被 A 和 B 拉低C 退出。A 和 B 继续竞争下一位。8IIC 的时钟同步和时钟拉伸是什么8.1时钟同步同上一个问题已用黄色高亮时钟同步发生于多个主机在同一时间发起通信都在总线空闲时产生 START 条件仲裁阶段自动触发时钟同步。8.2时钟拉伸时钟拉伸是从设备用来延长总线时钟周期的机制。从设备在主机释放 SCL让 SCL 变高后故意将 SCL 继续拉低阻止主机进入下一个时钟周期直到从设备完成内部处理后释放 SCL通信才继续。使用场景从设备需要额外处理时间例如接收完一个字节后需存入缓冲区或处理数据来不及接收下一个字节。主机从从机读取数据从机需要时间准备好要发送的数据。使慢速从设备能与快速主机正常通信避免数据丢失。触发方式主机往从机写数据从设备在收到主机发出的第 8 个时钟脉冲后即一个字节接收完成若内部处理未完成就在主机释放 SCL 后立即拉低 SCL延长低电平。主机读取从机数据从设备在主机读取数据时在应答位之前或之后拉低 SCL 以换取准备时间。硬件IIC和软件模拟IIC的支持情况硬件IIC大多数现代 MCU 的 I²C 硬件模块都支持时钟拉伸的检测可以从机模式下控制拉伸从机模式下响应拉伸。当从机拉低 SCL 时主机的硬件模块会自动插入等待周期暂停状态机直到 SCL 变为高再继续。软件不需要干预。但部分老旧或Simplified I²C 模块如某些 I²C-Lite 模块可能不支持时钟拉伸或者需要特殊配置才能开启。软件模拟IIC只要软件实现时加入了 SCL 低电平检测逻辑模拟 I²C 即可完全支持时钟拉伸。典型实现每次软件释放 SCL 后轮询读取 SCL 引脚状态若仍为低则一直等待直到变高后再继续后续时序。9IIC 通信中其他常见的问题及解决方案总线锁死现象SDA 或 SCL 被某个设备一直拉低总线无法恢复。解决方案法1 - 软件复位主机连续发送 9 个时钟脉冲尝试完成被中断的传输使从机释放总线。法2 - 硬件复位对相关 I²C 设备进行硬件复位如有复位引脚。法3 - 电源循环关闭再重新上电强制重置所有设备。地址冲突现象多个设备使用相同的 I²C 地址导致通信混乱或设备无法区分。解决方案法1 - 引脚选择使用带有地址选择引脚A0/A1/A2的器件通过硬件配置不同地址。法2 - 地址转换器使用 I²C 地址转换芯片如 PCA9547将单一总线虚拟出多个独立地址段。法3 - 多总线设计使用 MCU 的多组 I²C 接口将冲突设备分散到不同总线上。时序问题现象高速通信时数据错误、偶发失败波形边沿过缓。解决方案法1 - 减小上拉电阻降低上升时间但会增加功耗需平衡。法2 - 减少总线电容缩短走线长度、减少从机数量、选用低电容器件。法3 - 降速将通信速率降低到更稳定的档位如从 400 kHz 降至 100 kHz。噪声干扰现象通信不稳定偶发数据错误或挂死。解决方案法1 - 屏蔽与隔离使用屏蔽线缆远离强干扰源。法2 - 增加滤波在 SDA/SCL 线上对地加小电容通常 100 pF 以下避免影响上升时间。法3 - PCB 布局避免 I²C 走线与高速信号线如 PWM、SPI平行或靠近用地线隔离