3、多从机拓扑设计:地址分配、总线仲裁、上拉电阻计算
好,咱们进入第三章。多从机拓扑设计,说白了就是解决三个问题:谁是谁(地址分配)、谁先说话(总线仲裁)、信号能不能传到位(上拉电阻)。这三个点任何一个出问题,你的 I2C 总线就别想正常工作。
我记得刚入行那会儿,总觉得 I2C 简单,两根线嘛。结果第一次做多从机项目,三个传感器挂一条总线上,死活只认出一个。查了两天,最后发现是地址冲突。嗯,从那以后我再也不敢小看这个环节了。
3.1 地址分配:别让两个从机抢同一个名字
I2C 的地址是 7 位(也有 10 位模式,但 STM32 默认用 7 位)。7 位能表示 0x00 ~ 0x7F,共 128 个地址。但注意,0x00 是广播地址,0x7F 保留,实际可用的是 0x01 ~ 0x7E,共 126 个。
听起来够用对吧?但问题在于,很多传感器出厂时只给你一个固定地址,或者只有两三个可选引脚。比如常见的 MPU6050,地址只有 0x68 和 0x69 两个选择。你挂三个 MPU6050 上去,必然冲突。
3.1.1 地址分配策略
我一般按以下优先级来分配地址:
- 查数据手册:先看每个器件的默认地址和可选地址范围。
- 硬件引脚配置:很多芯片有 ADDR、A0/A1/A2 引脚,通过拉高或拉低来改变地址。
- 软件可编程地址:部分芯片支持通过命令修改地址(如 EEPROM 的 24 系列)。
- 分时复用:实在冲突了,用 GPIO 控制从机的电源或使能脚,分时访问。
| 器件类型 | 典型地址范围 | 地址配置方式 | 注意事项 |
|---|---|---|---|
| MPU6050(陀螺仪) | 0x68 / 0x69 | AD0 引脚电平 | 只有两个地址,多片需分时 |
| AT24C02(EEPROM) | 0x50 ~ 0x57 | A0/A1/A2 引脚 | 最多 8 片同总线 |
| BMP280(气压计) | 0x76 / 0x77 | SDO 引脚电平 | 注意默认值 |
| SSD1306(OLED) | 0x3C / 0x3D | DC 引脚或跳线 | 常见冲突源 |
3.1.2 地址冲突的排查方法
我曾经遇到一个项目,挂了两片 AT24C02,地址设成 0x50 和 0x51,结果读出来数据全是乱的。用逻辑分析仪一看,主机发送 0x50 时,两个从机都回了 ACK。为什么?因为 AT24C02 的地址是 0x50 + (A2<<2 | A1<<1 | A0),我 A0 引脚忘记接上拉电阻了,浮空状态导致两个芯片都读到了低电平。
排查步骤:
- 用逻辑分析仪抓取主机发送的地址字节。
- 检查每个从机的 ACK 响应,看是否有多个从机同时应答。
- 用万用表测量地址配置引脚的电压,确认硬件连接正确。
- 写一个扫描程序,遍历 0x01 ~ 0x7E,看哪些地址有应答。
// I2C 地址扫描示例(STM32 HAL 库)
for (uint8_t addr = 0x01; addr < 0x7F; addr++) {
HAL_StatusTypeDef ret = HAL_I2C_IsDeviceReady(&hi2c1, (addr << 1), 1, 10);
if (ret == HAL_OK) {
printf("Device found at 0x%02X\n", addr);
}
}
3.2 总线仲裁:谁先抢到谁说话
I2C 总线仲裁,很多人觉得跟自己没关系。其实关系大了。仲裁机制决定了多个主机同时发起通信时,谁获得总线控制权。但即使你只有一个主机,仲裁机制也会影响从机的响应行为。
说白了,I2C 的仲裁是基于线与逻辑的。谁先输出低电平,谁就赢。因为 SDA 和 SCL 都是开漏输出,低电平会覆盖高电平。
3.2.1 仲裁过程
假设两个主机同时想发送数据:
- 两个主机都拉低 SCL,开始时钟。
- 第一个数据位,主机 A 输出高电平,主机 B 输出低电平。
- SDA 线上实际是低电平(因为低覆盖高)。
- 主机 A 检测到 SDA 与自己输出的不一致,知道自己仲裁失败,立即释放总线。
- 主机 B 继续通信,不受影响。
这个过程完全由硬件自动完成,你不需要写代码处理。但你要知道:仲裁失败的主机不会产生错误中断,它只是默默退出。如果你的程序依赖“发送完成”标志来判断通信成功,仲裁失败时可能误判。
3.2.2 多主机拓扑的注意事项
- 每个主机必须能检测仲裁失败(硬件支持)。
- 仲裁失败后,主机必须释放总线并重试。
- 从机地址不能冲突,否则仲裁机制无法区分。
- 多主机场景下,上拉电阻要更保守计算(见下一节)。
3.3 上拉电阻计算:信号质量的命门
上拉电阻选不对,I2C 总线要么信号爬不上去,要么功耗太大。我见过太多人随便焊个 10kΩ 上去,结果 400kHz 模式下波形惨不忍睹。
上拉电阻的取值受三个因素约束:
- 上升时间:RC 常数决定,R 越大,上升越慢。
- 总线电容:包括引脚电容、走线电容、过孔电容。
- 驱动能力:从机拉低 SDA 时,需要能克服上拉电阻的电流。
3.3.1 计算公式
I2C 规范给出了上拉电阻的最小值和最大值:
| 参数 | 标准模式(100kHz) | 快速模式(400kHz) | 快速+模式(1MHz) |
|---|---|---|---|
| 最大上升时间 tr | 1000 ns | 300 ns | 120 ns |
| 最小上拉电阻 Rp(min) | ≈ 1.5 kΩ | ≈ 1.5 kΩ | ≈ 1.5 kΩ |
| 最大上拉电阻 Rp(max) | ≈ 10 kΩ | ≈ 4.7 kΩ | ≈ 2.2 kΩ |
具体计算:
- Rp(min) = Vcc / Iol(max),其中 Iol(max) 是从机最大灌电流(通常 3mA)。
- Rp(max) = tr / (0.8473 × Cb),其中 Cb 是总线总电容。
举个例子:3.3V 供电,总线电容 100pF,400kHz 模式:
- Rp(min) = 3.3V / 3mA = 1.1kΩ,取标称值 1.5kΩ。
- Rp(max) = 300ns / (0.8473 × 100pF) ≈ 3.54kΩ。
- 所以上拉电阻选 2.2kΩ ~ 3.3kΩ 比较合适。
3.3.2 多从机时的电容估算
每个从机引脚大约有 5~10pF 的输入电容。走线电容约 1pF/cm。过孔电容约 0.5pF。所以:
C_b = 主机引脚电容 + 所有从机引脚电容 + 走线电容 + 过孔电容
假设 5 个从机,每个 10pF,走线 30cm,过孔 10 个:
- 从机电容:5 × 10pF = 50pF
- 主机电容:约 10pF
- 走线电容:30cm × 1pF/cm = 30pF
- 过孔电容:10 × 0.5pF = 5pF
- 总电容 ≈ 95pF
这个值代入上面的公式,就能算出合适的上拉电阻。
3.4 拓扑结构图
下面这张图展示了多从机 I2C 总线的典型拓扑,包括地址分配、上拉电阻位置和仲裁逻辑。
3.5 实战建议
最后,给几个我踩过坑之后总结的实战建议:
- 地址规划表:项目初期就做好地址分配表,贴在工位上。
- 上拉电阻选型:不要盲目用 10kΩ。先估算总线电容,再按频率计算。
- 逻辑分析仪:调试多从机系统时,逻辑分析仪是必备工具。看波形比看代码快得多。
- 预留测试点:PCB 上给 SDA 和 SCL 预留测试点,方便抓波形。
- 分步上电:第一次调试时,只挂一个从机,确认通信正常后再逐个增加。
嗯,多从机拓扑设计就讲到这里。地址分配、总线仲裁、上拉电阻,这三个点看似独立,其实环环相扣。地址冲突会导致仲裁异常,上拉电阻不对会影响地址识别。你想想看,是不是这个道理?