
1. 项目概述如果你正在使用或评估恩智浦NXP的P89LPC9151、P89LPC9161或P89LPC9171这几款微控制器那么你肯定已经感受到了它们在小封装、低成本和高性能之间取得的平衡。作为基于增强型80C51内核的MCU它们以2-4个时钟周期执行指令的速度在资源受限的应用中显得尤为灵活。但真正让这些芯片“活”起来并发挥出最大潜力的恰恰是那些看似复杂的引脚复用功能和隐藏在内存映射中的特殊功能寄存器SFR。我接触这个系列芯片有段时间了从最初对着数据手册头疼到后来能熟练地“驯服”每一个引脚和外设中间踩过不少坑也总结出一些高效配置的心得。这篇内容我就想和你深入聊聊P89LPC9151/9161/9171的引脚配置逻辑与SFR操作精髓这不仅仅是照着手册配置更是理解其设计哲学从而在硬件设计和软件编程上做出最优决策。简单来说这几款芯片的核心魅力在于高度集成与灵活配置。它们把许多系统级功能如模拟比较器、ADC、DAC、SPI、I2C、UART等都塞进了小小的TSSOP封装里而实现这一切的钥匙就是通过软件配置SFR来定义每个引脚的角色。这就像给一个多功能工具台MCU上的每个接口引脚分配不同的工具头功能配置对了事半功倍配置错了可能连最基本的通信都无法建立。对于嵌入式开发者尤其是负责硬件选型、原理图设计和底层驱动编写的工程师来说吃透这部分内容意味着你能更精准地规划PCB布局、更高效地编写初始化代码并能在调试时快速定位问题是出在硬件连接还是软件配置上。2. 芯片家族概览与引脚配置核心逻辑在深入每个寄存器之前我们得先搞清楚手头这三款芯片的“家谱”和基本配置思路。P89LPC9151、9161和9171同属一个系列内核和许多外设是共通的但它们在外设集成度和引脚数量上做了差异化以满足不同应用场景的成本和功能需求。2.1 三款MCU的引脚与功能差异解析从你提供的资料可以看出它们都采用了TSSOP封装但引脚数不同P89LPC9151是14引脚P89LPC9161和P89LPC9171是16引脚。引脚数量的差异直接导致了可用I/O端口和外设通道的变化。P89LPC9151 (TSSOP14): 这是最精简的版本。它拥有完整的6位Port 0 (P0.0-P0.5) 和6位Port 1 (P1.0-P1.5)。其特色是集成了两个模拟比较器CMP1, CMP2、一个4通道10位ADC、一个8位DAC、I2C和UART。它没有独立的SPI模块也没有Timer 1的外部引脚T1和时钟输出CLKOUT功能。P1.5固定为复位输入引脚RST。P89LPC9161 (TSSOP16): 在9151的基础上增加了完整的4线SPI接口MOSI, MISO, SPICLK, SS这些功能分配在新增的Port 2 (P2.2-P2.5) 上。同时它的Port 0减少为5位P0.1-P0.5去掉了P0.0/CMP2/KBI0。Port 1也变为5位P0.1-P0.5其中P1.4缺失。这款芯片适合需要SPI通信连接传感器、存储器或显示模块的应用。P89LPC9171 (TSSOP16): 它的外设集合与9151更为接近保留了双比较器、ADC、DAC、I2C和UART。关键升级在于增加了Timer 1的外部引脚P0.7/T1和时钟输出功能P0.7/CLKOUT这为需要精确外部定时或为其他器件提供时钟源的应用提供了便利。它的Port 0是完整的7位P0.0-P0.5, P0.7Port 1为6位Port 2仅有一个引脚P2.2作为通用I/O。选择哪一款我的经验是如果项目只需要基本的模拟比较、ADC和I2C/UART通信且尺寸要求极致选9151。如果需要连接SPI设备9161是唯一选择。如果应用需要额外的定时器外部计数或系统时钟输出9171则更合适。理解这些差异是进行正确引脚分配的第一步。2.2 引脚复用的核心优先权与配置路径这三款芯片的每一个I/O引脚都像是一个多功能插座。例如P0.1这个引脚它可能是普通的数字I/OP0.1也可能是比较器2的正输入BCIN2B或者是键盘中断输入1KBI1甚至是ADC通道0的模拟输入AD10。那么MCU如何决定此刻它扮演哪个角色呢这里有一套清晰的优先级逻辑。模拟功能优先当一个引脚被配置为模拟输入如ADC通道AD10-AD13比较器输入CINxA/CINxB/CMPREF时其数字输入功能通常会被自动禁用具体需查看PT0AD寄存器这是为了防止数字噪声干扰敏感的模拟信号。这是最高优先级之一。数字特殊功能次之如果模拟功能未启用则数字特殊功能如TXD, RXD, SCL, SDA, MOSI等会覆盖普通的数字I/O功能。例如当你使能UART时P1.0和P1.1就会自动被硬件接管为TXD和RXD此时你对P1.0/P1.1的普通写操作是无效的。通用数字I/O为默认状态当以上特殊功能均未启用时引脚就作为通用的输入/输出端口其行为由对应的端口配置寄存器PxM1, PxM2控制。复位状态所有端口在上电复位后都处于输入模式高阻态且内部上拉电阻默认关闭。这是一个非常重要的安全设计防止MCU一上电就意外驱动外部电路。配置路径我们程序员的任务就是通过编写代码操作相应的SFR来“引导”每个引脚走向我们期望的功能路径。这个过程通常在main()函数开始处的初始化代码中完成。一个常见的初始化顺序是先配置系统时钟和看门狗然后配置端口模式最后使能所需的外设模块。3. 关键特殊功能寄存器SFR深度解析与配置实战数据手册里的SFR表格看起来密密麻麻但我们可以把它们分成几大类来攻克。下面我挑出最核心、最常用的几组寄存器结合代码示例告诉你它们到底怎么用。3.1 端口配置寄存器PxM1, PxM2定义I/O的“性格”这是控制引脚作为通用数字I/O时输入输出特性的关键。每个端口P0, P1, P2都有一对模式寄存器PxM1和PxM2。通过设置这两个寄存器的组合可以为每个引脚选择四种模式之一。这里有个极易混淆的点不同端口的复位值可能不同并且不是所有位都可用。以P89LPC9151的Port 1为例手册显示P1M1复位值为0xD3 (1101 0011b)P1M2复位值为0x00。我们需要结合表格和实际引脚来看P1.2 (T0/SCL) 和 P1.3 (INT0/SDA)复位后P1M1.2和P1M1.3为1P1M2.2和P1M2.3为0。查表手册Section 5.1可知(PxM1.y, PxM2.y) (1, 0)对应开漏输出模式。这正是I2C总线所要求的所以芯片出厂时已经为I2C功能做了初步适配。P1.0, P1.1, P1.4复位后模式为(1, 1)即仅输入模式高阻。P1.5是纯输入引脚没有输出驱动器因此不适用这些模式寄存器。配置示例将P1.0和P1.1设置为推挽输出驱动LED// 假设我们要将P1.0和P1.1设为强推挽输出模式00 // P1M1.0和P1M1.1需要清0P1M2.0和P1M2.1也需要清0 // 但要注意不能影响其他引脚的配置如P1.2/P1.3的开漏模式 // 方法使用位操作只修改我们需要的那几位 P1M1 ~0x03; // 清除P1M1.1和P1M1.0的位 (0x03 0000 0011b) P1M2 ~0x03; // 清除P1M2.1和P1M2.0的位 // 现在P1.0和P1.1的模式为(0,0)即推挽输出。可以直接赋值 P1 | 0x03; // P1.0和P1.1输出高电平 P1 ~0x03; // P1.0和P1.1输出低电平注意事项在配置端口模式前如果该引脚后续要用于模拟功能如ADC务必先通过PT0AD寄存器禁用其数字输入缓冲器以减少功耗和噪声。3.2 模拟功能相关寄存器ADC、DAC与比较器这是该系列芯片的亮点。它们集成了10位ADC、8位DAC和两个模拟比较器无需外置芯片即可实现模拟信号处理。1. ADC配置 (以ADC1为例)ADC涉及多个寄存器配置流程需要遵循一定顺序ADCON1 控制ADC的使能、时钟源和启动方式。ENADC1位是总开关。ADMODA和ADMODB 设置工作模式单次/连续扫描、突发模式、边界中断等、时钟分频。ADINS 选择当前要转换的模拟输入通道AIN10-AIN13对应P0.1-P0.4。AD1DATx 读取转换结果。配置示例初始化ADC进行单次转换读取通道0 (AD10/P0.1)void ADC_Init(void) { // 1. 配置P0.1为模拟输入禁用数字输入缓冲降低噪声 PT0AD | 0x02; // 设置PT0AD.11禁用P0.1数字输入 // 2. 配置ADC时钟和使能 (假设使用内部RC时钟) ADMODB 0x00; // 选择内部时钟其他位默认 ADCON1 0x20; // 使能ADC1 (ENADC11)选择ADC时钟... // 3. 选择通道0 ADINS 0x00; // AIN10 (通道0) // 4. 配置ADMODA为单次转换、软件启动 ADMODA 0x00; // 单次转换非扫描模式 } unsigned int ADC_ReadChannel0(void) { unsigned int result; ADCON1 | 0x08; // 设置ADCI1位启动转换 while ((ADCON1 0x08) ! 0); // 等待转换完成ADCI1位被硬件清零 result AD1DAT0; // 读取结果低8位 result | ((unsigned int)(AD1DAT0H 0x03) 8); // 假设有高位寄存器组合成10位 return result; }关键点ADC的参考电压通常连接至VDD和VSS。转换时间需要根据时钟频率计算确保满足精度要求。在低功耗应用中转换完成后应及时关闭ADC (ENADC10)。2. 模拟比较器配置比较器1和2分别由CMP1和CMP2寄存器控制。配置相对简单CE1/CE2 比较器使能位。CP1/CP2 比较器输出极性选择。CN1/CN2 选择哪个输入连接到负端通常是内部参考或CMPREF。CO1/CO2 比较器输出使能输出到引脚。CMF1/CMF2 比较器中断标志位。配置示例使能比较器1正端接CIN1A (P0.4)负端接内部参考输出到P0.0 (仅9171/9151)// 假设使用P89LPC9151/9171且CMPREF已配置为内部参考电压 CMP1 0x45; // 二进制 0100 0101: CE11使能, CP10正向输出, CN11负端接CMPREF, CO11输出使能 // 使能后比较结果会出现在CMP1寄存器的CMF1位如果CO11且引脚功能选择正确也会出现在P0.0引脚上。3.3 通信接口控制寄存器UART, I2C, SPI1. UART (串口)其控制主要围绕SCON和PCON寄存器以及波特率发生器BRGR1、BRGR0、BRGCON。SCON 设置工作模式模式1最常用8位UART、使能接收。PCON 其中的SMOD1/SMOD0可以加倍波特率。波特率计算这是新手最容易出错的地方。该系列MCU的波特率发生器独立于定时器公式为波特率 (Fosc / (16 * (256 * BRGR1 BRGR0)))。Fosc是系统时钟频率。你需要根据想要的波特率和系统时钟反算出BRGR1和BRGR0的值并在BRGEN0时写入它们最后置位BRGEN启动。配置示例初始化UART为9600波特率假设Fosc 7.3728MHzvoid UART_Init(void) { // 1. 计算波特率除数 // 除数 Fosc / (16 * 波特率) 7372800 / (16 * 9600) 48 // 由于除数寄存器是16位BRGR1:BRGR0且公式中为256*BRGR1BRGR0 // 令 BRGR1 0x00, BRGR0 48 (0x30) unsigned int divisor 48; BRGCON ~0x01; // 确保BRGEN0才能写BRGRx BRGR0 (unsigned char)(divisor); BRGR1 (unsigned char)(divisor 8); BRGCON | 0x01; // 使能波特率发生器 // 2. 配置串口模式 (模式18位UART可变波特率) SCON 0x50; // 0101 0000b: SM00,SM11 - 模式1, REN1允许接收 // 3. (可选) 如果需要双倍波特率设置SMOD1 PCON | 0x80; // 设置SMOD11此时波特率公式分母中的16变为8波特率加倍。 // 注意如果使能了SMOD1上面计算的除数需要重新调整。 }2. I2C总线I2C由I2CON、I2DAT、I2STAT、I2SCLH、I2SCLL等寄存器控制。其编程相对复杂涉及状态机。I2CON 核心控制寄存器包含使能(I2EN)、起始(STA)、停止(STO)、中断标志(SI)和应答(AA)。I2SCLH/I2SCLL 设置SCL时钟的高电平和低电平周期共同决定I2C总线频率。I2STAT 状态寄存器代码需要根据其值决定下一步操作。关键流程I2C操作启动、发送地址、读/写数据、停止必须严格遵循其状态流程。一个健壮的I2C驱动通常是一个基于状态I2STAT的switch-case函数。特别注意P1.2(SCL)和P1.3(SDA)复位后默认为开漏模式这符合I2C标准通常无需更改P1M1/P1M2但必须外接上拉电阻。3. SPI (仅P89LPC9161)SPI由SPCTL、SPSTAT、SPDAT控制。SPCTL 设置SPI为主/从机(MSTR)、时钟极性(CPOL)、相位(CPHA)、数据顺序(DORD)、时钟速率(SPR1:SPR0)和使能(SPEN)。SPSTAT 包含传输完成(SPIF)和写冲突(WCOL)标志。配置示例初始化SPI为主机模式0 (CPOL0, CPHA0)低位先传void SPI_MasterInit(void) { // 配置SPI引脚功能硬件自动接管但需确保引脚方向 // 对于9161SPI功能在P2.2(MOSI), P2.3(MISO), P2.5(SPICLK), P2.4(SS) // 作为主机MOSI和SPICLK应为输出MISO为输入SS可配置为通用输出或不用。 // 端口模式寄存器可能需要设置但通常特殊功能优先。 SPCTL 0x50; // 0101 0000b: SPEN1使能, MSTR1主机, CPOL0, CPHA0, SPR1:000 (最快) } unsigned char SPI_TransferByte(unsigned char data) { SPDAT data; // 写入数据启动传输 while (!(SPSTAT 0x80)); // 等待SPIF标志置位 SPSTAT ~0x80; // 清除SPIF标志通过读SPSTAT再写 return SPDAT; // 读取接收到的数据 }3.4 中断系统寄存器让MCU及时响应事件P89LPC91x1的中断系统是标准80C51的增强版支持多个中断源和两级优先级。管理中断主要涉及以下寄存器IEN0和IEN1 中断使能寄存器。EA是总开关。你需要使能具体的中断源如外部中断0(EX0)、定时器0(ET0)、ADC(EAD)、键盘中断(EKBI)等。IP0、IP0H、IP1、IP1H 中断优先级寄存器。每个中断源可以设置为4个优先级之一由IPx.y和IPxH.y两位组合决定00最低级11最高级。优先级高的中断可以打断正在执行的低优先级中断。各个外设自己的中断标志位 如定时器的TF0/TF1ADC的ADCI1比较器的CMF1/CMF2等。在中断服务程序(ISR)中必须用软件清除这些标志位否则会连续触发中断。配置示例使能外部中断0 (INT0/P1.3)下降沿触发设置为高优先级void INT0_Init(void) { // 1. 设置中断触发方式在TCON寄存器中 TCON | 0x01; // 设置IT01下降沿触发。IT00为低电平触发。 // 2. 设置中断优先级可选 IP0 | 0x01; // 设置PX01 (IP0.0) IP0H | 0x01; // 设置PX0H1 (IP0H.0) 组合为11最高优先级 // 3. 使能外部中断0和总中断 IEN0 | 0x81; // 设置EX01 (IEN0.0) 和 EA1 (IEN0.7) } // 中断服务函数需要根据编译器指定中断号如 using 0 void INT0_ISR(void) interrupt 0 { // 用户处理代码... // 硬件会自动清除IE0标志吗对于边沿触发是的。但最好查证手册。 }重要心得在低功耗应用中合理使用中断如键盘中断KBI、比较器中断唤醒MCU比轮询方式节能得多。配置键盘中断时需要设置KBMASK选择哪些引脚作为键盘输入和KBPATN定义触发模式然后使能EKBI。4. 系统级SFR与实战配置流程除了外设一些系统级的SFR对MCU的稳定运行至关重要。4.1 时钟与电源管理CLKCON(扩展SFR) 选择系统时钟源内部RC、看门狗振荡器、外部时钟。这个寄存器位于扩展的XDATA空间必须用MOVX指令访问。在C语言中通常通过厂家提供的宏或绝对地址指针来操作。// 示例切换到内部RC振荡器假设 #define CLKCON (*(unsigned char volatile xdata *)0xFFDE) CLKCON 0x00; // 具体值需根据UCFG1/UCFG2配置和需求设定PCON和PCONA 控制省电模式。PMOD1:PMOD0可以设置为空闲(IDLE)或掉电(Power-down)模式。在掉电模式下只有外部中断、键盘中断等少数事件能唤醒MCU。PCONA可以关闭特定外设如ADC、比较器的电源以节能。DIVM CPU时钟分频器。可以通过降低CPU运行频率来直接降低动态功耗公式为Fcpu Fosc / (DIVM 1)。4.2 看门狗定时器WDT看门狗是系统抗干扰的最后防线。相关寄存器有WDCON、WDL、WFEED1、WFEED2。WDCON 控制看门狗使能(WDRUN)、时钟源(WDCLK)、预分频(PRE2:PRE0)和查看溢出标志(WDTOF)。WDL 看门狗重载值。看门狗计数器从WDL值开始递减减到0则触发复位。喂狗序列必须在计数器溢出前先向WFEED1写入0xA5再向WFEED2写入0x5A。这个序列必须连续执行中间不能被中断打断否则可能导致意外复位。配置示例使能看门狗使用内部RC时钟设置约250ms超时假设Frc400kHzvoid WDT_Init(void) { WDCON 0xE7; // 1110 0111b: PRE[2:0]111 (最大分频), WDRUN1使能, WDCLK1 (选择内部RC) WDL 0xFF; // 设置重载值 // 超时时间 ≈ (预分频系数 * WDL) / Frc。需要根据具体振荡器频率计算。 } void WDT_Feed(void) { WFEED1 0xA5; WFEED2 0x5A; }4.3 复位源识别 (RSTSRC)在系统异常复位后可以通过读取RSTSRC寄存器来判断复位原因这对于现场故障诊断非常有用。R_WD 看门狗复位。R_EX 外部复位RST引脚。R_SF 软件复位。BOF 掉电检测复位。POF 上电复位。 在程序启动时检查这些位可以将信息记录到非易失存储器中便于分析。5. 典型应用场景配置与避坑指南5.1 场景一电池供电的传感器数据采集器使用9151需求周期性采集温度传感器模拟信号通过I2C发送到EEPROM大部分时间睡眠。引脚配置P0.1 (AD10): 配置为ADC输入连接温度传感器。P1.2 (SCL) / P1.3 (SDA): 保持默认开漏用于I2C外部接10k上拉电阻。P0.0 (CMP2): 可配置为比较器输出用于监控电池电压通过电阻分压接入CIN2A实现低压报警。SFR配置要点初始化时将PCONA中ADPD、VCPD等位置1关闭未使用的模拟外设电源。配置ADC为单次转换模式转换完成后进入IDLE模式。配置I2C注意I2SCLH/L设置合适的总线频率如100kHz。使用定时器中断唤醒MCU进行周期性采集。主循环中进入IDLE模式前确认所有外设已妥善关闭或进入低功耗状态。避坑ADC转换期间CPU时钟必须稳定。如果使用可变的系统时钟需确保ADC时钟(ADMODB.CLK[2:0])配置正确。I2C通信失败时检查总线是否被锁死。可以尝试在初始化时通过软件模拟几个SCL时钟脉冲来解锁总线。5.2 场景二SPI接口的显示驱动控制器使用9161需求驱动一个SPI接口的OLED屏幕并读取几个按键。引脚配置P2.2 (MOSI), P2.5 (SPICLK), P2.4 (SS): 配置为SPI主设备输出。P2.3 (MISO): 可留空或用作输入。P0.1-P0.4: 配置为带上拉的输入连接按键并启用键盘中断(KBI)。SFR配置要点SPCTL配置为主机模式根据显示屏数据手册设置CPOL和CPHA。按键扫描使用键盘中断功能。配置KBMASK选择P0.1-P0.4KBPATN设置为0x00任何引脚变化触发使能EKBI。在键盘中断服务程序KBI_ISR中读取P0端口值来识别具体按键并清除KBIF标志。避坑SPI时钟频率(SPR1:SPR0)不要超过显示屏控制器所能接受的最大值。键盘中断是电平变化中断。如果按键抖动严重需要在软件或硬件上做防抖处理。可以在ISR中延时一段时间再读取端口状态。5.3 常见问题排查速查表现象可能原因排查步骤引脚输出无反应1. 端口模式配置错误如应为输出但配置为输入。2. 该引脚被模拟功能或数字特殊功能占用。3. 引脚损坏或焊接问题。1. 检查PxM1和PxM2寄存器。2. 检查相关外设是否被使能如ADC、UART。3. 用万用表测量引脚电压或配置为输入测试外部信号能否读入。ADC读数不准或跳动大1. 模拟电源(VDD)噪声大。2. 参考电压不稳。3. 转换期间时钟不稳定。4. 数字输入缓冲未禁用对模拟引脚。5. 采样时间不足。1. 在VDD和VSS间加滤波电容如10uF0.1uF。2. 确保VDD稳定或使用外部精密参考源。3. 确保ADC时钟源稳定避免在转换期间切换CPU时钟模式。4. 设置PT0AD相应位为1。5. 检查ADC时钟分频适当降低时钟频率以增加采样时间。UART无法通信1. 波特率计算错误。2.BRGEN未使能或BRGRx在BRGEN1时被改写。3. 引脚模式错误P1.0/P1.1未正确复用。4. 硬件流控或线路问题。1. 双检查波特率计算特别是系统时钟Fosc值。2. 严格按照先写BRGRxBRGEN0后置位BRGEN的顺序。3. 确认UART功能已使能且引脚未被其他功能占用。4. 用示波器测量TXD引脚是否有数据波形。I2C通信锁死1. 从设备无应答或总线冲突。2. 主设备程序未正确处理状态I2STAT。3. 上拉电阻过大或过小。1. 用逻辑分析仪抓取SCL/SDA波形分析时序。2. 检查I2C中断服务程序确保每个状态都得到正确处理并清除了SI标志。3. 尝试发送一个STOP条件再发送START条件来复位总线状态。功耗高于预期1. 未使用的I/O引脚浮空。2. 未使用的外设模块未断电。3. 代码未进入低功耗模式或唤醒源太频繁。1. 将未使用的引脚设置为输出低电平或输入模式并使能内部上拉如果支持。2. 通过PCONA等寄存器关闭ADC、比较器等模拟模块电源。3. 优化软件逻辑增加睡眠时间检查中断配置。6. 扩展SFR访问与编程技巧6.1 如何操作扩展SFR像CLKCON、BODCFG这类寄存器位于XDATA空间地址0xFF00不能用标准的sfr关键字直接访问。在C语言中常见的做法是使用指针或宏。// 方法1使用绝对地址指针适用于大多数编译器 #define XBYTE ((unsigned char volatile xdata *) 0) #define CLKCON (*(XBYTE 0xFFDE)) // 方法2使用编译器扩展关键字如Keil C51 sfr16 CLKCON 0xFFDE; // 注意有些编译器不支持sfr16直接定义XDATA地址 // 更通用的Keil方法是 #define CLKCON XBYTE[0xFFDE] // 写入扩展SFR CLKCON 0x03; // 读取扩展SFR unsigned char clk_val CLKCON;关键点访问扩展SFR需要使用MOVX指令这在C代码中由编译器自动生成。确保你的编译器和链接器设置正确能够处理XDATA空间的访问。6.2 初始化代码结构建议一个健壮的初始化函数应该按以下顺序进行关闭看门狗如果需要在初始化复杂外设前先暂时禁用看门狗或将其超时设到最长。配置系统时钟(CLKCON,DIVM)确定MCU运行的主频。配置端口模式(PxM1,PxM2,PT0AD)根据原理图设定所有引脚的上电初始状态。初始化外设按需初始化UART、I2C、SPI、ADC、定时器等。注意外设之间的依赖关系例如某些功能可能共用定时器。配置中断(IEN0,IEN1,IPx,IPxH)设置中断优先级和使能。使能看门狗并喂狗如果使用看门狗在此处进行最终配置并喂一次狗。进入主循环。6.3 调试心得善用软件仿真在Keil或SDCC等开发环境中可以单步执行并观察SFR窗口中的寄存器值变化这是理解寄存器作用最直观的方式。GPIO翻转调试法当程序行为异常时在关键代码段如中断入口、函数开始结束用指令翻转一个未使用的GPIO然后用示波器观察波形可以判断程序是否执行到该处以及执行时间。寄存器备份与恢复在进入低功耗模式前如果某些外设配置会被复位不完全是这样需查手册需要在唤醒后重新初始化。更好的做法是在初始化函数中做好配置低功耗模式只关闭时钟或电源而不改变寄存器配置。仔细阅读数据手册的“复位值”很多问题的根源在于想当然地认为寄存器复位后是0。例如P1M1的复位值不是0x00WDCON的复位值也不是0x00。忽略复位值直接进行|操作可能导致非预期的行为。