1. 项目概述
在嵌入式开发领域,尤其是基于经典80C51架构的单片机应用,系统稳定性和固件可维护性是工程师们永恒的关注点。我接触过不少项目,从简单的智能家居传感器到复杂的工业控制器,都绕不开两个核心话题:如何防止程序“跑飞”导致系统死锁,以及如何在产品出厂后甚至运行现场,安全、便捷地更新程序。Philips(现NXP)的P89LPC930/931系列单片机,作为增强型80C51内核的代表,其内置的看门狗定时器(Watchdog Timer)和灵活的Flash编程能力,恰好为这两个痛点提供了非常经典的解决方案。这次,我就结合自己多年的调试和量产经验,来深入聊聊这两个功能的设计思路、实操细节以及那些容易踩坑的地方。
很多新手可能会觉得看门狗就是个简单的定时复位,Flash编程就是“烧录程序”,但实际用起来远不止如此。比如,看门狗的喂狗时机怎么选才能既有效监控又不误触发?Flash的ISP和IAP到底有什么区别,在电路设计上又有什么讲究?这些细节往往决定了产品的最终可靠性。这篇文章,我会从原理到寄存器操作,再到实际代码和硬件设计要点,为你拆解P89LPC930/931的看门狗与Flash编程技术,目标是让你看完后,不仅能理解手册上的描述,更能真正应用到自己的项目里,避开我当年走过的弯路。
2. 看门狗定时器(WDT)深度解析与实战配置
看门狗,顾名思义,就是给系统请的一个“保镖”。它的职责很简单:你必须定期告诉我“我还活着”(即喂狗),如果超过预定时间我没收到信号,我就认为你“死机”了,然后强制重启系统。在P89LPC930/931上,这个保镖的“工作模式”和“警觉性”是可以精细调节的。
2.1 硬件架构与工作原理
根据数据手册,P89LPC930/931的看门狗由一个12位可编程预分频器和一个8位递减计数器组成。时钟源可以选择系统时钟(PCLK)或者一个独立的、标称频率为400kHz的看门狗专用振荡器(WDOSC)。这个设计选择是第一个关键点。
为什么要有两种时钟源?选择PCLK作为时钟源,看门狗的计时和CPU指令执行是同步的。这意味着当CPU因故停机(比如进入某些错误的低功耗模式或时钟故障),PCLK也可能停止,看门狗也随之停止计数,从而失去保护作用。因此,在可靠性要求极高的场合,必须选择独立的400kHz看门狗振荡器作为时钟源。这样即使主时钟系统失效,看门狗依然能独立运行,在超时后触发复位。当然,独立振荡器会增加微弱的功耗,但对于大多数应用而言可以忽略不计。
预分频器的作用是对时钟源进行分频,以获得更长的定时周期。12位的预分频器意味着分频系数可以从1到4096(2^12)。8位递减计数器的范围是0-255。因此,总的超时时间T_wdt计算公式为:T_wdt = (预分频值) × (256 - WDL) / f_wdclk其中,f_wdclk是看门狗时钟频率(PCLK或~400kHz),WDL是写入看门狗数据寄存器(WDL)的值,决定了递减计数器的初始值。
举个例子,假设我们选择独立看门狗振荡器(f_wdclk ≈ 400kHz = 4×10^5 Hz),预分频值设置为256,WDL设置为0xFF(即初始值255,递减到0溢出)。那么超时时间大约是:T_wdt = 256 × (256 - 255) / 400000 ≈ 0.64 ms这显然太短了,几乎无法正常喂狗。如果我们把WDL设置为0x00(初始值0,注意计数器是减到0溢出,所以初始值0意味着立刻溢出?这里需要小心,通常我们设置WDL为小于255的值,比如0x00表示初始值0,但手册会规定有效范围,一般不会是0xFF立刻溢出,需要查证),或者更实际地,设置预分频为最大值4096,WDL设为0x00(初始值0):T_wdt = 4096 × 256 / 400000 ≈ 2.62秒这就得到了一个几秒级的监控窗口,比较实用。实际计算时,一定要查阅数据手册中关于预分频位(PRE2:PRE0)与分频系数的映射关系,以及WDL寄存器的有效加载值。
2.2 关键寄存器详解与配置流程
看门狗的功能完全由看门狗控制寄存器(WDCON,地址A7H)控制。这是一个需要重点理解的寄存器。
WDCON (A7H) 寄存器位定义:
- WDEN (Watchdog Enable): 看门狗使能位。1=启用看门狗功能;0=禁用,此时看门狗可作为间隔定时器使用,溢出时产生中断而非复位。
- WDRUN (Watchdog Run): 看门狗运行控制。1=看门狗计数器正在运行;0=停止。注意:一旦看门狗被启用(WDEN=1),该位只能由硬件复位清零,软件无法直接停止它。这防止了软件意外关闭看门狗。
- WDCLK (Watchdog Clock Select): 时钟源选择。0=选择PCLK;1=选择看门狗振荡器(~400kHz)。强烈建议在可靠性要求高的应用中选择1。
- PRE2, PRE1, PRE0: 预分频器选择位。这三位组合决定分频系数(1, 4, 16, 64, 256, 1024, 4096等,具体需查表)。
- WDTOF (Watchdog Time-Out Flag): 看门狗超时标志。当看门狗溢出导致系统复位后,该位由硬件置1。软件可以通过读此位来判断上次复位是否由看门狗引起,这对于系统故障诊断至关重要。该位需要软件写0清除。
- - (Bit 1): 保留位,读为0。
- - (Bit 0): 保留位,读为0。
看门狗数据寄存器 WDL (C1H): 这是一个8位寄存器,用于装载递减计数器的初始值。写入WDL的值并不会立即生效,而是在每次成功的喂狗序列后被加载到递减计数器中。因此,你可以在程序运行中动态调整喂狗间隔(通过改变WDL的值),但要注意下一次喂狗后新值才生效。
核心操作:喂狗序列喂狗不是简单地向某个寄存器写值,而是一个严格的两字节序列:
- 先向WFEED1地址写入0xA5。
- 紧接着向WFEED2地址写入0x5A。 这两个地址是固定的,在数据手册中定义。这两个写操作必须在连续的指令中完成,中间不能有任何其他操作(如中断)。如果序列错误、顺序颠倒、或者中间被打断,都会被视为无效喂狗,并可能立即触发看门狗复位!这是最容易出错的地方之一。
2.3 实战代码与设计要点
下面是一个典型的看门狗初始化和喂狗程序示例(基于Keil C51):
#include <REG932.H> // 包含P89LPC930/931的特殊功能寄存器定义 sfr WFEED1 = 0xC1; // 喂狗序列地址1,需根据具体头文件确认 sfr WFEED2 = 0xC2; // 喂狗序列地址2,需根据具体头文件确认 /* 注意:WFEED1/2的地址可能因编译器或头文件而异,务必核对数据手册和实际使用的头文件。 有些头文件可能已经定义了 WFEED1 和 WFEED2。*/ #define WDT_FEED() do { WFEED1 = 0xA5; WFEED2 = 0x5A; } while(0) /** * @brief 初始化看门狗定时器 * @param pre_scale 预分频选择(结合PRE2:PRE0位) * @param reload_val 重装载值(写入WDL) * @note 时钟源选择独立的看门狗振荡器(~400kHz)以提高可靠性 */ void WDT_Init(unsigned char pre_scale, unsigned char reload_val) { // 1. 首先暂时禁用看门狗(如果之前启用),以便配置。但注意,一旦WDRUN被硬件置位,软件无法清零。 // 更安全的做法是在系统初始化最早阶段,复位后立即配置。 WDCON &= ~0x80; // 清除WDEN位,尝试禁用(前提是WDRUN为0) // 2. 配置预分频器和时钟源 // 假设pre_scale的低3位对应PRE2:PRE0,并且我们想设置WDCLK=1(独立振荡器) WDCON = (pre_scale & 0x07) | (1 << 3); // 设置预分频和WDCLK=1,其他位(包括WDEN)为0 // 3. 设置看门狗重装载值 WDL = reload_val; // 4. 执行一次喂狗序列,将reload_val加载到计数器并启动看门狗(如果WDRUN因上电复位为0,则此操作会启动它) WDT_FEED(); // 5. 最后使能看门狗功能 WDCON |= 0x80; // 设置WDEN=1 // 此时,看门狗已经运行。一旦WDEN=1且WDRUN=1,看门狗将无法被软件禁用,直到下一次硬件复位。 } /** * @brief 主循环中的喂狗操作 * @note 必须确保在任何正常执行路径中,两次喂狗的间隔小于看门狗超时时间。 * 避免在长时间关中断的代码段或死循环中忘记喂狗。 */ void main(void) { // 系统初始化 // ... // 初始化看门狗,预分频设为1024,重装载值设为200(超时时间约 1024*(256-200)/400000 ≈ 0.143秒) // 这是一个较短的超时时间,适用于对响应速度要求高的任务。 WDT_Init(0x05, 200); // 假设0x05对应1024分频 while(1) { // 执行主要任务 Task_A(); Task_B(); // 在循环合适位置喂狗 WDT_FEED(); // 更多任务... Task_C(); // 注意:如果Task_A/B/C中任何一个可能长时间阻塞(如等待外部事件), // 必须在阻塞循环内部也加入喂狗操作! } } // 判断复位来源,用于诊断 void Check_Reset_Source(void) { if (WDCON & 0x04) { // 检查WDTOF位是否为1 // 上次复位是由看门狗超时引起的! // 可以在这里记录错误日志、点亮故障灯等 // ... // 清除标志位 WDCON &= ~0x04; // 写0清除WDTOF位 } else { // 上电复位或外部引脚复位 } }关键设计要点与避坑指南:
- 喂狗位置是艺术:喂狗代码应该放在主循环的“正常”执行路径中,确保只要程序逻辑正确运行,就一定能定期执行到。绝对要避免只在某个中断服务程序(ISR)中喂狗。因为如果主程序跑飞但中断还能响应,看门狗就不会复位,失去了监控主流程的意义。通常在主循环和关键的子任务循环中喂狗。
- 超时时间的选择:超时时间不宜过短,否则会因任务执行时间的正常波动导致误复位;也不宜过长,否则无法及时检测到死锁。一般设置为程序正常循环周期的1.5到3倍。例如,主循环周期是50ms,看门狗超时可设为100-150ms。需要结合预分频和WDL值仔细计算。
- 关中断与喂狗:在进入临界区(关中断)执行原子操作时,要确保这段代码的执行时间远小于看门狗超时时间。如果关中断时间可能较长,必须在关中断前喂狗,或者考虑更精细的设计。
- 低功耗模式下的处理:当CPU进入Power-down模式时,PCLK会停止。如果看门狗时钟源选的是PCLK,看门狗也会停止,失去保护。在进入低功耗模式前,必须将看门狗时钟切换到独立振荡器,或者直接禁用看门狗(如果允许)。唤醒后需要重新初始化。这是一个非常常见的陷阱。
- 诊断与恢复:充分利用
WDTOF标志。在系统初始化时检查该标志,如果置位,说明上次是看门狗复位,可能意味着系统遇到了严重错误。此时可以进行一些错误恢复操作,如初始化外设到已知状态、恢复默认参数等,甚至记录错误次数,连续多次看门狗复位后进入安全模式。
3. Flash存储器编程:ISP与IAP详解
P89LPC930/931内置了8KB的Flash程序存储器,这不仅是存放代码的地方,更因其支持在系统编程(ISP)和在应用编程(IAP)而成为产品后期维护和功能升级的利器。
3.1 Flash存储结构与管理
理解编程操作前,先要清楚其存储结构:
组织方式:8KB Flash被划分为8个扇区(Sector),每个扇区1KB。每个扇区又可进一步划分为16个页(Page),每页64字节。这是擦除操作的基本单位。
三个关键区域:
- 用户代码区:地址
0x0000-0x1DFF(具体范围以手册为准,此处为示例)。这是用户应用程序存放的位置。 - 引导加载程序区(Boot Loader):地址
0x1E00-0x1FFF(共512字节)。出厂时,Philips在此固化了一个串行ISP引导程序。用户可以通过特定的硬件时序(如复位时拉高某个引脚)让芯片从该区域启动,从而通过串口接收新程序并烧写到用户代码区。 - 引导ROM(Boot ROM):地址
0xFF00-0xFFFF。这是一个独立的、不可擦写的ROM,里面存放了底层的Flash擦除、编程、校验等子程序。无论是用户程序的IAP调用,还是ISP引导程序,最终都是通过一个统一的入口地址(例如0xFF00)调用Boot ROM中的例程来完成实际操作的。这保证了编程操作的可靠性和底层一致性。
- 用户代码区:地址
引导向量(Boot Vector)和引导状态位(Boot Status Bit):这是控制芯片上电后执行流程的关键。
- 引导状态位:非零时,芯片不会从
0x0000开始执行,而是结合引导向量决定启动地址。 - 引导向量:当引导状态位非零时,芯片将
(Boot Vector的值 << 8)作为程序计数器的高字节,低字节为0x00,从此地址开始执行。出厂默认值通常是0x1E,这意味着上电后若状态位非零,则跳转到0x1E00执行厂家的ISP引导程序。 - 用户可以将引导向量修改为自定义的引导程序地址,实现自己的升级协议(如通过CAN、以太网等)。完成后,再将引导状态位写回0,使下次正常启动时从用户程序
0x0000开始。
- 引导状态位:非零时,芯片不会从
3.2 ISP(在系统编程)实战指南
ISP允许你通过芯片的串口(UART),在电路板上直接给单片机编程,无需拆下芯片。这极大方便了生产烧录和现场升级。
硬件连接要求:ISP只需要5个引脚:VDD, VSS, TxD, RxD, RST。你需要设计一个简单的接口(通常是4-6pin的接头),将目标板的这些引脚连接到编程器(可以是另一个单片机、USB转串口工具配合特定软件,或专用ISP编程器)。关键点是RST引脚的控制:编程器需要能控制目标板的复位引脚,在上电过程中将其置于特定电平以强制芯片进入ISP模式。
典型的ISP操作流程(以厂家引导程序为例):
- 硬件触发ISP模式:编程器控制目标板,先保持RST为低电平,然后给目标板上电。上电后,再将RST拉高一段时间(具体时序需严格参照数据手册,例如
tVR,tRH,tRL等参数)。这个特定的上电复位序列会强制芯片检查ISP激活条件,并跳转到引导向量指向的地址(默认0x1E00)。 - 建立串口通信:ISP引导程序运行后,会通过TxD/RxD引脚以预定的波特率(通常是固定的,如9600或根据时钟自动调整)发送同步字符或等待主机命令。
- 执行编程命令:主机(编程软件)通过串口发送命令帧,引导程序解析后,调用Boot ROM中的底层函数,执行擦除、编程、校验等操作。常见的协议是Philips的
IAP协议或自定义的简化协议。 - 退出与重启:编程完成后,主机发送退出命令,引导程序通常会执行一个软复位,芯片从
0x0000开始运行新程序。
注意事项:
- 波特率校准:确保编程器使用的波特率与芯片内部引导程序期望的波特率一致。有些引导程序支持自动波特率检测,有些则需要固定波特率。
- 复位电路设计:目标板上的复位电路(通常是RC电路)不能干扰编程器对RST引脚的控制。常见做法是在复位线路上串联一个100-470欧姆的电阻,或者使用跳线帽在编程时断开本地复位电路。
- 电源稳定性:编程期间必须保证VDD稳定。Flash编程/擦除操作对电压敏感,电压波动可能导致操作失败甚至损坏存储单元。
3.3 IAP(在应用编程)高级应用
IAP是更高级的功能,允许正在运行的用户程序自己修改Flash存储器的内容(包括程序区和用户配置区)。这意味着你的产品可以在运行中通过网络、串口、USB等方式接收新的固件数据,然后自己把自己“更新”了。
IAP的实现原理:用户程序通过一个统一的调用接口(例如,使用LCALL或ACALL指令调用固定地址0xFF00)来访问Boot ROM中的服务例程。在调用前,需要按照约定设置好参数(通过寄存器或固定RAM区域),调用后根据返回结果判断操作是否成功。
一个典型的IAP擦除并编程页(Page)的流程如下:
- 准备数据:将待写入的64字节数据存放在RAM的缓冲区中。
- 设置参数:将目标Flash地址(页地址)、源数据RAM地址、操作命令码等写入特定的特殊功能寄存器(SFR)或通用寄存器。对于P89LPC系列,通常涉及
PSW、R0、R1、DPL、DPH、AUXR1等寄存器,具体格式需查阅用户手册中关于IAP调用的详细章节,这部分信息在数据手册中往往只是概述。 - 调用入口:使用
LCALL 0xFF00(或指定的其他入口地址)指令。 - 等待操作完成:Boot ROM例程执行期间会禁止中断。操作完成后,CPU从中断返回(或根据状态寄存器判断)。
- 检查结果:从指定的状态寄存器(如
PSW的进位位CY)读取操作结果(成功/失败)。
IAP操作的关键约束与安全考量:
- 不能擦写当前正在执行的代码:这是铁律。如果你尝试擦除或编程当前CPU正在取指令的Flash扇区,会导致不可预料的后果,通常立即导致程序跑飞或看门狗复位。因此,IAP代码(即执行擦写操作的这段程序)必须位于RAM中运行,或者位于一个不会被擦除的独立Flash扇区(例如,将IAP引导程序放在最后一个扇区,而主应用程序放在其他扇区)。
- 操作时序与电源:每次擦除或编程操作需要一定时间(手册标明典型值为2ms)。IAP代码中需要等待操作完成或检查状态位。同样,操作期间VDD必须稳定。
- 数据备份与验证:在擦除一个扇区前,如果该扇区还有需要保留的数据,必须先将它们读到RAM中备份。编程完成后,强烈建议进行读取验证或CRC校验。
- 通信协议与故障恢复:设计IAP升级功能时,必须考虑通信中断、数据错误、升级中途断电等情况。通常需要设计一个完整的协议,包含数据包校验、握手、断点续传、升级失败回滚(保留旧版本)等机制。永远不要在没有备份和恢复机制的情况下直接擦除主程序区。
4. 用户配置字节与安全保护
P89LPC930/931的Flash中还有一些特殊的非易失性字节,用于芯片的初始配置和安全保护,这些通常在编程阶段(通过ISP或并行编程器)设置。
4.1 用户配置字节(UCFG1)
这是一个至关重要的字节,在芯片上电时被读取,用于配置一些运行时无法更改的硬件选项。主要包括:
- 振荡器配置:选择使用内部RC振荡器、外部晶体还是外部时钟源,以及相关频率范围。
- 看门狗使能/禁用(上电默认状态)。
- 复位引脚功能(仅作为输入,或作为输入/输出)。
- 其他功能选项,如是否启用
CLKOUT等。
配置要点:这些设置必须在编程时根据你的硬件电路和需求正确配置。例如,如果你的板子上焊接了12MHz的晶体,就必须在UCFG1中配置为外部晶体模式,否则芯片无法正常起振。配置错误是导致芯片“不工作”的常见原因之一。
4.2 用户扇区安全字节
P89LPC930/931提供了扇区级的代码保护功能。每个1KB的扇区都有一个对应的安全字节。当某个扇区的安全位被编程(通常意味着设置为0)后,该扇区的内容:
- 无法通过外部编程器(包括ISP)读取,防止代码被轻易拷贝。
- 无法通过MOVC指令读取,这意味着即使程序运行中,也无法用代码读取该扇区的内容,进一步防止软件破解。
- 可以擦除和重新编程,以便后续更新。
安全策略建议:
- 对于需要严格保密的算法、密钥等核心代码,可以放在独立的扇区并设置安全位。
- 注意,安全位一旦设置,只有通过全片擦除(Chip Erase)才能解除(前提是安全位本身允许被擦除,有些芯片的安全位是OTP的)。全片擦除会清除所有用户代码。因此,设置安全位前务必确认代码已经稳定。
- IAP操作是否可以修改安全位,需要查阅具体手册。通常,IAP可以编程安全位来加强保护,但可能无法解除已被保护扇区的保护(除非擦除整个扇区)。
5. 常见问题排查与调试心得
在实际开发中,围绕看门狗和Flash编程的问题层出不穷。下面我整理了一个常见问题排查表,并附上一些“血泪”换来的经验。
| 问题现象 | 可能原因 | 排查思路与解决方案 |
|---|---|---|
| 看门狗频繁误复位 | 1. 喂狗间隔大于超时时间。 2. 喂狗序列被中断打断。 3. 在长时间关中断或死循环的任务中未喂狗。 4. 看门狗时钟源选择PCLK,但系统进入低功耗模式后PCLK停止。 | 1.计算并测量:精确计算超时时间,并在代码中关键点打点输出,用逻辑分析仪或示波器测量实际喂狗间隔。 2.检查喂狗代码:确保 0xA5,0x5A的写入是原子操作,中间不会被任何中断打断。可以将喂狗代码放在临界区(操作前关中断,操作后开中断)。3.审查任务逻辑:在可能阻塞的函数内部增加喂狗点。 4.检查低功耗处理:在进入Idle或Power-down模式前,切换看门狗时钟到独立振荡器或妥善处理。 |
| 系统死机但看门狗不复位 | 1. 看门狗未成功启用(WDEN或WDRUN位状态不对)。 2. 看门狗时钟源失效(如选择了失效的时钟)。 3. 程序跑飞后意外地持续执行了喂狗操作(例如PC指针跳转到了一段循环喂狗的代码区)。 | 1.初始化验证:在初始化后读取WDCON寄存器,确认WDEN和WDRUN位已按预期设置。 2.时钟源检查:确认选择的时钟源是否存在且稳定。对于内部RC,注意其精度;对于外部时钟,检查电路。 3.代码结构审查:避免在程序中存在大段无条件的喂狗循环。确保喂狗操作与主程序状态强相关。 |
| ISP编程连接失败 | 1. 串口波特率不匹配。 2. 复位时序不符合要求。 3. 目标板供电不足或不稳。 4. TxD/RXD引脚被其他电路影响(如接了下拉电阻)。 5. 引导程序区被意外擦除。 | 1.核对波特率:尝试常见的波特率(9600, 19200, 38400等),或确认芯片是否支持自动波特率。 2.示波器抓时序:用示波器观察RST和VDD的上电时序,严格对照数据手册的 tVR,tRH等参数。3.测量电源:编程时,确保VDD在标称范围(如3.3V)且纹波小。 4.检查电路:ISP期间,确保编程接口的TxD/RXD引脚与目标板其他电路隔离(如使用零欧姆电阻或跳线)。 5.尝试并行编程:如果ISP完全无法进入,可能需要先用并行编程器恢复引导程序。 |
| IAP操作失败(返回错误) | 1. 尝试擦写当前正在执行的代码扇区。 2. Flash地址或数据缓冲区地址设置错误。 3. 调用IAP前未按要求设置好所有参数寄存器。 4. 操作期间发生了中断。 5. VDD电压在操作期间跌落。 | 1.确保IAP代码在RAM运行:这是最根本的要求。将IAP相关函数用#pragma关键字定位到RAM地址,或者复制到RAM中执行。2.仔细调试参数:单步调试IAP调用前的代码,检查所有地址参数、命令码是否正确写入对应寄存器。 3.查阅手册示例:用户手册中通常有IAP调用的汇编或C示例代码,务必严格按照示例的寄存器使用顺序。 4.关中断:在准备参数到调用IAP完成期间,必须关闭所有中断。 5.加强电源:在启动IAP操作(尤其是擦除)前,可以短暂提升系统工作电流,并检查电源路径上的去耦电容是否充足。 |
| 设置安全位后无法再次编程 | 1. 安全位被设置为永久保护(OTP)。 2. 试图通过ISP修改安全位,但该操作不被允许。 3. 编程算法或命令序列错误。 | 1.确认安全位类型:仔细阅读数据手册,确认安全位是可擦除的还是OTP的。 2.使用正确方法:对于可擦除的安全位,通常需要先执行“扇区擦除”或“全片擦除”命令才能解除保护。全片擦除会清除所有代码。 3.联系工具供应商:确认使用的编程器软件和算法是否支持对该型号芯片的安全位操作。 |
个人调试心得:
- 看门狗调试法:在项目初期,可以故意加长看门狗超时时间(比如10秒),然后在代码中插入一个“故障注入”测试点(例如,按下一个测试按键后模拟死循环)。测试看门狗是否能如期复位系统。这是验证看门狗是否真正生效的最直接方法。
- ISP接口标准化:在设计产品PCB时,无论当前项目是否需要ISP,我都习惯预留一个标准的6Pin接口(VCC, GND, RST, TxD, RxD, 可能再加一个信号线)。这几乎不增加成本,但在生产调试、售后升级时会带来巨大便利。接口附近记得预留串联电阻和滤波电容的位置。
- IAP的“双区备份”设计:对于需要可靠远程升级的产品,我强烈推荐“双程序区+引导区”的设计。将Flash划分为三个部分:一个小的、永不更新的引导程序(Bootloader);两个大的、交替使用的应用程序区(App A, App B)。Bootloader负责验证和跳转。升级时,将新固件下载到非活动的App区,校验通过后,Bootloader更新标志并复位,从新的App区启动。即使新固件有问题,Bootloader也可以根据标志回滚到旧版本。这种设计虽然复杂,但可靠性极高。
- 善用CRC校验:无论是ISP传输的数据,还是IAP写入Flash后的验证,都一定要做CRC校验。P89LPC930/931的Boot ROM本身就提供了CRC计算功能(通过IAP调用),一定要用起来。它可以有效避免因传输错误或Flash偶发性位错误导致的程序错误。
P89LPC930/931的这些特性,在当年看来是非常先进的,即使放到现在,其设计思想依然值得学习。看门狗和Flash编程不仅仅是两个独立的功能,它们共同构成了嵌入式系统“可靠性”和“可维护性”的基石。理解透彻并运用得当,能让你设计的产品在严苛的环境中依然稳定运行,并在整个生命周期内保持更新的能力。希望这篇结合了手册原理和实战经验的详解,能帮助你在下一个项目中更好地驾驭这颗经典的芯片。