ESP32 实战教程:用 TCA9548A 扩展多个同地址 I2C 传感器

本文按“先跑通、再测量、最后工程化”的顺序整理。不同开发板、模块批次和库版本可能存在差异,请以手中硬件的丝印、数据手册与实际串口日志为准。

ESP32 实战教程:用 TCA9548A 扩展多个同地址 I2C 传感器 系统架构

一、为什么值得做

I2C 允许多个设备共享两根线,但每个设备需要可区分的地址。当你想接八个地址固定为 0x76 的传感器时,总线就像一栋楼里住了八户同门牌号的人,快递员再认真也会迷路。TCA9548A 通过选择下游通道,让同地址设备分时出现在主总线上,特别适合多点测距、多房间环境采集和模块测试台。

这次不追求把所有功能一次堆满。先完成一个最小闭环:硬件能初始化、原始数据有变化、异常时能明确报错;随后再加入标定、滤波和状态机;最后才连接网页、MQTT 或本地存储。这个顺序看起来慢一点,实际会少掉很多“到底是线错了、库错了,还是页面错了”的集体猜谜。

二、硬件清单与接线重点

准备 ESP32、TCA9548A 模块和至少两个同地址 I2C 传感器。ESP32 的 SDA、SCL 接复用器上游,各传感器分别接到不同下游通道。确认所有模块电压兼容,并检查每块板自带的上拉电阻;并联上拉过多会让等效阻值过低,线太长又会增加电容,两种情况都可能让波形变差。

第一次接线建议使用短线,在断电状态下逐根核对,并记录开发板型号、GPIO 编号、模块供电电压和接口地址。不要只写“接到 SDA”,因为换一块板后默认 SDA 可能不同。电机、舵机、风扇和继电器等负载应使用合适的独立电源,GPIO 只负责信号,不能兼职当小型发电站。

三、工作原理

TCA9548A 本身占用一个上游 I2C 地址。主机向它写入一个位掩码,决定哪些通道导通,然后再按原地址访问下游设备。最稳妥的做法是一次只启用一个通道,完成初始化或读取后再切换。业务层应把通道号也作为设备身份的一部分,例如 channel 3 + address 0x76,否则日志里仍然是一群同名传感器。

ESP32 实战教程:用 TCA9548A 扩展多个同地址 I2C 传感器 数据流程

把系统分成五层会更容易排错:电气连接、驱动通信、原始数据、业务换算、显示与联网。每层都留一个可观察点,例如电源电压、初始化返回值、原始帧、换算结果和页面状态。上层失败时先确认下层证据,不要页面上没有数字就立刻换三套库。

四、第一次实验与标定

先不接下游设备,只确认复用器地址能扫描到;然后每次只接一个传感器并扫描单个通道。全部连接后,逐通道记录发现的地址、模块型号和安装位置。不要只在开机时扫描一次就永久相信设备存在,运行中还应记录连续失败次数和最近成功时间。

标定数据应与设备配置一起保存,并记录时间、参考物、环境和固件版本。更换模块、改变机械结构或升级算法后应重新验证。只记一个最终系数而不记原始数据,下一次发现偏差时很难判断是传感器老化、结构变化,还是当初计算时手滑。

五、最小可运行代码

下面的代码用于验证关键链路。安装对应库后,根据自己的开发板修改引脚、地址和参数:

#include <Wire.h>
const uint8_t MUX_ADDR = 0x70;

bool selectChannel(uint8_t channel) {
  if (channel > 7) return false;
  Wire.beginTransmission(MUX_ADDR);
  Wire.write(1 << channel);
  return Wire.endTransmission() == 0;
}

void setup() {
  Serial.begin(115200);
  Wire.begin(21, 22);
}

void loop() {
  for (uint8_t ch = 0; ch < 4; ++ch) {
    if (!selectChannel(ch)) continue;
    Wire.beginTransmission(0x76);
    bool online = Wire.endTransmission() == 0;
    Serial.printf("channel=%u online=%d\n", ch, online);
  }
  delay(1000);
}

示例故意保留串口输出,因为学习阶段最重要的是能看到系统正在做什么。代码跑通后再逐步拆分模块,不能因为最终产品没有串口窗口,就在开发阶段也把所有线索关掉。

