I2C总线协议深度解析与PXD10实战:从原理到寄存器配置
1. I2C总线协议深度解析从理论到PXD10实战在嵌入式系统开发中设备间的通信是构建复杂功能的基础。面对琳琅满目的通信协议I2CInter-Integrated Circuit总线以其极简的两线制设计和灵活的多主从架构成为了连接微控制器与各类传感器、存储器、IO扩展芯片的首选方案之一。你可能在Arduino上用过Wire库在树莓派上配置过I2C设备地址但你是否真正理解SCL线上那个微妙的时钟拉伸Clock Stretching是如何实现的或者当两个主设备同时发起传输时总线是如何通过“仲裁”优雅地解决冲突而不是让数据撞成一团乱麻本文将以Freescale现NXP的PXD10微控制器为具体载体不仅带你重温I2C的核心原理更会深入其硬件控制器如IBFD、IBCR、IBSR等关键寄存器的配置细节。我会结合多年调试经验分享如何精准计算通信速率、避坑常见的时序问题以及当通信异常时如何像侦探一样通过状态寄存器快速定位问题根源。无论你是刚接触嵌入式的新手还是希望深化底层理解的资深工程师相信这篇融合了协议理论与MCU实战的解析都能带来收获。2. I2C协议核心机制与工作原理解析2.1 总线物理层与逻辑“线与”I2C总线仅由两根线构成串行数据线SDA和串行时钟线SCL。所有设备都通过开漏Open-Drain或开集Open-Collector输出结构与这两根线相连并通过上拉电阻连接到正电源。这种设计形成了物理上的“线与”Wired-AND逻辑。开漏输出与“线与”的深层含义开漏输出意味着设备的输出级只能主动将总线拉低对地导通或释放总线呈高阻态。总线的高电平状态完全由上拉电阻提供。当所有设备都不主动拉低总线时上拉电阻将SDA和SCL线维持在逻辑高电平。任何一台设备都可以通过拉低任一线路来强制该线路为低电平。这种机制是实现多主设备仲裁和时钟同步的物理基础。上拉电阻的阻值选择至关重要它需要在总线电容由布线长度和连接设备数量决定与上升时间、功耗之间取得平衡。通常在标准模式100kbps下对于约100-200pF的总线电容使用4.7kΩ的上拉电阻是常见选择。过小的电阻会导致上升沿变陡但增加功耗和下拉电流过大的电阻则会使上升时间变长在高速模式下可能无法满足时序要求。2.2 数据有效性、起始与停止条件在I2C协议中数据在时钟信号为高电平期间必须保持稳定。SDA线上的数据变化只允许发生在SCL为低电平期间。这是判断数据有效性的黄金法则。起始START和停止STOP条件是总线状态的控制信号由主设备产生。起始条件S在SCL线为高电平期间SDA线发生一个从高到低的跳变。这个独特的信号组合标志着一次传输的开始并唤醒总线上所有从设备使其准备接收地址信息。停止条件P在SCL线为高电平期间SDA线发生一个从低到高的跳变。这标志着本次传输的终止并释放总线。重复起始Repeated START Sr是一个非常重要的特性。它是指在发送一个停止条件之前主设备再次发送一个起始条件。这允许主设备在不释放总线控制权即不发送停止条件的情况下切换通信对象从设备或改变数据传输方向读/写切换。这在需要连续访问多个设备或进行复合操作如先写寄存器地址再读数据时非常高效避免了频繁的总线释放与竞争。2.3 字节格式、地址帧与应答机制每一次I2C传输都以起始条件开始紧接着的第一个字节总是地址帧。地址帧构成7位从设备地址 1位读写方向位R/W#。其中R/W#位为0表示主设备向从设备写入数据写操作为1表示主设备从从设备读取数据读操作。需要注意的是广播地址0x00和10位地址扩展是协议的可选部分PXD10的I2C模块明确不支持广播地址和10位寻址。从设备寻址总线上每个从设备都有一个唯一的7位地址。主设备发出地址帧后所有从设备都会将其与自身地址比较。匹配的从设备会在第9个时钟周期通过拉低SDA线来发出一个应答ACK信号。如果没有从设备应答即SDA在第9个时钟的高电平期间仍为高则主设备认为寻址失败通常以发送停止条件结束传输。地址帧之后是数据帧的传输。每个数据帧也包含8位数据同样在第9个时钟周期跟随一个应答位。这个应答位由接收方发出。主设备发送数据写从设备作为接收方在成功接收每个字节后发出ACK。主设备接收数据读主设备作为接收方在成功接收从设备发来的每个字节后发出ACK。当主设备希望结束读取时它会在最后一个字节后发送一个非应答NACK即在第9个时钟周期不拉低SDA保持高电平随后发出停止条件。2.4 多主操作、时钟同步与仲裁I2C支持多主设备这是其强大灵活性的体现但也带来了总线冲突的风险。协议通过时钟同步和仲裁机制优雅地解决了这个问题。时钟同步由于SCL线是“线与”任何设备拉低SCL都会使整条线变低。各主设备使用自己的时钟驱动SCL。当多个主设备同时产生时钟时SCL的低电平周期将由时钟低电平最长的那个主设备决定而高电平周期则由时钟高电平最短的那个主设备决定。这实际上产生了一个统一的、由“最慢”低电平和“最快”高电平共同决定的SCL信号。在此期间时钟周期较短的主设备会进入“高电平等待”状态直到总线上的SCL被释放为高。这个过程对数据传输是透明的确保了所有设备都在同一个时钟节拍下工作。仲裁仲裁发生在SDA线上。当多个主设备同时开始传输时它们会像往常一样发送起始条件、地址和数据。在传输过程中每个主设备都会在发送一位后通过检测SDA线的实际电平来与自己发送的电平进行比较。由于“线与”特性只有当所有主设备都发送逻辑‘1’时SDA线才是高电平。如果有任何一个主设备发送了‘0’SDA线就会被拉低。因此仲裁规则是在SDA线上发送‘1’但检测到‘0’的主设备立即输掉仲裁。输掉仲裁的主设备会立刻关闭其SDA输出驱动器切换到从设备接收模式并监听赢得仲裁的主设备继续完成传输。同时它内部的仲裁丢失状态标志位如PXD10的IBAL位会被置位。仲裁过程不会破坏正在进行的数据传输赢得仲裁的主设备甚至不会察觉到有仲裁发生。整个仲裁机制基于地址和数据本身的内容优先级由二进制数据流决定本质上是一种“非破坏性”的竞争解决方式。3. PXD10微控制器I2C模块详解3.1 模块概览与核心特性PXD10微控制器集成的I2C控制器模块是一个完全兼容标准I2C总线协议的从硬件层面实现的控制器。它抽象了复杂的时序生成、位采样、起始/停止条件检测、仲裁处理等底层细节开发者主要通过配置一组内存映射寄存器来控制其行为极大简化了软件驱动开发。该模块的核心特性包括多主模式操作支持与其他主设备共享总线内置仲裁逻辑与时钟同步。可程时钟频率通过分频寄存器可在256种不同的串行时钟频率中选择适应不同外设的速度要求。中断驱动传输支持以字节为单位产生中断提高CPU效率。完整的协议支持自动生成和检测起始START、停止STOP、重复起始Repeated START信号自动处理应答ACK位。总线状态监控提供总线忙Busy、被寻址为从机Addressed as Slave、仲裁丢失Arbitration Lost等状态标志。DMA支持可与DMA控制器配合实现数据块的高效搬移减少CPU中断开销。需要注意的限制根据手册PXD10的I2C模块不支持广播呼叫地址General Call Address也不兼容10位地址寻址模式。在设备选型和地址规划时需避开这些功能。3.2 关键寄存器功能解析与配置策略理解并正确配置寄存器是驱动I2C模块的关键。以下是几个最核心的寄存器及其配置要点。1. I2C总线频率分频寄存器IBFD - Offset 0x01这是配置通信速率波特率的核心寄存器。I2C模块的SCL时钟并非直接使用系统时钟而是通过一个可编程的分频器产生。IBFD寄存器8位的各个位域共同决定了分频系数。IBC[0:1] (Bit 0-1)乘法因子MUL。可选1、2、4。这是整个分频计算的基础倍乘系数。IBC[2:4] (Bit 2-4)预分频器选择。决定了分频器内部tap2tap抽头间隔和scl2tapSCL下降沿到第一个抽头的时钟数等基础参数。详见手册表20-5。IBC[5:7] (Bit 5-7)SCL与SDA抽头点选择。决定了SCL高/低电平的占空比以及SDA数据保持时间相对于SCL下降沿的延迟。详见手册表20-6。配置公式与实战计算 手册提供了公式20-1至20-4并给出了详尽的预计算表表20-7。但在实际开发中我们通常根据目标SCL频率反向查找合适的IBFD值。实战步骤确定输入时钟首先确认提供给I2C模块的bus_clock频率例如系统时钟分频后的外设总线时钟假设为20MHz。计算目标分频值SCL_Divider bus_clock / desired_SCL_frequency。例如目标SCL为100kHzbus_clock为20MHz则SCL_Divider 20,000,000 / 100,000 200。查表匹配在手册表20-7中查找SCL Divider (clocks)列最接近200的值。可以看到当IBC0x20十进制32时SCL Divider为160MUL1当IBC0x10十进制16时SCL Divider为48MUL1。显然200介于两者之间。选择与评估我们需要选择一个SCL Divider小于等于计算值200的配置以确保实际频率不高于目标频率。IBC0x20对应的160时钟分频实际SCL频率为20MHz / 160 125kHz略快于100kHz但通常仍在从设备容差范围内。IBC0x21对应192分频频率约104kHz更接近。关键点必须同时检查该配置下的SDA Hold时间是否满足从设备要求通常需查阅从设备数据手册的最小保持时间要求。写入寄存器将选定的IBC值如0x21写入IBFD寄存器。注意手册中的表20-7是基于特定bus_clock周期计算的时钟数。实际频率是bus_clock / SCL_Divider。确保你的bus_clock与手册计算时的基准一致或根据公式重新计算。2. I2C总线控制寄存器IBCR - Offset 0x02此寄存器控制模块的基本操作模式。MDIS (Bit 7)模块禁用位。写1复位并禁用整个I2C模块寄存器仍可访问。任何操作前需先将其清0以启用模块。IBIE (Bit 6)中断使能位。置1允许I2C中断需与状态寄存器IBIF配合。MS/SL (Bit 5)主/从模式选择。这是模式切换的关键。从模式切主模式当总线空闲IBB0时将MS/SL由0写为1硬件会自动在总线上产生一个起始START条件模块进入主模式。主模式切从模式在主模式下将MS/SL由1写为0硬件会自动产生一个停止STOP条件然后模块切换为从模式。重要应在一次传输完成IBIF1且TCF1后执行此操作以确保正常结束当前帧。若因仲裁丢失导致MS/SL被硬件清0则不会产生STOP条件。Tx/Rx (Bit 4)传输方向选择。1为发送主设备写或从设备被读0为接收主设备读或从设备被写。在地址周期主设备总是发送故此位应置1。在从设备模式下当检测到被寻址IAAS1后应根据状态寄存器中的SRW位来设置此位以匹配主设备的读写意图。RSTA (Bit 2)重复起始控制位。仅当本设备是当前总线主设备时有效。向此位写1硬件会生成一个重复起始Repeated START条件。此位总是读为0。DMAEN (Bit 1)DMA使能位。置1后I2C模块在需要读写数据时会触发DMA请求适用于大数据块传输。3. I2C总线状态寄存器IBSR - Offset 0x03这是一个只读寄存器除IBIF和IBAL可写1清零外反映了总线实时状态是调试中最常查看的寄存器。TCF (Bit 7)传输完成标志。一个字节8位数据1位ACK传输过程中为0在第9个时钟的下降沿被硬件置1。此标志是判断字节传输是否完成的直接依据。IAAS (Bit 6)被寻址为从设备标志。当接收到的7位地址与自身IBAD寄存器匹配时置1。如果IBIE使能会产生中断。CPU应在中断服务程序中检查此位并根据SRW位设置Tx/Rx方向。IBB (Bit 5)总线忙标志。由硬件根据检测到的START/STOP条件自动置1/清0。1表示总线正被占用。IBAL (Bit 4)仲裁丢失标志。当模块作为主设备在仲裁中失败时硬件置位此位。必须通过软件写1来清除。仲裁丢失后模块会自动切换到从模式。SRW (Bit 2)从设备读/写方向。当IAAS1时此位表示主设备发送的地址帧中的R/W#位。SRW1表示主设备要读从设备应切换为发送模式SRW0表示主设备要写从设备应切换为接收模式。IBIF (Bit 1)中断标志位。当TCF、IAAS、IBAL置位或总线从忙变闲IBB高到低跳变且BIIE使能时此位置1。必须通过软件写1来清除。RXAK (Bit 0)接收应答位。在字节传输的第9个时钟周期采样SDA线得到。RXAK0表示收到了ACKRXAK1表示收到了NACK。在主发送模式下如果收到NACK通常意味着从设备未就绪或地址错误主设备应中止传输。4. I2C总线数据I/O寄存器IBDR - Offset 0x04这是一个具有“写即发送读即启动接收”特殊行为的寄存器。在主发送模式下向IBDR写入一个字节硬件会立即启动该字节的发送流程包括8位数据和1位ACK接收。第一个写入的字节必须是地址字节7位地址 R/W#位。在主接收模式下读取IBDR会启动接收下一个字节的流程。在读取之前需要确保Tx/Rx位已正确设置为0接收模式。在从模式下行为类似但仅在地址匹配IAAS1后根据Tx/Rx设置的方向进行读写操作才有效。重要提示读IBDR返回的是移位寄存器的值即最后一次成功接收的字节。它不是发送数据寄存器的回读。你不能通过读IBDR来验证刚才写入的数据是否正确。3.3 主模式与从模式操作流程精讲主设备发送写流程初始化与等待配置IBFD波特率、IBAD自身从地址如果也需被寻址、IBCRIBIE、Tx/Rx1等。检查IBB位等待总线空闲。启动传输将MS/SL位由0写为1。硬件自动产生START条件模块进入主模式。发送地址帧将7位从设备地址左移1位并与R/W#位此处为0写进行或操作得到地址字节写入IBDR。例如向地址0x50写数据则写入(0x50 1) | 0x00 0xA0。等待并检查轮询或等待中断IBIF1。检查TCF1确认字节发送完成。关键检查RXAK位。如果RXAK0收到ACK说明从设备应答地址正确。如果RXAK1收到NACK说明从设备无应答应发送STOP条件中止传输写MS/SL0。发送数据帧地址被应答后继续向IBDR写入数据字节。每写入一个字节等待TCF1并检查RXAK。从设备通过NACK可以指示数据接收结束。结束传输所有数据发送完毕后将MS/SL位由1写为0产生STOP条件。或者写入RSTA1产生重复起始条件开始下一轮通信。主设备接收读流程启动与发送读地址步骤1-3与发送流程类似但地址字节的R/W#位应为1读。例如读地址0x50写入(0x50 1) | 0x01 0xA1。切换为接收模式地址发送并收到ACK后必须在读取第一个数据字节之前将Tx/Rx位由1发送改为0接收。启动接收并读取数据将Tx/Rx设为0后执行一次对IBDR的“虚读”读取的值可丢弃这会启动硬件接收第一个数据字节。等待TCF1后再次读取IBDR即可获得有效数据。应答控制与结束在接收倒数第二个数据字节时主设备应发送ACKNOACK0。在接收最后一个数据字节前主设备应设置NOACK1然后在收到该字节后发送NACK紧接着发送STOP条件写MS/SL0。从设备响应流程初始化配置IBAD自身地址、IBFD如果支持时钟拉伸或需要设定超时、IBCRIBIE使能MS/SL0从模式。等待寻址当IAAS被置位通常触发中断进入中断服务程序。判断方向并配置读取SRW位。若SRW1表示主设备要读从设备应设置Tx/Rx1发送模式并准备数据写入IBDR。若SRW0表示主设备要写从设备应设置Tx/Rx0接收模式并准备从IBDR读取数据。数据传输根据设置的方向进行IBDR的读写操作。每次字节传输完成TCF1后进行下一步操作。结束处理检测到STOP条件或重复起始条件本次传输结束从设备回到监听状态。4. PXD10 I2C模块配置与驱动实现实战4.1 初始化配置步骤详解基于上述理论我们来看一个完整的PXD10 I2C主设备初始化与单字节写入的C语言代码示例。假设系统总线时钟bus_clock为20MHz目标SCL频率为100kHz从设备地址为0x50。#include // 假设包含PXD10寄存器定义头文件 #define I2C_BASE_ADDR 0x4000A000 // 假设I2C模块基地址 #define IBAD (*(volatile uint8_t *)(I2C_BASE_ADDR 0x00)) #define IBFD (*(volatile uint8_t *)(I2C_BASE_ADDR 0x01)) #define IBCR (*(volatile uint8_t *)(I2C_BASE_ADDR 0x02)) #define IBSR (*(volatile uint8_t *)(I2C_BASE_ADDR 0x03)) #define IBDR (*(volatile uint8_t *)(I2C_BASE_ADDR 0x04)) void I2C_Master_Init(void) { // 1. 禁用模块软复位 IBCR | (1 7); // 设置MDIS位 // 可选短暂延时确保复位完成 for(volatile int i0; i100; i); // 2. 配置自身从机地址如果不需要被寻址可设为一个不冲突的地址或忽略 IBAD 0x00; // 例如设置为0x00但注意模块不支持广播地址 // 3. 配置波特率目标100kHz, bus_clock20MHz - SCL_Divider 200 // 查表20-7IBC0x21 (MUL1)时SCL Divider192 - ~104.2kHz // IBC0x20 (MUL1)时SCL Divider160 - 125kHz // 选择IBC0x21 (33) 更接近且略低于目标频率兼容性更好 IBFD 0x21; // 4. 使能模块配置基本控制位使能中断可选初始设置为从模式 // 先清除MDIS使能模块同时清空其他控制位 IBCR 0x00; // MDIS0, IBIE0, MS/SL0, Tx/Rx0, RSTA0, DMAEN0, IBSDOZE0 // 如果需要中断可在此处设置 IBCR | (1 6); } uint8_t I2C_Master_WriteByte(uint8_t slaveAddr, uint8_t data) { uint8_t status 0; volatile uint16_t timeout 10000; // 简单超时计数器 // 1. 等待总线空闲 while ((IBSR (1 5)) timeout--) { // 检查IBB位 if(timeout 0) return 0xFF; // 超时错误 } // 2. 生成START条件进入主模式并设置为发送模式 IBCR | (1 5) | (1 4); // 设置MS/SL1, Tx/Rx1 // 注意MS/SL从0变1的跳变会硬件产生START信号 // 3. 发送从设备地址写操作R/W# 0 IBDR (slaveAddr 1) | 0x00; // 4. 等待地址发送完成并检查应答 timeout 10000; while (!(IBSR (1 1)) timeout--) { // 等待IBIF置位 if(timeout 0) { IBCR ~(1 5); // 产生STOP return 0xFE; // 超时错误 } } // 清除IBIF标志写1清零 IBSR | (1 1); // 检查传输完成和应答 if (!(IBSR (1 7))) { // TCF应为1 status 0xFD; } if (IBSR 0x01) { // RXAK为1表示NACK status 0xFC; } if(status ! 0) { IBCR ~(1 5); // 产生STOP return status; } // 5. 发送数据字节 IBDR data; // 6. 等待数据发送完成并检查应答 timeout 10000; while (!(IBSR (1 1)) timeout--) { if(timeout 0) { IBCR ~(1 5); return 0xFB; } } IBSR | (1 1); // 清除IBIF if (!(IBSR (1 7))) { status 0xFA; } if (IBSR 0x01) { // 检查数据ACK status 0xF9; } // 7. 生成STOP条件 IBCR ~(1 5); // MS/SL从1变0产生STOP return 0x00; // 成功 }4.2 中断服务程序设计与DMA应用要点对于高效的系统轮询方式浪费CPU资源。使用中断是更佳选择。中断服务程序ISR设计要点进入ISR首先读取IBSR寄存器并保存其值因为某些位如IBIF在读取后可能需要写操作清除。事件分发根据IBSR的标志位判断中断原因IAAS置位被寻址为从设备。读取SRW设置Tx/Rx方向并准备数据或地址。TCF置位且IBAL0一个字节传输完成。如果是主发送检查RXAK决定是否继续发送或停止如果是主接收读取IBDR获取数据并决定下一个字节是否发送ACK。IBAL置位仲裁丢失。应清除IBAL标志并将模块状态切换为从模式通常硬件已自动完成等待下次作为主设备发起传输的机会。IBIF由总线空闲触发如果使能了BIIE可用于检测传输序列的完全结束。清除标志根据需要向IBIF和IBAL位写1以清除标志。TCF和IAAS是只读状态位无需清除。数据缓冲区管理在ISR中通常结合软件缓冲区环形队列来管理待发送或已接收的数据避免在ISR内进行复杂耗时操作。DMA配置思路 当需要进行大量数据块传输如读写EEPROM的一页时使用DMA可以极大减轻CPU负担。PXD10的I2C模块支持DMA请求。使能DMA设置IBCR寄存器的DMAEN位。配置DMA控制器将DMA的源/目标地址分别指向内存数据缓冲区和I2C的IBDR寄存器。设置传输字节数。启动传输以主模式启动I2C传输发送地址帧。此后每当IBDR空需发送数据或满已接收数据时I2C模块会向DMA控制器发出请求。注意事项手册指出即使使用DMA每个数据帧以START开始以STOP或重复START结束的开始和结束仍需要CPU干预。例如CPU需要负责发送起始条件、地址帧并在DMA传输完成后发送停止条件。DMA主要用于中间数据字节的自动搬移。4.3 典型问题排查与调试技巧I2C通信失败是嵌入式调试中的常见问题。以下是一个基于PXD10状态寄存器的系统性排查流程1. 总线死锁SCL被持续拉低现象用逻辑分析仪或示波器看到SCL线始终为低电平通信完全停止。可能原因某个从设备可能是你的PXD10也可能是其他设备正在进行“时钟拉伸”Clock Stretching但在完成操作后未能释放SCL线。或者在仲裁过程中出现异常。PXD10相关排查检查PXD10的I2C模块是否意外处于从模式且正在拉低SCL可以尝试暂时将PXD10的I2C模块禁用MDIS1看总线是否恢复。如果恢复则检查代码中从设备处理逻辑确保在完成操作后正确释放总线。通用解决I2C协议规定主设备在检测到SCL被拉低超时后应认为总线错误。一些主控库有超时处理机制。最粗暴但有效的硬件恢复方法是依次将总线上每个设备的电源或I2C引脚断开再连接以强制其复位。也可以在软件上尝试向SCL线发送多个时钟脉冲需将引脚临时配置为GPIO输出模式来“唤醒”卡住的从设备。2. 从设备无应答NACK现象主设备发送地址或数据后检测到RXAK1。排查步骤地址错误确认发送的7位从设备地址是否正确是否左移了1位。用逻辑分析仪抓取波形直接查看发出的地址字节。从设备未就绪某些设备如EEPROM在写操作后需要几毫秒的写入周期Write Cycle Time在此期间不会应答。必须加入延时。电源与上拉测量从设备的电源电压是否正常。检查SDA和SCL线的上拉电阻是否接好电压上拉是否到位。总线电容过大可能导致上升沿太慢在高速模式下被误判为低电平。从设备故障或未连接检查硬件连接。3. 仲裁丢失现象IBAL状态位被置1主设备发送中断。原因分析总线上有另一个主设备同时发起传输且发送了不同的数据位。这是正常的多主竞争现象。处理在中断服务程序中检测到IBAL后应清除该标志。PXD10硬件会自动切换到从模式。你的软件应做好重发准备可以在稍后例如等待总线空闲后重新尝试发起传输。4. 通信速率不稳定或错误现象低速时正常提高速率后数据出错。排查时序计算重新核对IBFD寄存器的配置值。使用逻辑分析仪测量实际的SCL频率、占空比以及SDA相对于SCL的建立Setup和保持Hold时间。确保其满足从设备数据手册的要求特别是SDA保持时间SDA Hold Time。总线负载过长的走线、过多的连接器、过多的设备会导致总线电容Cb增加。这会减慢信号边沿速度。标准模式最大允许400pF。如果电容过大需降低通信速率或使用更小的上拉电阻但会增加功耗或使用I2C缓冲器Buffer隔离总线段。调试必备工具逻辑分析仪这是调试I2C的“神器”。它能非侵入式地捕获SDA和SCL上的波形并以协议格式解析出地址、数据、ACK/NACK、START/STOP一目了然地看到整个通信过程。Saleae Logic系列是常用选择。示波器用于观察信号质量测量上升/下降时间、过冲、振铃等模拟特性排查信号完整性问题。万用表检查电源、上拉电压、引脚连接。一个关键的实操心得在编写I2C驱动时务必在每个重要的状态检查点如等待IBIF、检查RXAK后加入超时处理。因为如果从设备故障或总线异常程序可能会永远等待一个不会发生的事件导致整个系统卡死。超时后应执行总线恢复操作如发送STOP条件、重新初始化模块这能极大提高系统的鲁棒性。