1. 从I2C总线的老毛病说起:为什么要给总线加一个“分线开关”
做嵌入式这些年,I2C应该是我用得最多、也最容易被它坑的总线。两根线、一堆设备、地址一配就能跑,看起来比SPI、UART都省事,可真到了产品里挂上五六个设备的时候,问题就一件接一件地冒出来。地址冲突算一个,总线电容超标算一个,某一个从设备把SDA拉死导致整条总线瘫痪更是家常便饭。这个时候,PCA9546A这种带I2C地址选择功能的四路双向转换开关,就成了很多人方案里默默救场的那颗芯片。
1.1 I2C挂多设备时最常踩的三个坑
先说说I2C为什么会有这么多限制。I2C是开漏结构,所有设备的SDA和SCL引脚都是开漏输出,要靠外部上拉电阻把电平拉高。设备多了以后,每个引脚的引脚电容、PCB走线寄生电容、上拉电阻本身的寄生参数都会叠加到总线上,结果就是总线电容越来越大,信号的上升沿越来越缓。
第一个坑就是地址冲突。I2C的7位地址空间里,很多外设芯片只留了1到3个地址引脚,比如常见的AT24C02只能选8个地址,OLED的SSD1306基本固定在0x3C或0x3D。两块屏、两片EEPROM、一个温湿度传感器,地址就撞车了。地址撞了以后,数据根本不是“乱”的问题,而是两个设备同时响应同一个地址,SDA上的数据直接变成“线与”打架,读回来的数据全是0xFF或者随机值。
第二个坑是总线电容。I2C规范里,标准模式100kHz时总线电容上限是400pF,快速模式400kHz时上限更严。实际打板的时候,一挂传感器、屏幕、EEPROM,走线再绕几圈,电容轻轻松松就超了。电容一大,SCL和SDA的上升沿变缓,从设备就可能把高电平误判成低电平,通信就会随机出错。这种问题用示波器看才明显,裸眼很难排查。
第三个坑是单点故障。I2C总线上只要有一个设备把SDA拉低不放,整条总线就瘫痪了,其他设备全部跟着遭殃。比如某块屏幕在上电时序不对的时候死锁,或者某片传感器在调试时被错误写入配置,SDA就可能被死死拉住。这时候你查主控代码、查上拉电阻、查逻辑分析仪,全都正常,但总线上就是一片低电平。
1.2 PCA9546A到底是个什么东西
PCA9546A是NXP(原Philips)推出的一颗I2C多路复用/选择开关芯片,封装很小,SOIC、TSSOP都有,工作电压范围是2.3V到5.5V,可以直接兼容3.3V和5V系统。它的核心逻辑很简单:主控通过I2C总线向PCA9546A写一个字节的控制寄存器,这个字节的低4位分别对应4个下游通道的开关,写1就接通,写0就断开。
芯片本身不参与数据内容,它就是一个模拟开关,把主控的SCL/SDA物理上切换到对应的下游通道。下游设备还是挂在原生的I2C总线上,主控写0xE0地址,PCA9546A会“导通”某一路,之后主控再访问下游设备时,通信数据就会经过开关走向对应通道。
我打个比方,PCA9546A就像一个四路电源排插,总线是入户电线,四个通道是你房间里的四个插座。平时排插总闸可以拉掉,四个插座全部断电;需要哪个房间用电,就把对应的支路开关合上,其他房间保持断电。这样每个房间互不干扰,就算某个房间的电器短路了,也不会把整个屋子都烧了。
1.3 这款芯片解决的核心痛点
PCA9546A解决的核心问题可以归纳成三点。第一,它把同一地址的多个设备从“物理同一条总线”变成“逻辑上分时复用同一条总线”,地址冲突的问题迎刃而解。第二,它能把总线电容分开管理,每次只导通一路,等效总线上挂的设备数量大幅减少,信号质量明显改善。第三,它天然提供了故障隔离能力,某个通道的下游设备把总线拉死时,只要把该通道关断,其他通道依然能正常工作。
当然,它也不是万能的。它做不了电平转换,下游通道的电压不能超过芯片的VCC,而且它本身也是一个I2C从设备,地址也要靠A0、A1引脚来配。后面我会把这些注意事项一个个展开讲。
2. 硬件基础与电路搭建:引脚、封装、上拉电阻一个都不能错
PCA9546A这种芯片看着不起眼,但硬件上如果接错了,后面调试能折腾掉你半天时间。先看引脚功能,再看怎么搭电路,重点讲清楚几个容易被忽略的电气细节。
2.1 引脚定义与选型细节
PCA9546A的引脚不算多,典型封装是16脚TSSOP或者14脚SOIC,具体以你买到的封装为准。核心引脚包括:
- SCL/SDA:主控侧的I2C时钟和数据线,连接主控的I2C总线。
- SC0-SC3/SD0-SD3:四路下游通道的时钟和数据线,分别接到四组外设。
- A0/A1:地址选择引脚,用于配置芯片自身的I2C地址,必须外部接高或接低,不能悬空。
- VCC/GND:电源和地,VCC范围2.3V到5.5V。
选型的时候要注意,市场上还经常能看到PCA9546A的“近亲”TCA9546A,两者功能几乎一样,TCA9546A的工作电压范围更宽一点(1.65V到5.5V),适合低压系统。我自己一般3.3V系统下两者混用都没问题,但如果你的主控是1.8V供电,就必须选TCA9546A。
还有一个很容易被弄混的型号是PCA9548A,那是8通道版本,寄存器定义和用法有区别,不能用PCA9546A的驱动直接套。买芯片前一定看清楚后缀和丝印,不是所有“9546”都一样,有些国产兼容芯片的寄存器行为并不完全一致,上板前先看数据手册。
2.2 地址是怎么算出来的
I2C地址是7位,PCA9546A的固定前缀是“1110”,后跟A1和A0两个引脚电平。所以7位地址就是0x70加上A1左移一位再加A0。
具体来说:
| A1 | A0 | 7位地址 | 写地址字节 | 读地址字节 |
|---|---|---|---|---|
| 0 | 0 | 0x70 | 0xE0 | 0xE1 |
| 0 | 1 | 0x71 | 0xE2 | 0xE3 |
| 1 | 0 | 0x72 | 0xE4 | 0xE5 |
| 1 | 1 | 0x73 | 0xE6 | 0xE7 |
这里注意,I2C的地址在发送的时候是8位,低1位是读写标志位。所以你在代码里写HAL_I2C_Master_Transmit时,如果用的是STM32 HAL库,传入的地址参数是8位写地址0xE0或0xE2这样的值。很多新手写代码时传了0x70,导致芯片一直无应答,这个坑我当年也踩过。
A0和A1引脚内部没有上拉也没有下拉,必须外部电路明确拉高或拉低。有的板子上为了省事直接把A0、A1接地,如果总线上只挂一颗PCA9546A,那没问题;如果还要级联多颗,就必须给不同芯片配不同地址,不能全部接地。
2.3 上拉电阻怎么配才合理
PCA9546A的开关在关断状态下,下游通道与主控总线是完全断开的,所以理论上主控总线和各下游通道可以分别配各自的上拉电阻。我见过很多参考设计,主控侧上拉4.7kΩ,每个下游通道也各自上拉4.7kΩ。但要注意的是,当通道导通时,主控侧和该通道的上拉电阻是并联关系。
举个例子,如果主控侧上拉是4.7kΩ,某一路通道上拉也是4.7kΩ,导通后等效上拉电阻变成2.35kΩ。四路全部导通时,等效上拉电阻变成不到1kΩ,总线低电平时的灌电流明显增大,从设备的IOL可能吃不消,低电平电压会被抬高,通信就会失败。
所以我一般建议,常规3.3V/400kHz系统里,主控侧和每个通道的上拉电阻都用4.7kΩ到10kΩ之间,按需逐个通道打开,不要图省事一次性全开。如果确实要同时开多个通道,就要重新算上拉电阻,确保最坏情况下低电平仍然低于从设备的VIL阈值。
从电气安全角度看,下游通道的电源电压不能高于PCA9546A的VCC,因为芯片内部的模拟开关和ESD保护结构会形成寄生二极管,一旦下游电压高于VCC,电流会通过寄生路径倒灌,轻则漏电,重则烧毁芯片。
3. 控制机制详解:一个字节就搞定四路开关
PCA9546A的控制逻辑应该是I2C系列芯片里最简单的一类了,但简单不等于没有细节。如果你把控制寄存器读回来,或者在某些特殊场景下误操作,还是会遇到一些意料之外的行为。这一节把寄存器、时序和复位逻辑一次讲透。
3.1 控制寄存器0x00:低四位就是四路开关
PCA9546A内部只有一个8位控制寄存器,地址是0x00。寄存器低4位对应四路通道,Bit0对应通道0,Bit1对应通道1,以此类推。写入1代表将该通道导通,写入0代表断开。高4位没有定义,一般写0。
这里有个非常容易踩的坑:你向PCA9546A写入任意一个字节时,这个字节会被当作控制寄存器的值,而不是“操作命令”。比如不小心向芯片写入了0x80,高4位的值被忽略,低4位都是0,结果就是所有通道全部关闭。如果你是在代码里封装了一个通用的I2C写函数,参数里带了寄存器地址0x01之类,PCA9546A会把0x01当成控制值,只打开通道0,逻辑就乱了。
我自己的习惯是在驱动层单独封一个函数,比如:
#define PCA9546A_ADDR_W 0xE0 uint8_t pca9546a_select_channel(uint8_t ch) { uint8_t data = 0x01 << ch; // 只允许ch取0~3 return HAL_I2C_Master_Transmit(&hi2c1, PCA9546A_ADDR_W, &data, 1, 100); }这个函数只负责“选择通道”,不涉及其他I2C操作,调用的人不会误传寄存器地址。屏蔽层越薄,出错概率越小。
3.2 写操作时序与常见误区
写PCA9546A的标准时序是:起始位、写地址字节(0xE0到0xE6之间的偶数)、控制寄存器值、停止位。注意这里不需要先写寄存器地址,因为控制寄存器就是唯一的寄存器,你发的第一个数据字节就是控制值,和AT24C02这类需要先发内部地址的EEPROM完全不同。
很多从EEPROM驱动转过来的人,会习惯性地先发一个0x00作为内部地址,再发控制值。这样一来,第二次发送的0x01会被当成新的数据,但因为一次I2C写事务已经结束了,芯片实际收到的是前一个字节0x00,也就是所有通道关闭,然后再收到一个0x01只会被丢弃或者触发异常。现象就是“我明明发了数据,芯片没反应”。
正确做法用一个事务完成写操作。HAL库下面就是一句话:
uint8_t ctrl = 0x04; // 打开通道2 HAL_I2C_Master_Transmit(&hi2c1, 0xE0, &ctrl, 1, 100);如果我用Linux用户态i2c-tools调试,那更简单:
i2cset -y 1 0x70 0x04这里0x70是7位地址,i2cset会自动转换成写地址0xE0。很多人在命令行里直接写0xE0,反而会被工具当成7位地址处理,导致找不到设备,这个细节也要注意区分。i2c-tools里的地址参数是7位地址,不含读写位。
3.3 读控制寄存器有什么意义
读操作通常是发一个读地址字节(例如0xE1),然后从芯片读回当前控制寄存器的值。PCA9546A支持读回,好处是你可以确认当前哪个通道是导通的。
这在调试时特别有用。比如程序跑到某个状态发现I2C通信异常,你可以先读一下PCA9546A的控制寄存器,看看当前到底选了哪一路。如果读回来是0x00,说明所有通道都关闭,那下游设备自然无应答;如果读回来是0x05,说明通道0和通道2同时导通,你要检查是不是代码里没有先关通道就切到另一路了。
读操作还有一种用法是总线健康检查。上电后先读一次寄存器,如果NACK,说明PCA9546A没正常工作,优先排查电源和地址引脚,而不是去查下游设备。
3.4 复位与上电默认状态
PCA9546A没有复位引脚,复位只能靠掉电。上电后控制寄存器默认值是0x00,即所有通道关闭。这个特性在多数场景下是好事,它保证了下游总线在上电期间处于隔离状态,不会出现主控还没初始化就有一堆从设备争抢总线的情况。
但反面也很明显:如果你上电后直接去访问下游设备,而忘了先选择通道,那必然是无应答。很多“I2C探测不到设备”的问题,查到最后发现是PCA9546A通道没有打开。
还有个细节值得注意:PCA9546A本身不会像EEPROM那样记住通道状态,每次上电都要重新配置一次。所以接通通道这个动作要放在外设初始化代码里,不能只做一次就以为万事大吉。
4. 实战案例:STM32HAL库驱动PCA9546A扩展四路OLED
理论讲了一堆,不如直接跑一个完整例子。这个例子的场景很典型:一块主控板需要接4个I2C接口的OLED显示屏,它们默认地址都是0x3C,无法同时挂同一条总线。用PCA9546A做四路扩展,通过切换通道来分别点亮每一块屏。
这个场景几乎覆盖了PCA9546A的所有核心操作,代码写一遍,你就能掌握这颗芯片的用法。
4.1 场景设计与硬件连接思路
四块OLED,地址全是0x3C,如果直连一条总线,地址冲突后四块屏显示的内容会完全一样,因为你发到0x3C的数据会被四块屏同时接收。解决办法就是用PCA9546A把四块屏分别放在4个通道上,同一时刻只导通一块屏的通道,其余通道断开。
硬件连接上,主控的I2C1_SCL和I2C1_SDA接到PCA9546A的SCL/SDA,PCA9546A的SC0/SD0接OLED0,SC1/SD1接OLED1,SC2/SD2接OLED2,SC3/SD3接OLED3。A0和A1都接地,芯片地址就是0x70(7位),写地址0xE0。
四块OLED的VCC和GND正常接电源,I2C引脚上的上拉电阻用4.7kΩ即可。主控的I2C总线也配上拉电阻,注意总线上电时序,让OLED先完成硬件复位再通信。
4.2 核心驱动代码
先是PCA9546A的驱动,这段代码我直接贴出来,注释里写清楚使用注意点:
#include "i2c.h" #define PCA9546A_ADDR_W 0xE0 // A0=0, A1=0 的写地址 #define PCA9546A_ADDR_R 0xE1 // 读地址 uint8_t pca9546a_read_register(void) { uint8_t val = 0; HAL_I2C_Master_Receive(&hi2c1, PCA9546A_ADDR_R, &val, 1, 100); return val; } uint8_t pca9546a_select_channel(uint8_t ch) { uint8_t data; if (ch > 3) return 1; data = 0x01 << ch; return HAL_I2C_Master_Transmit(&hi2c1, PCA9546A_ADDR_W, &data, 1, 100); } uint8_t pca9546a_close_all(void) { uint8_t data = 0x00; return HAL_I2C_Master_Transmit(&hi2c1, PCA9546A_ADDR_W, &data, 1, 100); }然后是操作OLED的代码,比如选择通道0并显示一行字:
void oled_show_on_channel(uint8_t ch, char *str) { pca9546a_select_channel(ch); OLED_Clear(); OLED_ShowString(0, 0, str); OLED_Update(); }这里最关键的一步,就是每次切换通道前,必须先明确“上一步选的通道是否已经断开”。如果程序在通道0显示完,想切到通道1,你直接调pca9546a_select_channel(1),这时候控制寄存器的值是0x01或0x03,取决于之前的状态。因为每次写控制寄存器都是用新值覆盖旧值,所以直接传1<<1=0x02就能把通道0关掉、通道1打开,不需要额外关闭全部通道。
不过我在实际调试时发现,有些国产兼容芯片在“通道切换瞬间”可能会产生毛刺,下游从设备偶尔会收到一个不完整的起始条件。为了稳妥,我习惯在切换通道后加一个小延时,比如100us,再开始访问OLED。这个延迟可以避免莫名其妙的首帧花屏问题。
4.3 扫描所有通道,快速定位设备
调试硬件的时候,我最推荐做的事是写一个“通道扫描+设备扫描”函数。它遍历4个通道,在每个通道里扫描0x03到0x77的所有I2C地址,看看哪些设备在线。这样一块板子拿到手,5分钟就能确定PCA9546A的通道接线是否正确,以及每个通道上挂的从设备地址是什么。
参考实现:
void pca9546a_scan_all_channels(void) { for (uint8_t ch = 0; ch < 4; ch++) { pca9546a_select_channel(ch); HAL_Delay(1); printf("Channel %d: ", ch); for (uint8_t addr = 0x03; addr < 0x78; addr++) { // 7位地址左移1位变成8位写地址 if (HAL_I2C_IsDeviceReady(&hi2c1, (uint16_t)(addr << 1), 1, 10) == HAL_OK) { printf("0x%02X ", addr); } } printf("\r\n"); } pca9546a_close_all(); }这个扫描代码虽然简单,但在现场排查问题的时候特别顶用。我曾经遇到一个板子,通道2上应该挂着一颗温湿度传感器,但扫描显示为空。后来发现是PCB上通道2的SC2和SD2丝印画反了,PCB走线把SD2接到了SCL,把SC2接到了SDA。这种问题用代码扫一遍立马暴露,省得拿万用表一个一个戳。
4.4 如果主控是Linux系统怎么操作
现在很多项目直接上树莓派、RK3588这样的Linux平台,操作PCA9546A就更方便了。Linux内核自带了pca954x的驱动,Device Tree里配一下就行,i2c-mux节点会把下游通道注册成虚拟的i2c bus,应用层直接打开对应bus号访问从设备,完全不用手动切通道。
一个简单的Device Tree片段示例:
&i2c1 { pca9546a: pca9546a@70 { compatible = "nxp,pca9546"; reg = <0x70>; #address-cells = <1>; #size-cells = <0>; i2c-mux-idle-disconnect; }; };内核驱动加载后,系统里会多出i2c-2、i2c-3、i2c-4、i2c-5四个bus(具体编号取决于系统)。你直接对对应bus操作,就能访问每块OLED,不用关心底层开关状态。这也是PCA9546A生态成熟的一个体现,驱动都是现成的,集成成本很低。
5. 常见问题与排查技巧实录
PCA9546A本身不复杂,但我用了这么多年,大大小小的坑都遇过。这里挑几个典型问题整理成速查表,再补充一些独家排查思路,遇到类似情况可以直接对号入座。
5.1 开关“没反应”怎么办
现象:往PCA9546A写入控制值后,读回寄存器还是0x00,下游设备怎么都访问不到。
排查顺序:
- 先确认你写的地址对不对。HAL库传的是8位地址0xE0,i2c-tools里传的是7位地址0x70,两边不要混。
- 量VCC引脚电压是否正常,PCA9546A对电源纹波不敏感,但低于2.3V它就不工作。
- 查A0/A1引脚是否接了明确电平,悬空的状态在万用表上看可能是高,但上电瞬间的浮空电平会导致地址随机。
- 用示波器抓SCL和SDA,看主控有没有发出起始条件,有没有ACK信号。能抓到波形,说明芯片在工作,问题在通道或下游设备;抓不到波形,问题在主控侧配置。
还有一个隐蔽问题:如果主控的I2C总线上挂了多个设备,有一个设备地址恰好和PCA9546A冲突,比如0x70,那么主控发0xE0时可能会被两个设备同时响应,ACK时序混乱,表现为“有时候能通,有时候不通”。这种只能靠逐个摘设备来排查。
5.2 打开某通道后SDA一直被拉低
这是I2C总线最常见的死锁现象。现象是:你一旦打开某个通道,SDA立刻变成低电平,主控后续所有I2C通信都超时。
这种问题90%出现在下游设备的SDA被它自己拉死。可能原因包括:下游设备供电异常、I2C地址配置错误导致设备状态机混乱、设备处于busy状态需要复位。PCA9546A的通道隔离反而帮了我们一个大忙,因为其他没导通的通道不受影响,你可以逐个通道去试探,看是哪个下游设备搞的鬼。
排查时可以写一个只打开通道、不访问任何从设备的测试函数。打开通道后等100ms,再用读PCA9546A寄存器的方式间接判断下游总线状态。如果能读到寄存器值,说明开关本身没问题,SDA被拉低大概率是下游设备或下游上拉的问题。
5.3 通道全开时通信质量下降
有朋友为了图省事,把控制寄存器写成0x0F,四路全开,然后四块屏幕同时显示。这样做通信质量会明显下降,尤其总线频率用400kHz时,上升沿变得很缓,偶尔还会出现屏幕花屏。
原因就是我在2.3小节里说的,四路通道的上拉电阻全部并联,等效电阻变小,总线负载变重。如果必须全开,有几个补救办法:把每个通道的上拉电阻从4.7kΩ改成10kΩ,降低并联后的整体影响;降低I2C时钟频率到100kHz;或者干脆改硬件设计,在每路通道上加一个MOS管电平隔离,需要哪路再打开哪路。
我的建议是,PCA9546A的定位本来就是“分时复用”,不是“同时并联”。如果应用场景确实是多个设备要同时访问,那PCA9546A可能不是最优解,可以考虑换成I2C转SPI的桥接芯片,或者给总线加I2C缓冲器,而不是开关。
5.4 通道切换瞬间的毛刺问题
这是我后来做高精度传感器数据采集时才注意到的。PCA9546A是模拟开关,切换瞬间会有短暂的导通电阻变化和电容充放电,理论上会在下游总线上产生毛刺。对OLED这种显示设备无所谓,但如果下游挂的是高精度ADC、温湿度传感器,或者正在做连续I2C读取,毛刺可能导致数据错位。
最保险的做法是:关断旧通道、打开新通道之后,延迟几个毫秒再启动下游通信;同时在下游每个设备的SDA/SCL上加一个1nF左右的滤波电容,吸收毛刺。这个电容不能太大,否则会拖慢上升沿,反而弄巧成拙。
6. 除了扩展I2C设备,它还能这么用
你以为PCA9546A只是用来“分线”的吗?它的开关特性其实还能玩出很多花活。这里分享几个我实际项目中用过的思路,扩展一下你的想象力。
6.1 用PCA9546A做总线级热插拔保护
I2C不支持热插拔,因为热插拔瞬间的毛刺可能把总线上其他设备的状态机打乱。但用PCA9546A可以做成“软插拔”:先把对应通道关断,再接上或拔掉下游设备,然后再打开通道。这样每次插拔只影响该通道,主控总线和其它通道完全不受影响。
我做过一个多传感器采集盒子,带多个RJ45接口,用户可以随时插拔温湿度探头。每个探头对应PCA9546A的一个通道,系统每秒钟扫描一次各通道的设备在位状态。用户插入新探头时,Linux系统里就能自动识别并读取数据;拔出时也不会导致整个I2C总线崩溃。这个方案比单纯用I2C总线加ESD保护可靠得多。
6.2 级联扩展:一个不够就串两个
一颗PCA9546A只有4个通道,如果设备特别多,可以用片选方案级联。第一颗芯片的通道0接第二颗PCA9546A的SCL/SDA,第二颗芯片的A0/A1配成不同地址,这样第一颗选通道0,第二颗再选它的下属通道,最多能挂出4×4=16个通道。
级联时要注意两点:一是每一级的总线电容要重新算,层级越多,主控到目的设备之间的开关导通电阻累积越大,信号质量越差;二是地址分配不能冲突,第一颗和第二颗的A0/A1必须不同。我实际用两颗PCA9546A级联驱动过8路传感器,通信速率放到100kHz完全稳定,400kHz会出现偶发超时,所以级联方案里优先降低总线速率。
6.3 对比同类芯片,怎么选才不踩坑
和PCA9546A类似功能的芯片还有几款,选择时要根据场景区分:
| 芯片 | 通道数 | 中断输入 | 特点 |
|---|---|---|---|
| PCA9546A | 4 | 无 | 经典款,便宜,够用 |
| PCA9545A | 4 | 有 | 带中断输入,适合传感器场景 |
| PCA9548A | 8 | 无 | 通道更多,寄存器映射不同 |
| TCA9546A | 4 | 无 | 低压版,支持1.65V |
如果你的下游设备里面有中断引脚,比如触摸屏、多路按键,优先选PCA9545A,它能把中断信号也一并切换给主控。如果只是单纯扩展OLED、EEPROM这种无中断设备,PCA9546A完全够用,没必要多花钱。如果通道数超过4个但不想级联,直接上PCA9548A也行,它的控制寄存器是字节映射,一次可以配置多路状态。
前面那个ST7789屏幕的例子里,因为OLED没有中断脚,用PCA9546A就绰绰有余。芯片体积小、价格低,一颗不到两块钱,PCB上占的地方也小,性价比很高。
最后再分享一个小技巧
如果你和我一样经常用逻辑分析仪调试I2C,建议在PCA9546A的输出侧挂一个很小的测试点,比如在每个通道的SCx/SDx上预留一个0欧电阻位。调试时把0欧电阻摘掉,就能把逻辑分析仪直接夹在通道和主控之间,方便看到底是主控没发数据,还是下游设备没应答。这个小设计在PCB上只多花几秒钟,却能帮你省下大量的排查时间。
另外,如果你在写程序时发现OLED通过PCA9546A显示偶尔花屏,别急着改屏幕驱动,先去看看是不是切换通道后立刻写数据导致的。我的经验是,在切换通道和访问设备之间加一个1ms左右的延时,能让信号稳定下来,很多莫名其妙的花屏、误码问题就自动消失了。
PCA9546A不是一个让人兴奋的芯片,它没有复杂的功能,也没有花哨的算法,但它就是把I2C这条“独木桥”变成“立交桥”的关键角色。做嵌入式越久越发现,真正让系统稳定运行的,往往就是这些不起眼的小芯片。希望这篇内容能帮你在下次遇到I2C多设备挂载问题时,第一时间想到这个四路开关。