TCA9534 I/O扩展器实战:I2C地址配置、寄存器详解与驱动代码

📅 2026/7/25 11:16:35
TCA9534 I/O扩展器实战:I2C地址配置、寄存器详解与驱动代码
1. 项目概述为什么我们需要I/O扩展器在嵌入式项目里摸爬滚打十几年我遇到最多的硬件限制之一就是微控制器MCU的GPIO通用输入输出引脚不够用。无论是早期的8位单片机还是现在功能强大的32位ARM Cortex-M系列引脚资源永远是稀缺的。项目初期你可能觉得引脚绰绰有余但随着功能不断叠加——几个按键、几颗状态LED、一个显示屏、几个传感器——GPIO很快就捉襟见肘。这时候有经验的工程师不会去换一个引脚更多的、更贵的MCU而是会想到一个更经济、更灵活的方案I/O扩展器。I/O扩展器顾名思义就是用来扩展输入输出端口的芯片。它通过某种通信总线最常见的就是I2C和SPI与主MCU连接主MCU只需要占用2根线I2C的SDA和SCL或4根线SPI就能额外控制8个、16个甚至更多的数字IO口。这就像给你的MCU装上了“USB Hub”用有限的接口换来了巨大的扩展能力。在众多I/O扩展器中德州仪器TI的TCA9534是一款非常经典且广泛使用的器件。它采用I2C接口提供8个可独立配置为输入或输出的端口支持极性反转还带有一个中断输出引脚可以高效地通知MCU端口状态变化。无论是工业控制板上的按钮和指示灯管理还是智能家居设备中连接多个传感器TCA9534都是解决GPIO瓶颈的利器。然而把芯片焊到板子上只是第一步。真正让它在你的系统中跑起来关键在于理解并正确配置两件事设备地址和内部寄存器。地址决定了MCU如何在I2C总线上找到它寄存器则像它的“控制面板”每一个比特位都对应着一个具体的功能设置或状态读取。很多新手工程师在这里栽跟头要么地址冲突导致通信失败要么寄存器配置错误使得IO口行为诡异。本文将围绕TCA9534抛开数据手册中繁杂的电气参数聚焦于工程师最关心的实战部分从硬件地址引脚焊接开始到每一个寄存器的位操作详解再到I2C读写时序的代码级还原为你彻底讲透这颗芯片的使用精髓。2. 核心基石TCA9534的设备地址解析与硬件配置要让主MCU和TCA9534说上话首先得让MCU知道“叫谁”。在I2C总线上这个“名字”就是7位的设备从地址Slave Address。TCA9534的地址并非固定不变它的一部分由芯片内部固化另一部分则交给了我们工程师通过硬件引脚来设定这为在同一总线上挂载多个同型号器件提供了可能。2.1 地址字节的构成与寻址原理TCA9534的完整I2C地址字节是8位但有效地址是7位最低位LSB是读/写R/W方向位。在发起通信时主设备发送的第一个字节就是这8位。我们拆开来看固定部分与可配置部分根据数据手册TCA9534的7位从地址格式为0100 A2 A1 A0。0100这是芯片型号的固定标识符由TI公司分配对于TCA9534系列这个前缀是固定的。A2, A1, A0这三位就是我们可以通过硬件配置的地址位。它们分别对应芯片物理引脚A2、A1、A0的电平状态。R/W位的作用第8位即字节的最低位是读/写控制位。当这一位为0时表示主设备接下来要执行写操作向TCA9534发送数据为1时表示要执行读操作从TCA9534读取数据。这个位是由I2C控制器硬件自动根据你的操作类型添加的在编程时我们通常只关心7位地址。2.2 硬件地址引脚配置实战A2, A1, A0这三个引脚的状态接高电平VCC或低电平GND直接决定了芯片的7位地址。数据手册提供了一个清晰的对照表但我们需要理解其二进制逻辑。地址计算与对照表我们将0100看作二进制的高4位A2 A1 A0作为低3位组合成一个7位二进制数再转换为十六进制和十进制就是最终的设备地址。硬件引脚电平 (A2 A1 A0)7位二进制地址十六进制地址十进制地址备注L L L0100 0000x2032全部接地L L H0100 0010x2133L H L0100 0100x2234L H H0100 0110x2335H L L0100 1000x2436H L H0100 1010x2537H H L0100 1100x2638H H H0100 1110x2739全部接VCC实操心得一地址引脚的硬件连接在实际PCB布局中A2/A1/A0引脚强烈建议通过电阻上拉或下拉而不是直接连接到VCC或GND。例如通过一个10kΩ电阻连接到GND下拉来设置0通过一个10kΩ电阻连接到VCC上拉来设置1。这样做的好处是在调试阶段你可以通过焊锡短路或切断电阻旁的跳线帽/0欧姆电阻来临时更改地址而无需飞线或重新焊接芯片极大提升了调试灵活性。多设备级联场景假设你的系统需要控制24个LED但MCU的IO口不够。你可以使用3片TCA9534将它们挂在同一条I2C总线上。只需将三片芯片的A2A1A0引脚分别配置为000001010对应地址0x20 0x21 0x22。这样MCU通过发送不同的地址就能分别与三片芯片通信控制总共24个IO口。这是I2C总线多从机架构的典型应用。注意事项I2C总线地址冲突在设计系统时必须确保总线上所有I2C设备的7位地址唯一。除了TCA9534总线上可能还有EEPROM如AT24C02地址常为0x50、温度传感器如LM75地址为0x48等。务必在设计初期列出所有设备的地址检查是否有冲突。地址冲突是I2C通信失败最常见的原因之一。3. 内部控制核心四大寄存器详解与操作逻辑成功寻址后MCU与TCA9534的对话就进入了“寄存器操作”阶段。你可以把TCA9534想象成一个有4个特殊功能房间寄存器的小房子每个房间有8个开关8个比特位分别控制着8个IO引脚P0-P7的不同属性。MCU通过发送“命令字节”来指定要进入哪个房间然后进行读写操作。3.1 命令字节访问寄存器的钥匙在发送设备地址并得到应答ACK之后主MCU必须紧接着发送一个命令字节。这个字节的唯一作用就是告诉TCA9534“我接下来要操作哪个寄存器”。命令字节本身也会被存入TCA9534内部的一个控制寄存器中。命令字节很简单只有低2位B1和B0有效高6位必须为0。控制寄存器位 (B1 B0)命令字节 (十六进制)对应的寄存器操作协议上电默认值0 00x00输入端口寄存器只读字节XXXX XXXX (取决于外部电平)0 10x01输出端口寄存器可读/可写字节1111 11111 00x02极性反转寄存器可读/可写字节0000 00001 10x03配置寄存器可读/可写字节1111 1111关键机制一旦发送了一个命令字节例如0x03后续的读操作就会一直访问这个被选中的寄存器配置寄存器直到你发送一个新的命令字节来改变目标。这个特性在连续读取多个字节时需要注意。3.2 四大寄存器功能深度剖析3.2.1 寄存器0输入端口寄存器 (只读 命令字节 0x00)功能这个寄存器是外部世界状态的“镜子”。它直接反映P0-P7这8个引脚上当前的实际逻辑电平高或低与你将这个引脚配置为输入还是输出无关。操作只能读取不能写入。写入操作无效。默认值上电后寄存器的值是不确定的XXXX XXXX因为它完全取决于每个引脚外部连接的电平。应用场景读取按键状态、传感器数字输出、中断信号等。例如将一个按键一端接P0另一端接地并启用内部上拉电阻通过配置寄存器当按键按下时读取输入端口寄存器的bit0就会是0。3.2.2 寄存器1输出端口寄存器 (可读/写 命令字节 0x01)功能控制那些被配置为输出的引脚的电平。你可以向这个寄存器写入数据来设置输出高或低也可以读取它来查看你上次设置的值。重要区别读取这个寄存器得到的不是引脚上的实际电压而是内部锁存器的值。如果外部电路将输出引脚强行拉高或拉低例如短路读取该寄存器依然会返回你之前写入的值而不是实际引脚电平。要获取实际电平必须读输入端口寄存器。默认值上电默认所有位为1高电平。这意味着如果某个引脚被配置为输出上电瞬间它会输出高电平。在设计需要上电安全状态的系统如上电默认关闭继电器时必须考虑这一点可能需要外部下拉电阻或软件初始化后立即拉低。应用场景驱动LED、控制继电器、使能其他芯片等。3.2.3 寄存器2极性反转寄存器 (可读/写 命令字节 0x02)功能这是一个非常实用的功能用于反转被配置为输入的引脚的电平逻辑。当某一位设置为1时对应引脚的输入逻辑将被反转外部高电平读为0外部低电平读为1设置为0时保持原始极性。默认值所有位为0不反转。应用场景简化软件逻辑。例如你的按键电路设计是按下时产生低电平但你的软件习惯处理“按下为1”。此时你可以将该按键对应引脚的极性反转位设为1这样读取输入端口时按下按键读到的就是1释放则是0无需在软件中再做一次逻辑取反。3.2.4 寄存器3配置寄存器 (可读/写 命令字节 0x03)功能这是最重要的寄存器决定了每个引脚的根本角色——是输入还是输出。位 1将对应引脚配置为输入。此时引脚呈高阻抗状态用于读取外部信号。作为输入时可以启用内部上拉电阻需注意TCA9534本身没有内部可编程上拉电阻此功能需依赖MCU的I2C总线内部上拉或外部增加上拉电阻。对于输入引脚通常需要在外部连接上拉电阻以确保默认状态。位 0将对应引脚配置为输出。此时可以驱动电流输出高电平或低电平。默认值所有位为1。这意味着芯片上电后所有8个引脚默认都是输入模式。这是一个安全的设计防止上电瞬间引脚意外输出驱动外部电路。核心操作流程在使用任何一个引脚前你必须先通过配置寄存器将其设置为输入或输出模式然后才能对其进行读输入端口寄存器或写输出端口寄存器操作。实操心得二配置寄存器的使用顺序正确的初始化流程应该是先配置再操作。写配置寄存器 (0x03)设定P0-P7中哪些是输入哪些是输出。例如0xF0二进制1111 0000表示P7-P4为输入P3-P0为输出。写输出端口寄存器 (0x01)为那些配置为输出的引脚设置初始输出电平。可选写极性反转寄存器 (0x02)如果需要为输入引脚设置极性反转。在程序运行中读输入端口寄存器 (0x00)获取输入状态写输出端口寄存器 (0x01)改变输出状态。4. I2C通信时序实战读写操作代码级还原理解了地址和寄存器最后一步就是通过I2C总线实现具体的读写操作。下面我们抛开抽象的时序图用具体的字节流和代码逻辑来还原整个过程。假设MCU作为主设备TCA9534的地址引脚A2A1A0全部接地即7位地址为01000000x20。4.1 写操作向寄存器写入数据场景我们将P0引脚配置为输出对应配置寄存器bit0设为0并让其输出高电平。步骤分解发送起始条件 (Start Condition)MCU拉低SDA线然后拉低SCL线启动通信。发送设备地址 写命令MCU发送一个字节0x40。怎么来的7位地址0100000(0x20) 左移一位变成01000000。加上R/W位写操作为0所以最低位是0结果还是01000000即0x40。TCA9534收到地址匹配在第9个时钟周期拉低SDAACK。发送命令字节MCU发送命令字节0x03表示接下来要操作配置寄存器。TCA9534再次回应ACK。发送数据字节MCU发送数据0xFE二进制1111 1110。这意味着将P0配置为输出bit00P1-P7保持为输入bit1-71。TCA9534回应ACK。发送停止条件 (Stop Condition)MCU拉高SDA线然后拉高SCL线结束本次传输。此时P0已被配置为输出模式但输出电平还是默认值输出寄存器默认全1即高电平。如果我们想让它输出低电平需要再写输出端口寄存器。再次发起传输发送地址0x40(ACK)。发送命令字节0x01选择输出端口寄存器 (ACK)。发送数据0x00假设我们只想让P0输出低其他输出位保持高或发送0xFE仅P0输出低P1-P7输出高——但注意P1-P7是输入模式输出寄存器的值对它们无效。TCA9534回应ACK。发送停止条件。连续写入示例配置设输出在实际编程中我们常用“复合写入”来减少通信次数。即在一个通信帧内连续写入多个数据字节。例如一次性设置配置寄存器和输出寄存器[Start] - 0x40 (ACK) - 0x03 (ACK) - 0xFE (ACK) - 0x01 (ACK) - 0x00 (ACK) - [Stop]但这种写法是错误的因为发送0xFE后控制寄存器指向了配置寄存器紧接着发0x01会被当作第二个数据字节写入配置寄存器而不是命令字节。正确做法是分两次独立的写操作。4.2 读操作从寄存器读取数据场景读取P1-P7配置为输入的当前状态。读操作比写操作多一步因为它需要先“告诉”芯片要读哪个寄存器然后再发起一次读请求。步骤分解发送起始条件。发送设备地址 写命令 (0x40) ACK。注意这里先发写命令发送命令字节 (0x00)选择输入端口寄存器 ACK。这一步就是“指针定位”。发送重复起始条件 (Repeated Start, Sr)。这是读操作的关键MCU在不释放总线不发停止条件的情况下再次发起一个起始条件。发送设备地址 读命令MCU发送0x41。0x20左移一位是0x40加上读命令位(R/W1)所以是0x41。TCA9534回应ACK。MCU释放SDA线切换为接收模式。TCA9534开始控制SDA线发送一个字节的数据即输入端口寄存器的值。MCU在接收完8位数据后在第9个时钟周期发送一个非应答 (NACK)表示“我只读一个字节够了”。MCU发送停止条件。注意事项读操作前的“哑写”务必记住在读取任何寄存器尤其是输入端口寄存器之前必须先进行一次写操作来发送命令字节以设定要读的寄存器地址。这是TCA9534以及很多I2C设备的典型协议。直接发起读操作芯片将不知道你要读哪个寄存器通常会返回NACK导致通信失败。4.3 代码片段示意基于模拟I2C以下是用C语言模拟I2C时序操作TCA9534的伪代码逻辑假设已有基本的I2C_Start(),I2C_Stop(),I2C_WriteByte(),I2C_ReadByte()等函数。#define TCA9534_ADDR 0x40 // 7位地址0x20 左移一位后为0x40 // 函数将TCA9534的某个引脚配置为输出并设置初始电平 void TCA9534_SetPinOutput(uint8_t pinNum, uint8_t level) { uint8_t configReg, outputReg; // 1. 首先读取当前的配置寄存器值避免影响其他引脚 I2C_Start(); I2C_WriteByte(TCA9534_ADDR); // 地址写 I2C_WriteByte(0x03); // 命令字节指向配置寄存器 I2C_Start(); // 重复起始条件 I2C_WriteByte(TCA9534_ADDR | 0x01); // 地址读 configReg I2C_ReadByte(1); // 读取配置字节参数1表示发送NACK I2C_Stop(); // 2. 清除该引脚对应的配置位设为0 输出模式 configReg ~(1 pinNum); // 3. 写入新的配置寄存器值 I2C_Start(); I2C_WriteByte(TCA9534_ADDR); I2C_WriteByte(0x03); // 命令字节配置寄存器 I2C_WriteByte(configReg); // 写入新的配置值 I2C_Stop(); // 4. 读取当前的输出寄存器值 I2C_Start(); I2C_WriteByte(TCA9534_ADDR); I2C_WriteByte(0x01); // 命令字节输出端口寄存器 I2C_Start(); I2C_WriteByte(TCA9534_ADDR | 0x01); outputReg I2C_ReadByte(1); I2C_Stop(); // 5. 设置或清除该引脚的输出位 if (level) { outputReg | (1 pinNum); } else { outputReg ~(1 pinNum); } // 6. 写入新的输出寄存器值 I2C_Start(); I2C_WriteByte(TCA9534_ADDR); I2C_WriteByte(0x01); // 命令字节输出端口寄存器 I2C_WriteByte(outputReg); I2C_Stop(); } // 函数读取TCA9534所有输入引脚的状态 uint8_t TCA9534_ReadInputs(void) { uint8_t inputVal; // 步骤写命令字节(0x00) - 重复起始 - 读数据 I2C_Start(); I2C_WriteByte(TCA9534_ADDR); // 写地址 I2C_WriteByte(0x00); // 命令字节指向输入端口寄存器 I2C_Start(); // 重复起始 I2C_WriteByte(TCA9534_ADDR | 0x01); // 读地址 inputVal I2C_ReadByte(1); // 读取一个字节发送NACK I2C_Stop(); return inputVal; }5. 高级应用与避坑指南掌握了基本读写我们来看看在实际项目中如何用好TCA9534以及那些数据手册里不会明说但能让你调试效率倍增的经验。5.1 中断INT引脚的高效使用TCA9534有一个开漏输出的中断引脚INT。当任何输入引脚的状态发生变化例如按键按下或传感器信号跳变时INT引脚会被拉低。这允许MCU不必持续轮询Polling输入状态而是通过外部中断来及时响应极大节省了MCU资源并降低了系统功耗。工作原理你通过配置寄存器将某些引脚设为输入。TCA9534会持续比较输入端口当前的电平与一个内部锁存的“上一次状态”。一旦发现不同立即将INT引脚拉低。MCU检测到INT引脚的中断信号后进入中断服务程序ISR。在ISR中MCU通过I2C读取输入端口寄存器。这个读取操作会自动清除中断条件INT引脚随之恢复高电平需外部上拉。实操心得三中断与软件消抖对于机械按键这类会产生抖动的输入源直接连接TCA9534的中断会导致多次误触发。建议的实践是在MCU的外部中断服务程序ISR中仅设置一个标志位然后立即退出。在主循环或一个低优先级任务中检测到这个标志位后先延时15-50ms消抖时间。延时后再通过I2C读取TCA9534的输入端口状态进行真正的按键处理。这样做避免了在ISR中进行耗时的I2C通信也解决了抖动问题。5.2 上拉电阻的计算与选择I2C总线需要上拉电阻Rp其阻值选择至关重要过大或过小都会导致通信失败。计算公式与考量最小值 Rp(min)由总线允许的最大低电平电流IOL和VCC、VOL决定。公式为Rp(min) (VCC - VOL(max)) / IOL。例如VCC3.3V VOL(max)0.4V IOL3mA 则Rp(min) ≈ (3.3-0.4)/0.003 ≈ 967Ω。通常要留有余量。最大值 Rp(max)由总线电容Cb和要求的上升时间tr决定。公式为Rp(max) tr / (0.8473 * Cb)。对于标准模式100kHz tr最大1μs快速模式400kHz tr最大300ns。Cb是总线上所有器件、走线、连接器的寄生电容之和一般估计在100-200pF。经验值在3.3V系统、总线长度小于0.5米、器件不多的情况下4.7kΩ是一个广泛适用且安全的选择。在5V系统中常用2.2kΩ或4.7kΩ。如果总线较长或器件很多电容大可能需要减小到2.2kΩ甚至1kΩ以确保上升时间。避坑指南电源轨与上拉电压务必确保I2C总线的上拉电阻接到与TCA9534的VCC相同的电源轨。如果SCL/SDA被上拉到一个在TCA9534断电时仍存在的电源上可能会导致芯片内部寄生二极管导通产生额外的漏电流增大功耗在电池供电应用中尤其要注意。5.3 典型问题排查实录问题1I2C通信完全无应答NACK。检查清单地址错误用逻辑分析仪或示波器抓取第一个地址字节核对是否与A2/A1/A0硬件设置匹配。这是最常见的问题。电源和地测量TCA9534的VCC和GND引脚电压是否正常。上拉电阻确认SCL和SDA线上有上拉电阻通常4.7kΩ且阻值合适。焊接与连接检查芯片是否虚焊I2C线路是否与其它信号短路。总线冲突确认总线上没有其他器件在错误地驱动SCL/SDA线。可以尝试暂时断开其他I2C设备。问题2可以写入但读取的数据不对或全为0xFF/0x00。检查清单读操作时序错误确认是否遵循了“先写命令字节定位再发起读操作”的流程。忘记发送重复起始条件Sr是常见错误。ACK/NACK时序在读取最后一个字节后主设备必须发送NACK然后紧跟停止条件。发送ACK会导致芯片继续发送下一个字节而下一个字节不存在或不正确。配置寄存器未设置如果引脚被配置为输出模式你去读输入端口寄存器得到的可能是未定义的值。确保在读之前目标引脚已配置为输入。问题3输出引脚驱动能力不足电平达不到预期。检查清单查阅数据手册查看IOL输出低电平电流和IOH输出高电平电流参数。TCA9534的驱动能力是有限的通常在10mA量级。负载过重如果你直接驱动一个LED而没有限流电阻或者驱动的负载电流超过芯片能力会导致输出电压被拉垮。输出高电平时电流是从VCC通过芯片内部PMOS管流出的能力较弱输出低电平时电流是灌入芯片内部NMOS管到地的能力较强。驱动LED时通常采用“低电平点亮”的方式将LED阳极接VCC阴极通过电阻接TCA9534引脚引脚配置为输出低电平。电平转换如果TCA9534是3.3V供电而你要驱动一个5V器件需要考虑电平转换问题。问题4使用中断时中断持续触发无法退出。检查清单未读取输入端口中断条件在读取输入端口寄存器后才会清除。确保你的中断服务程序里执行了读操作。输入信号抖动如按键抖动会在短时间内产生多次边沿导致中断多次触发。需要在软件中加入消抖逻辑。INT引脚外部上拉确认INT引脚开漏输出外部接了上拉电阻如10kΩ到VCC。6. 实战设计一个完整的传感器与执行器管理节点让我们设计一个简单的智能节点使用一片TCA9534管理以下设备P0, P1: 连接两个常闭型干簧门磁传感器平时输出高电平门开时输出低电平。P2: 连接一个蜂鸣器高电平报警。P3, P4, P5: 连接红、绿、蓝三色LED低电平点亮。P6, P7: 预留。硬件设计要点地址配置将A2,A1,A0全部接地地址设为0x20。传感器接口 (P0, P1)由于干簧管输出是开关量直接连接即可。为了确保引脚在悬空时有确定状态门磁未安装时应在P0和P1上各接一个10kΩ上拉电阻到VCC。这样未触发时读为高电平1触发时被干簧管拉低到GND读为低电平0。蜂鸣器驱动 (P2)蜂鸣器通常需要一定电流10mA。TCA9534的IO口驱动能力可能不足。应在P2和蜂鸣器之间增加一个NPN三极管如2N3904或MOSFET来驱动。P2输出高电平时三极管导通蜂鸣器响。LED驱动 (P3, P4, P5)采用“低电平点亮”接法。LED阳极通过一个限流电阻如330Ω接VCC阴极接TCA9534引脚。当引脚输出低电平时LED点亮。限流电阻R (VCC - Vf_led) / I_led。假设VCC3.3V 红色LED压降Vf≈2.0V期望电流I10mA则R ≈ (3.3-2.0)/0.01 130Ω 取标准值150Ω。中断将INT引脚连接到MCU的一个外部中断输入引脚并接10kΩ上拉电阻。这样任何门磁状态变化都能及时通知MCU。电源去耦在TCA9534的VCC和GND引脚附近放置一个0.1μF的陶瓷电容以滤除高频噪声。软件初始化流程void TCA9534_Init(void) { // 1. 配置引脚方向 // P0,P1: 输入 (1); P2: 输出 (0); P3,P4,P5: 输出 (0); P6,P7: 输出 (0) 或输入(1)预留 // 二进制: P7 P6 P5 P4 P3 P2 P1 P0 - 1 1 0 0 0 0 1 1 // 十六进制: 0xC3 I2C_WriteReg(TCA9534_ADDR, 0x03, 0xC3); // 2. 设置输出引脚初始状态 // P2(蜂鸣器)关(低), P3,P4,P5(LED)全灭(高) // 二进制: x x P5 P4 P3 P2 x x - 1 1 1 0 1 1 1 1 (只关心输出位输入位写1或0不影响) // 简便起见将所有输出位初始化为高(不激活)即0xFF。 // 因为P3-P5是低电平点亮输出高则灭P2是高电平驱动输出低则关。 // 所以初始值应为: P20, P31, P41, P51. 即二进制: x x 1 1 1 0 x x - 0xFC (假设高两位为1) // 更稳妥的做法先读取当前输出寄存器值再修改特定位。 uint8_t currentOutput I2C_ReadReg(TCA9534_ADDR, 0x01); currentOutput 0xC3; // 清空输出位 P2,P3,P4,P5 (bit2,3,4,5) currentOutput | ( (15) | (14) | (13) ); // P5,P4,P3置1 (LED灭) // P2保持0 (蜂鸣器关) I2C_WriteReg(TCA9534_ADDR, 0x01, currentOutput); // 3. 可选设置极性反转。本例中门磁触发为低电平符合常规认知(1表示触发)无需反转。 // I2C_WriteReg(TCA9534_ADDR, 0x02, 0x00); }中断服务与主逻辑volatile uint8_t doorSensorFlag 0; // MCU外部中断服务程序 void EXTI_IRQHandler(void) { if(检测到是TCA9534_INT引脚产生的中断) { doorSensorFlag 1; // 仅设置标志 清除中断标志位 } } int main(void) { // ... 系统初始化I2C初始化TCA9534_Init() 配置MCU外部中断... while(1) { if(doorSensorFlag) { doorSensorFlag 0; delay_ms(20); // 简单消抖 uint8_t sensorState TCA9534_ReadInputs(); // 读取输入端口 uint8_t door1 (sensorState 0) 0x01; // P0 uint8_t door2 (sensorState 1) 0x01; // P1 if(door1 0) { // P0为低门磁1触发 // 点亮红色LED (P3)关闭其他LED SetLED(RED_ON); // 启动蜂鸣器 (P2置高) SetBuzzer(ON); // 发送报警信息... } else if(door2 0) { // 处理门磁2... SetLED(BLUE_ON); } else { // 状态恢复关闭报警 SetLED(GREEN_ON); SetBuzzer(OFF); } } // ... 其他任务 } }通过这样一个完整的案例我们可以看到TCA9534如何将分散的传感器、执行器有机地整合在一起通过标准的I2C总线受控于核心MCU显著减少了主控芯片的GPIO占用并借助中断功能实现了高效的事件驱动管理。这种设计模式在需要大量数字IO的嵌入式系统中极具价值。