深入解析P87C554增强型外设:UART帧错误检测、T2捕获比较与I2C控制器实战
1. 项目概述与核心价值
在嵌入式系统开发领域,尤其是基于经典80C51架构的深入应用,外设功能的深度理解和灵活运用往往是区分普通应用与高性能、高可靠性设计的关键。很多开发者对基本的UART、定时器有所了解,但面对像Philips P87C554这类集成了增强型外设的增强型单片机时,其手册中复杂的寄存器描述和功能框图常常让人望而却步,导致宝贵的硬件资源被闲置,或者只能以最基础的方式使用,无法发挥其全部潜力。
我接触P87C554这类芯片有些年头了,在多个工业控制和通信网关项目中都深度使用过。它的魅力在于,在经典的80C51内核基础上,Philips(后来的NXP)为其注入了非常实用的高级功能。增强型UART不仅仅是个串口,它自带的帧错误检测和硬件级自动地址识别,能让你轻松构建稳定可靠的多机通信网络,软件负担极轻。定时器T2更是个“瑞士军刀”,不仅仅是计数,其强大的捕获/比较功能,配合专用的端口输出,是实现精准脉冲测量、PWM生成甚至简易电机控制的利器。而片上的I2C总线控制器,则让你与各类传感器、EEPROM的通信变得优雅而高效。
本文将抛开数据手册的冰冷叙述,以一个实际使用者的视角,深入解析P87C554这三个核心外设模块的工作原理、配置技巧和实战中的“坑”。我会结合代码片段和配置流程,告诉你如何将这些功能用起来,并分享一些从调试中得来的、数据手册上不会写的经验。无论你是正在评估这款芯片,还是已经用它做项目遇到了瓶颈,相信这些内容都能给你带来直接的帮助。
2. 增强型UART:超越基础的串行通信
标准80C51的UART功能已经足够强大,支持四种工作模式。但P87C554的增强型UART(SIO0)在模式1、2、3的基础上,增加了两项关键特性:帧错误检测(Framing Error Detect)和自动地址识别(Automatic Address Recognition)。这两项功能对于构建健壮的分布式系统至关重要。
2.1 帧错误检测机制与实战配置
帧错误,简单说就是接收到的数据帧格式不对,最常见的就是停止位不是预期的逻辑‘1’。在噪声环境或波特率失配时,这类错误频发。标准UART无法直接检测此错误,需要软件通过超时等方式间接判断,既复杂又不可靠。
P87C554的硬件帧错误检测功能,让这件事变得简单。其核心在于S0CON寄存器的第7位。这个位比较特殊,它是一个复用位,功能由PCON寄存器的第6位(SMOD0)决定。
- 当
SMOD0 = 0时,S0CON.7作为SM0位,用于选择UART工作模式(与标准8051相同)。 - 当
SMOD0 = 1时,S0CON.7作为FE(Framing Error)标志位。
配置步骤:
- 使能帧错误检测:将
PCON.6 (SMOD0)置1。通常通过PCON |= 0x40;实现。 - 检查错误标志:在UART接收中断服务程序(或轮询读取接收数据时),读取
S0CON寄存器,并判断其第7位(S0CON & 0x80)。若为1,则表示发生了帧错误。 - 清除错误标志:FE标志不能由硬件自动清除,必须用软件清零:
S0CON &= 0x7F;。务必在读取错误状态后、处理新数据前清除它。
实操心得与避坑指南:
- 顺序很重要:一定要先设置
SMOD0=1,再去解读S0CON.7作为FE。如果顺序反了,你可能会误操作模式选择位,导致通信根本不通。 - 中断处理:帧错误发生时,不会产生独立的中断。它只是设置FE标志位。你需要在UART接收中断(RI触发)的服务程序中,在读取接收数据(SBUF)之前或同时,检查FE位。因为RI和FE可能同时因同一帧错误数据而有效。
- 错误恢复:检测到帧错误后,除了清除FE标志,一定要考虑如何恢复通信。常见的做法是丢弃当前错误帧,并可能清空接收缓冲区。对于连续错误,可能需要检查硬件连接、波特率设置或系统时钟稳定性。
- 模式影响:此功能在UART模式1(8位数据)、模式2和3(9位数据)下有效。在模式0(同步移位寄存器模式)下无效。
下面是一个简化的代码框架,展示如何在中断服务程序中处理帧错误:
// 假设已正确初始化UART为模式1,并使能了接收中断 void UART_ISR(void) interrupt 4 // 串口中断向量 { if (RI) { // 接收中断 RI = 0; // 软件清除接收中断标志 unsigned char status = S0CON; // 读取S0CON状态 if (status & 0x80) { // 检查FE位(此时SMOD0应已设为1) // 发生帧错误 S0CON &= 0x7F; // 必须软件清除FE标志 // 错误处理:丢弃该字节,记录错误日志,或采取恢复措施 unsigned char dummy = SBUF; // 读取SBUF以清空接收寄存器,但丢弃数据 // ... 错误处理代码 ... } else { // 正常接收 unsigned char receivedData = SBUF; // 读取有效数据 // ... 数据处理代码 ... } } if (TI) { // 发送中断处理 TI = 0; // ... 发送处理代码 ... } }2.2 自动地址识别:高效的多机通信基石
在多处理器系统中,主机需要与多个从机通信。传统方法是主机发送地址字节,所有从机接收并用自己的软件判断地址是否匹配,匹配者才响应后续数据。这导致每个从机的CPU都被每个地址字节中断,软件开销大。
P87C554的自动地址识别功能将地址匹配工作交给了硬件。只有当地址匹配时,才会置位接收中断标志(RI),从而触发CPU中断。这极大地减轻了CPU负担,尤其适合从机需要休眠以省电的应用。
其核心是两个特殊功能寄存器:SADDR(从机地址寄存器)和SADEN(从机地址掩码寄存器)。
- SADDR:设定本机的“基础地址”。
- SADEN:定义地址中的哪些位需要严格匹配(掩码位为1),哪些位是“无关位”(掩码位为0)。
硬件比较的逻辑是:(接收到的地址字节) & SADEN == SADDR & SADEN。只有“有关位”匹配,从机才响应。
配置与使用流程:
- 设置从机地址:向
SADDR写入本机的7位地址(通常左对齐,最高位MSB在前)。例如,地址0x50,则SADDR = 0x50;(假设8位数据,最高位可忽略或用作其他用途,在9位模式中第9位为1表示地址帧)。 - 设置地址掩码:向
SADEN写入掩码。需要精确匹配的位写1,忽略的位写0。例如,SADEN = 0xFF;表示所有位都必须匹配(唯一地址)。SADEN = 0xFE;则表示只匹配高7位,最低位是无关位。 - 使能自动地址识别:在UART模式2或3(9位数据)下,设置
S0CON中的SM2=1。在模式1下,SM2也需置1,且需要有效的停止位。 - 从机工作流程:
- 初始化后,
SM2=1,单片机处于“地址监听”状态。只有收到匹配地址的帧(第9位数据为1表示地址帧),RI才会置位。 - 中断服务程序中,读取地址帧,确认是本机呼叫后,软件清除
SM2位(SM2=0)。此后,所有数据帧(第9位数据为0)都会触发RI,实现连续数据接收。 - 数据接收完毕后,重新置位
SM2=1,等待下一个地址帧。
- 初始化后,
灵活寻址方案示例:手册中给出了精妙的例子,展示了如何用SADDR和SADEN实现地址组播和广播。
假设系统中有三个从机:
从机0:
SADDR = 1100 0000,SADEN = 1111 1001=> 给定地址格式:1100 0XX0。- 必须匹配的位:位7、6、5、4、1(掩码为1)。
- 无关位:位2、0(掩码为0)。
- 唯一地址示例:
1100 0110(令无关位X=11)。
从机1:
SADDR = 1110 0000,SADEN = 1111 1010=> 给定地址格式:1110 0X0X。- 必须匹配的位:位7、6、5、4、2。
- 无关位:位1、0。
- 唯一地址示例:
1110 0101。
从机2:
SADDR = 1110 0000,SADEN = 1111 1100=> 给定地址格式:1110 00XX。- 必须匹配的位:位7、6、5、4、3、2。
- 无关位:位1、0。
- 唯一地址示例:
1110 0011。
广播地址由SADDR和SADEN逻辑或(OR)产生,其中结果为0的位是无关位。通常,如果SADEN将某些位设为无关(0),则广播地址对应位也是无关位。最常用的广播地址是0xFF(所有从机都响应)。
关键注意事项:
- 第9位(RB8)是关键:在模式2/3下,硬件只在接收到的第9位为1(表示地址帧)时,才进行地址匹配检查。因此,主机发送地址帧时,必须将第9位(TB8)设为1;发送数据帧时,设为0。
- SM2的灵活运用:
SM2位是控制是否进行地址过滤的开关。在地址识别阶段置1,在数据接收阶段清0,这个“握手”过程必须由软件管理。 - 复位状态:复位后,
SADDR和SADEN均为0,这意味着所有位都是无关位,自动地址识别功能被禁用。此时UART行为与标准8051完全一致。必须显式初始化这两个寄存器才能启用该功能。 - 模式1下的区别:在8位模式1下,
SM2=1时,除了地址匹配,还需要一个有效的停止位才能触发RI。这增加了在噪声环境下的可靠性。
3. 定时器T2:不止于计数的强大工具
P87C554的定时器T2是一个功能异常丰富的16位定时器/计数器,远不止基础的定时功能。它集成了可编程预分频器、字节溢出与16位溢出中断、外部复位以及最强大的捕获/比较逻辑。理解它,你就能用硬件完成许多原本需要复杂软件干预的任务。
3.1 基本结构与工作模式
定时器T2的核心是一个16位计数器,由TML2(低字节)和TMH2(高字节)组成。其时钟源可以通过TM2CON寄存器选择:
T2MS1:T2MS0 = 01:时钟源为fOSC/12(与Timer 0/1相同)。T2MS1:T2MS0 = 11:时钟源为外部引脚T2 (P1.4)的上升沿(计数器模式)。T2MS1:T2MS0 = 00:定时器关闭。T2MS1:T2MS0 = 10:测试模式,勿用。
预分频器可以对输入时钟进行1、2、4、8分频,由TM2CON的T2P1:T2P0控制。特别注意:改变预分频器分频比或时钟源,会清零预分频器。
中断能力:T2提供两级溢出中断。
- 字节溢出中断:当低8位计数器(
TML2)从0xFF翻转到0x00时,标志位T2BO (TM2CON.4)置位。若中断使能位ET2 (IEN1.7)和T2IS0 (TM2CON.6)同时为1,则触发中断。 - 16位溢出中断:当整个16位计数器(
TMH2:TML2)从0xFFFF翻转到0x0000时,标志位T2OV (TM2IR.7)置位。若ET2和T2IS1 (TM2CON.7)同时为1,则触发中断。 两者共用同一个中断向量(0073H)。在中断服务程序中,你需要通过检查T2OV和T2BO标志来确定中断源,并手动清除它们。
外部复位:通过设置T2ER (TM2CON.5)=1,可以使能外部引脚RT2 (P1.5)的上升沿将整个T2计数器(包括预分频器)复位为0。这在需要外部事件同步清零定时器的场合非常有用。
3.2 捕获功能:精准的时间戳记录器
捕获功能是T2的亮点之一。它有四个独立的16位捕获寄存器:CT0,CT1,CT2,CT3。每个捕获寄存器关联一个外部输入引脚CTnI(与P1口复用)。
工作原理:当配置的边沿(上升沿、下降沿或双边沿)在CTnI引脚上发生时,硬件会瞬间将当前T2计数器的值(TMH2:TML2)锁存到对应的CTn寄存器中,并置位相应的中断标志CTIn (TM2IR)。
配置寄存器 CTCON:
CTPx位:设置为1,则在对应CTxI引脚上升沿时捕获。CTNx位:设置为1,则在对应CTxI引脚下降沿时捕获。- 如果
CTPx和CTNx同时为1,则在双边沿(即任何变化)时捕获。
典型应用——脉冲宽度/周期测量:
- 将T2配置为内部时钟定时模式,并设置合适的预分频器,使其计时范围大于待测信号周期。
- 将待测信号接入
CT0I引脚。 - 配置
CTCON,使CT0在上升沿和下降沿都捕获(CTP0=1, CTN0=1)。 - 使能
CT0捕获中断(ECT0=1)。 - 在中断服务程序中:
- 读取
CT0寄存器的值,这就是边沿发生时刻的“时间戳”。 - 用本次时间戳减去上一次的时间戳,差值乘以定时器计数周期,就得到了边沿间隔时间(例如,上升沿到上升沿的时间就是信号周期,上升沿到下降沿的时间就是高电平宽度)。
- 注意处理定时器溢出的情况。如果两次捕获之间T2发生了溢出,计算差值时需要加上65536(或使用后文提到的扩展方法)。
- 读取
避坑指南:
- 输入滤波:
CTnI引脚上的信号在采样时,可能会受到噪声干扰。虽然芯片内部有一定处理,但对于非常尖锐的毛刺,建议在外部增加简单的RC滤波。 - 中断响应时间:从捕获事件发生到CPU响应中断并读取
CTn寄存器,存在延迟。但这个延迟是固定的(若干机器周期),对于测量相对时间间隔(差值)没有影响,因为每次捕获的延迟相同,会在相减时抵消。绝对时间戳则存在这个固定误差。 - 读取顺序:虽然T2没有专门的读锁存器,但读取16位的
CTn时,也应遵循先读低字节CTnL,再读高字节CTnH的原则,以防在两次读取之间发生低字节向高字节的进位。不过,由于捕获是瞬间完成的,CTn寄存器值相对稳定,此风险比直接读正在运行的TML2/TMH2要小。
3.3 比较功能:硬件驱动的精准输出
比较功能是另一个强大的特性。T2配备了三个16位比较寄存器:CM0,CM1,CM2。T2计数器每个时钟周期都会与这三个寄存器的值进行比较。当匹配发生时,可以自动控制P4口特定引脚的电平,产生精确的波形,完全无需CPU干预。
相关控制寄存器:
- STE (Set Enable Register):当
CM0与T2匹配时,如果STE中对应位为1,则P4口的相应引脚会被置位(拉高)。例如,STE.0=1,则P4.0会在匹配时置高。 - RTE (Reset/Toggle Enable Register):功能更复杂。
- 对于
P4.0到P4.5:当CM1与T2匹配时,如果RTE中对应位为1,则相应引脚会被复位(拉低)。 - 对于
P4.6和P4.7:当CM2与T2匹配时,如果RTE中对应位为1,则相应引脚会翻转(Toggle)。注意,这里翻转的不是端口锁存器,而是两个独立的触发器(TG46,TG47),它们的状态可以从STE.6和STE.7读取。这确保了即使软件在翻转之间改变了端口锁存器值,下一次硬件翻转动作仍然是基于上一次翻转的结果,保证了输出波形的连续性。
- 对于
工作流程:
- 初始化T2为定时器模式,设置初始值(通常为0)。
- 根据需要的输出波形时间,计算并设置
CM0,CM1,CM2的值。 - 配置
STE和RTE寄存器,决定哪个匹配事件控制哪个引脚。 - 启动T2。
- 此后,硬件会自动在匹配时刻改变P4口输出。同时,匹配事件会置位
CMI0,CMI1,CMI2中断标志,你可以选择是否使能中断来通知CPU进行下一组比较值的装载(用于生成连续波形)。
应用实例——生成固定占空比PWM: 假设用P4.0输出一个PWM波,高电平时间对应CM0匹配,低电平时间对应CM1匹配。
- 设置
STE.0 = 1,RTE.0 = 1。 - 假设T2时钟周期为
T,需要的高电平时间为T_high,低电平时间为T_low,周期T_period = T_high + T_low。 - 设置
CM0 = T_high / T。 - 设置
CM1 = T_period / T。 - 启动T2。当T2计数到
CM0时,P4.0置高;计数到CM1时,P4.0置低,同时T2溢出(如果CM1值小于65535且不重载)或通过中断服务程序重载CM1为下一个周期的匹配值(如果使用连续模式)。
更复杂的应用——生成带死区的互补PWM: 利用CM0置高一对引脚(如P4.0,P4.1),CM1复位它们,CM2翻转另一对引脚(如P4.6,P4.7),并精心计算匹配值,可以生成用于半桥或全桥驱动的互补PWM信号,甚至插入死区时间。
重要提示:
- 优先级:硬件修改(比较匹配)的优先级高于软件对P4口的写操作。如果在同一个机器周期内,软件试图写P4口而硬件也要求改变,则硬件操作生效。
- 冲突处理:如果
CM0和CM1在同一时刻要求对同一引脚进行置位和复位,复位操作优先。 - 中断标志:比较匹配中断标志
CMIx在匹配发生后的下一个周期置位。中断服务程序里需要手动清除它们。
3.4 定时器扩展与长周期定时
T2是一个16位定时器,即使使用最低的输入时钟(fOSC/12,再8分频),在12MHz晶振下,最大定时周期也只有约524ms(65536 * (1/(12MHz/12/8)) ≈ 0.524s)。对于需要更长定时的应用,手册给出了一个经典的软件扩展方案。
原理:利用T2的16位溢出中断,在中断服务程序中对一个软件计数器(例如一个24位的变量,由3个字节组成)进行递增。这样,定时范围就从16位扩展到了16 + n位。
代码实现(基于手册示例):
; 假设定义了三个字节的扩展计数器:TIMEX1 (LSB), TIMEX2, TIMEX3 (MSB) OVINT: PUSH ACC ; 保存现场 PUSH PSW INC TIMEX1 ; 递增最低字节 MOV A, TIMEX1 JNZ INTEX ; 如果未溢出,跳转 INC TIMEX2 ; TIMEX1溢出,递增中间字节 MOV A, TIMEX2 JNZ INTEX ; 如果未溢出,跳转 INC TIMEX3 ; TIMEX2溢出,递增最高字节 INTEX: CLR T2OV ; 清除T2溢出中断标志 POP PSW ; 恢复现场 POP ACC RETI在这个例子中,每次T2溢出(约524ms),TIMEX1加1。当TIMEX1从255溢出到0时,TIMEX2加1,依此类推。这个24位扩展计数器可以提供长达2^24 * 0.524s ≈ 2200小时的定时范围。你可以根据实际需要的最大定时长度来决定扩展的字节数。
注意事项:
- 在扩展模式下,通常只使能16位溢出中断(
T2IS1=1),而禁用字节溢出中断(T2IS0=0),以避免过于频繁的中断。 - 软件扩展计数器应在主程序中定期读取或判断,以实现超长延时或定时任务。读取时也要注意多字节变量的原子性问题,防止在递增过程中读取到中间值。一种方法是在中断中更新,在主程序循环中复制一份进行判断。
4. I2C总线控制器(SIO1):硬件驱动的两线通信
P87C554集成了一个完整的I2C总线控制器,Philips称之为SIO1。它完全由硬件处理复杂的I2C协议时序、仲裁、时钟同步等,极大地简化了软件设计。支持主发送、主接收、从发送、从接收四种模式,以及多主机仲裁。
4.1 硬件架构与核心寄存器
要驾驭SIO1,必须理解其四个核心的特殊功能寄存器(SFR):
S1CON (控制寄存器,D8H):这是大脑。控制着I2C的启动、停止、应答、时钟速率和中断。
ENS1:总使能位。为0时,SIO1功能关闭,P1.6/P1.7可作为普通I/O。STA,STO:启动(START)和停止(STOP)条件控制位。软件置位STA可发起起始条件;置位STO可发起停止条件(主模式)或从错误中恢复(从模式)。SI:串行中断标志。任何I2C状态变化(除了状态F8H)都会置位此标志。必须由软件清零,清零后硬件才会继续I2C操作。AA:应答确认标志。为1时,在应答时钟周期内,SIO1会拉低SDA线(发送ACK);为0时,释放SDA线(发送NACK)。CR2, CR1, CR0:时钟速率选择位。决定主模式下的SCL时钟频率。可选固定分频(如fOSC/120,fOSC/960)或使用Timer1溢出率/16。从模式下自动同步主机时钟。
S1STA (状态寄存器,D9H):这是眼睛。其高5位包含了当前I2C总线的26种状态代码(00H, 08H, 10H, 18H, 20H, ... F8H)。每个有效状态码都对应一个明确的I2C操作阶段(如“START已发送”、“SLA+W已发送并收到ACK”、“数据字节已接收”等)。中断服务程序必须根据此状态码来执行相应的操作。低3位恒为0。
S1DAT (数据寄存器,DAH):这是数据通道。要发送的数据写入这里,接收到的数据从这里读取。数据移出时是MSB在先。
S1ADR (地址寄存器,DBH):这是从机身份牌。高7位存放本机的7位I2C从机地址。最低位
GC如果置1,则使能对通用呼叫地址(0x00)的响应。
4.2 主模式操作流程与状态机编程
使用SIO1的核心是状态机编程。硬件负责状态转移,软件负责在每个状态点做出正确响应。手册中的表6和表7是主模式的状态响应表,是编程的圣经。
主发送模式(Master Transmitter)流程示例: 假设我们要作为主机,向从机地址0x50写入两个字节数据0xAA, 0x55。
初始化:设置
S1CON,选择时钟频率(例如CR2:CR0=001对应 ~100kHz @12MHz),使能SIO1 (ENS1=1),AA=1(初始化为应答状态),STA=STO=SI=0。准备好要发送的数据和从机地址(SLA+W = 0xA0,因为0x50左移一位,最低位写方向位W=0)。启动传输:软件置位
STA=1。硬件检测总线空闲后,发出START条件,进入状态08H,并置位SI。中断服务程序(状态08H):
- 读取
S1STA,确认状态为08H。 - 将
SLA+W (0xA0)写入S1DAT。 - 向
S1CON写入一个值,其特点是:保持ENS1=1,AA=1,清除STA和SI(STA=0, SI=0)。例如写入0x45(假设CR位对应100kHz)。 - 退出中断。硬件会自动发送
S1DAT中的地址字节。
- 读取
后续状态:
- 地址发送并收到从机ACK后,进入状态18H,
SI再次置位。 - 在状态18H的中断服务程序中,将第一个数据字节
0xAA写入S1DAT,然后同样清除SI(STA=0, STO=0, SI=0, AA=1)。 - 数据发送并收到ACK后,进入状态28H。
- 在状态28H的中断服务程序中,判断是否还有后续数据。如果有,发送下一个数据(
0x55),清除SI。如果是最后一个数据,则置位STO=1并清除SI,硬件将在完成当前字节后产生STOP条件。 - 发送最后一个数据后收到ACK,进入状态28H,此时置位
STO,产生STOP,传输结束。
- 地址发送并收到从机ACK后,进入状态18H,
关键点:
SI标志是流程控制器:硬件在进入一个新状态后立即拉高SI并暂停总线(拉伸SCL低电平),等待软件处理。软件必须根据状态码执行对应操作,并手动清除SI标志,总线才会继续。- 状态码是路标:26个状态码(F8H除外)每一个都指明了当前精确的总线阶段和下一步软件该做什么。必须严格按照手册附录表格的“APPLICATION SOFTWARE RESPONSE”列操作。
STA和STO的软件管理:STA和STO由软件置位,但在某些条件下由硬件自动清除(如STOP条件已发出)。在中断程序中,我们通常写入一个包含STA、STO、SI、AA目标状态的字节到S1CON。
4.3 从模式操作与地址识别
从模式配置更简单。只需设置好S1ADR中的本机地址,并使能SIO1 (ENS1=1),置位AA=1(表示准备好应答自己的地址)。之后,SIO1便自动监听总线。
当主机发送的地址与S1ADR匹配(或通用呼叫地址且GC=1)时,SIO1会自动应答(ACK),并根据读/写位(R/W)进入从接收或从发送模式,并进入相应的状态(如60H、A8H),置位SI。
在从模式下,AA位变得非常有用。在数据传输过程中,如果从机暂时无法处理更多数据(例如缓冲区满),可以在中断服务程序中清除AA位。这样,在接收到下一个数据字节后,从机会回复NACK,主机通常会终止传输。从机也可以在发送完最后一个数据后清除AA,这样在主机发送ACK后,从机将释放总线并忽略后续地址呼叫,直到AA被重新置位。
4.4 常见问题与调试技巧
总线卡死(SCL被拉低):这是I2C调试中最常见的问题。可能原因:
- 从机故障,持续拉低SCL或SDA。硬件上需要每个设备都有上拉电阻。软件上,P87C554的SIO1提供了“强制访问总线”的恢复机制:在尝试发送START条件超时后,可以同时置位
STA和STO,硬件会尝试内部产生一个STOP条件并重新开始。 - 主机程序错误,在某个状态后没有正确清除
SI,导致SCL一直被拉伸为低。务必检查每个状态处理分支是否都清除了SI。
- 从机故障,持续拉低SCL或SDA。硬件上需要每个设备都有上拉电阻。软件上,P87C554的SIO1提供了“强制访问总线”的恢复机制:在尝试发送START条件超时后,可以同时置位
无应答(NACK):
- 检查从机地址是否正确(7位地址左移一位,最低位是R/W)。
- 检查从机设备是否上电、初始化正常。
- 用逻辑分析仪或示波器观察SDA线,看从机是否在ACK时钟脉冲期间拉低了SDA。
仲裁丢失:在多主机系统中,当两个主机同时开始传输时,会进行仲裁。SIO1硬件会自动处理仲裁丢失,并切换到从机模式(如果被寻址)。状态码38H、68H、78H、B0H都表示仲裁丢失。处理方法是:在中断服务程序中,通常置位
STA,这样当总线空闲后,本机会自动重试发送START条件。状态码F8H:表示“无可用状态信息”,即
SI=0,总线空闲或在等待中。在中断程序中通常忽略此状态或直接返回。状态码00H:表示总线错误,如非法的START或STOP位置。处理方法是:向
S1CON写入ENS1=1, STO=1, SI=0, AA=x来复位总线状态,并释放SDA和SCL。
调试建议:
- 充分利用状态码:在中断服务程序入口,将
S1STA的值通过串口打印出来,是追踪I2C流程最有效的方法。 - 分步测试:先实现主发送,向一个已知的EEPROM(如24C02)写一个字节并读回验证。再实现从机接收。
- 注意上拉电阻:I2C总线必须接上拉电阻,阻值通常为4.7kΩ ~ 10kΩ,具体取决于总线电容和速度。
- 初始化顺序:确保在设置
S1CON使能SIO1 (ENS1=1) 之前,已将P1.6和P1.7的端口锁存器置1(设置为准双向模式且输出高电平)。
5. 外设协同与系统设计考量
在实际项目中,UART、T2和I2C很少孤立工作。例如,一个典型的数据采集节点可能用T2的捕获功能测量传感器脉冲宽度,通过I2C读取另一个数字传感器,最后通过增强型UART将打包的数据发送给上位机。
中断管理:P87C554有15个中断源,包括这里提到的UART、T2的各种捕获/比较/溢出中断、I2C中断等。必须精心规划中断优先级(通过IP0,IP0H,IP1,IP1H寄存器设置4个优先级),并确保关键任务(如通信超时处理)不被低优先级中断长时间阻塞。例如,UART接收中断应设为较高优先级,以防数据丢失;T2的捕获中断用于精确计时,也应给予较高优先级;而I2C中断可以设为较低优先级,因为其硬件状态机可以等待。
电源与时钟:P87C554支持空闲和掉电模式。在空闲模式下,CPU停止工作,但外设如UART、T2、I2C(如果时钟来自系统)可能仍在运行。需要特别注意,如果使能了看门狗定时器(T3),在空闲模式下它依然会计时,需要在程序中定期喂狗。ADC在空闲模式下可以通过AUXR1.6 (AIDL)位选择是否关闭以省电。
引脚复用:P1.4 (T2), P1.5 (RT2), P1.6 (SCL), P1.7 (SDA), P1.0-P1.3 (CT0I-CT3I) 等引脚都与T2和I2C功能复用。当启用这些外设功能时,必须确保对应的端口锁存器设置为正确的状态(通常为1),并且软件避免对这些引脚进行普通的I/O操作。
代码结构化:对于状态机驱动的I2C和事件驱动的UART/T2,建议采用模块化编程。为每个外设编写独立的初始化函数、中断服务函数和功能函数。例如,I2C模块可以提供一个I2C_WriteBytes()的API,内部处理所有状态跳转,对上层应用隐藏复杂性。
性能估算:在同时使用多个外设时,需评估CPU负载。例如,在12MHz系统时钟下,一个115200bps的UART每字节传输约需87μs,其接收中断服务程序必须在下一个字节到来前完成,否则会发生溢出。T2的捕获中断如果用于测量高频信号,中断频率可能很高。必要时,可以使用T2的硬件比较输出功能来生成PWM,完全解放CPU。
最后,数据手册是你的终极参考。本文解读了关键原理和实用技巧,但具体到每一个寄存器的每一位,以及最精确的时序参数,仍需以你所用芯片型号的最新数据手册为准。希望这篇深入解析能帮助你真正释放P87C554这颗经典芯片的潜力,在项目中游刃有余。