六、数据处理与状态设计

建立一个设备状态表,保存通道、地址、类型、最后值、最后成功时间、连续错误数和采样周期。轮询调度器按设备周期选择通道并读取,不要在多个任务里同时切换复用器。网页按物理位置展示数据,而不是只写“传感器 1、传感器 2”,过两个月没人记得 2 到底装在哪。

建议为设备统一设计四种状态:INIT 表示初始化,RUNNING 表示数据有效,DEGRADED 表示部分功能仍可用,ERROR 表示需要人工处理。每次状态变化记录原因和时间。错误恢复要有间隔,不能每个循环都重新初始化外设,否则日志会被刷满,设备也只是在高频重复同一个错误。

七、常见问题与排错顺序

忘记选择通道、一次打开多个含同地址设备的通道、上拉电阻不合适和总线过长是最常见问题。某个下游设备把 SDA 拉低时可能拖住当前通道,应记录超时并尝试切换或电源复位。I2C 不是为跨房间长线设计的,距离较远时应考虑 RS485、CAN 或在传感器旁放置节点。

排错时按以下顺序进行:先测供电和地线,再确认引脚与接口参数;然后只运行最小示例,打印原始数据;最后才恢复网页和自动控制。每次只改一个变量,并保留失败时的原始输出。最怕的是接线、库版本和业务代码同时修改,最终虽然偶然成功,却不知道是哪一步真正起了作用。

八、从演示变成长期运行设备

将复用器访问封装成唯一入口,切换通道和完成事务之间加互斥保护。对每个通道设置独立错误计数,单个传感器离线不能阻塞整轮采样。正式设备可增加下游电源开关,让异常模块能够单独断电重启;线路和接口也要有清晰标签。

程序结构上,可以把驱动、数据模型、业务状态机、网络和存储拆开。采样任务只负责产生带时间戳的有效数据,网页负责读取快照,日志任务负责批量落盘。任何网络故障都不应阻止本地采样,任何页面刷新也不应改变控制周期。配置保存在 NVS 时加入默认值、范围检查和版本迁移。

九、建议完成的测试清单

  1. 冷启动、复位和断电重启后,设备能否进入明确状态;
  2. 外设拔掉、接错或返回异常值时,程序是否会卡死;
  3. 连续运行两小时,内存、温度、供电和日志是否稳定;
  4. 阈值附近反复变化时,输出是否存在抖动或频繁动作;
  5. 更换同型号模块后,原标定是否仍然适用;
  6. Wi-Fi 断开、网页关闭或存储满时,本地核心功能是否继续工作;
  7. 对涉及人体、机械运动和大电流的项目,保护措施是否独立于软件存在。

建议建立实验表,至少记录原始值、处理值、单位、采样周期、错误次数、供电方式和测试结论。遇到偶发问题时,再增加启动次数和运行时长。工程经验常常不是来自“成功一次”,而是来自知道失败出现在哪个边界。

十、还能怎么扩展

可以连接多个 VL53L0X 做环形测距、多个环境传感器做机柜温度分布,或搭建批量模块老化测试台。多块 TCA9548A 还能通过地址引脚继续扩展,但设备越多,轮询周期、布线电容和故障定位成本也会一起增长。

扩展功能时仍然遵循一次增加一层的原则。先证明新模块独立工作,再接入现有状态机;先保存原始值,再绘制漂亮曲线。这样教程不仅能展示结果,也能给读者留下一条可以照着走的排错路线。

十一、总结

本项目的重点不是某一行库函数,而是把硬件、数据、状态和异常组合成一个可解释的小系统。能读取只是起点,能标定、能发现错误、能恢复、能留下日志,才算真正完成。实际制作后,建议继续补充接线照片、串口截图和一次真实失败记录,这些往往比“运行成功”四个字更有参考价值。

参考资料

打赏

如果这篇学习记录对你有帮助,欢迎扫码支持后续整理。

打赏码

打赏支持:王庆岩

posted on 2026-10-06 00:30  潇洒石头  阅读(17)  评论(0)    收藏  举报

导航