10.【NXP 号令者RT1052】开发——实战-RT 看门狗(RTWDOG)
10.【NXP 号令者RT1052】开发——实战-RT 看门狗(RTWDOG)
这一章,我们将向大家介绍如何使用 RT1052 的另外一个看门狗,RT 看门狗(WDOG3,以下简称RTWDOG)。在本章中,我们将使用按键 KEY_UP 来喂狗,通过 DS0 提示程序的运行状态。本章为如下几个部分:
10.1 RT1052 RT 看门狗简介
RT 看门狗(WDOG3)和前面介绍的普通看门狗(WDOG1 和 WDOG2)有一些区别:
- RT 看门狗计数器是向上计数的,普通看门狗是向下计数的;
- RT 看门狗支持窗口模式(类似STM32 的窗口看门狗),普通看门狗不支持;
- 在精度上面,RT 窗口看门狗的精度可以到 ns级别,而普通看门狗只有 0.5 秒的精度。所以,在需要精确控制复位时间或刷新窗口的时候,可以选择 RT 看门狗。

由图可知,窗口看门狗的时钟可以从 4 个时钟源里面选择:BUS_CLK(150M)、LPO_CLK(32.768K)、INTCLK(32.768K)和 ERCLK(1M),通过复用器(MUX)选择,然后可以选择使用/不使用 256 分频器,最后进入 16 位的看门狗计数器,作为计数时钟。看门狗计数器有 2 个比较值,上方的是溢出时间比较值(TOVAL),下方的是窗口时间比较值(WIN),可以通过控制逻辑对看门狗计数器进行刷新(喂狗),以避免复位。具体的刷新时间.

图中,如果使用窗口模式,则刷新(喂狗)时间必须在看门狗计数器的值大于等于 WIN,小于TOVAL 的时间段里面刷新。如果使用普通模式(非窗口模式),则只要看门狗计数器值小于 TOVAL,就可以刷新(喂狗)。
当在可刷新的时间之外刷新(喂狗),会导致 CPU 复位;同样,如果看门狗计数器达到或超过 TOVAL,也会导致 CPU 复位。
RT 看门狗超时时间由下列公式计算:
[ Trtwdog = \dfrac{TOVAL}{Frtwdog} ]
其中:
- Trtwdog:RT 看门狗超时时间,单位为 ms
- Frtwdog:RT 看门狗时钟频率,单位为 kHz
Frtwdog 的时钟频率由 PRES 位决定,可选两种分频:256 分频(约 3.072 kHz)和 1 分频(约 0.128 kHz)。PRES 位设置对应的超时时间范围如下表所示(表中超时时间由公式计算得出):
| PRES | 看门狗超时(TOVAL <= 0x0001) | 看门狗超时(TOVAL >= 0xFFFF) |
|---|---|---|
| 0 | 约 0.3 ms | 约 30.5 s |
| 1 | 约 7.8 ms | 约 763 s |
说明:
- 选择 256 分频时,系统源时钟(示例中)为 3.072 MHz,因此 RT 看门狗时钟约为 3.072 kHz。
- 选择 1 分频时,系统源时钟仍为 3.072 MHz,因此 RT 看门狗时钟约为 0.128 kHz。
通过设置 PRES 位与 TOVAL 值,可以得到不同的超时时间,以满足不同系统需求。
接下来,我们介绍 RT 看门狗的 4 个寄存器。

32 位寄存器位定义(仅低 16 位有效)
| 位域 | 名称 | 访问 | 描述 |
|---|---|---|---|
| 15 | WIN | R/W | 窗口模式使能 0 = 关闭 1 = 开启 |
| 14 | FLG | R/W1C | 看门狗中断标志 0 = 无中断 1 = 已发生中断 |
| 13 | CMD32EN | R/W | 32 位刷新/解锁命令支持 0 = 不支持 1 = 支持 |
| 12 | PRES | R/W | 输入时钟 256 分频 0 = 不分频 1 = 256 分频 |
| 11 | ULK | RO | 解锁状态 0 = 未解锁 1 = 已解锁 |
| 10 | RCS | RO | 重新配置状态 0 = 失败 1 = 成功 |
| 9:8 | CLK[1:0] | R/W | 时钟源选择 00 = BUS CLK 01 = LPO CLK (32.768 kHz,推荐) 10 = INTCLK 11 = ERCLK |
| 7 | EN | R/W | RTWDOG 使能 0 = 关闭 1 = 开启 |
| 6 | UPDATE | R/W | 允许重新配置 0 = 禁止 1 = 允许(置 1 后需在 255 总线时钟周期内完成配置,150 MHz 时约 1.7 µs) |
| 5 | INT | R/W | 中断使能 0 = 禁止 1 = 使能(溢出或非法操作后先产生中断,255 总线时钟周期后强制复位 MCU,仅用于善后,不可喂狗 |
接下来,看 RT 看门狗的第二个寄存器:计数寄存器(CNT)

16 位只读/写寄存器(低 16 位有效)
| 功能 | 操作 | 数据 | 说明 |
|---|---|---|---|
| 1. 读当前计数器值 | 读寄存器 | —— | 直接返回 RT 看门狗实时计数器值 |
| 2. 解锁 | 写序列 | 0xC520 → 0xD928 | 两步解锁,完成后允许配置寄存器 若 CMD32EN=1,可一次写入 0xD928C520 |
| 3. 刷新(喂狗) | 写序列 | 0xA602 → 0xB480 | 两步清零计数器 若 CMD32EN=1,可一次写入 0xB480A602 |
注意
解锁后必须在 255 个总线周期(150 MHz 下约 1.7 µs)内完成全部配置,否则解锁失效。
接下来,我们看 RT 看门狗的第三个寄存器:溢出时间寄存器(TOVAL)

该寄存器决定了 RT 看门狗的溢出时间,低 16 位有效,最小值为 1(不能为 0!),最大值为 0XFFFF,当 RT 看门狗计数器(CNT)的值等于 TOVAL 时,将引起 CPU 复位。
RT 看门狗的第四个寄存器:窗口寄存器(WIN)

窗口寄存器(仅窗口模式有效)
- 位宽:低 16 位有效
- 取值范围:1 – 0xFFFF(不能为 0)
- 作用:设定允许刷新的时间窗口上限
- 时间关系:
WIN ≤ Trefresh < TOVAL
在Trefresh之外喂狗将立即触发 CPU 复位 - 硬性约束:WIN 必须小于 TOVAL
RT1052 RTWDOG 启用流程(使用 KEY_UP 按键喂狗)
1) 使能 RTWDOG 时钟
CLOCK_EnableClock(kCLOCK_Wdog3);
注:
RTWDOG_Init内部已调用,用户无需重复操作。
2) 初始化 RTWDOG(超时值 & 窗口值)
函数原型:
void RTWDOG_Init(RTWDOG_Type *base, const rtwdog_config_t *config);
配置结构体 rtwdog_config_t 关键成员:
| 成员 | 说明 |
|---|---|
enableRtwdog | 设为 true 方能使能看门狗 |
clockSource | 对应寄存器 CS 的 CLK[1:0],四选一时钟源 |
prescaler | 256 分频或不分频 |
testMode | 通常选 kRTWDOG_UserModeEnabled |
enableWindowMode | 是否启用窗口模式 |
windowValue | 窗口值(启用窗口模式时有效) |
timeoutValue | 看门狗超时值 |
初始化示例:
rtwdog_config_t rtwdog_config;
rtwdog_clock_prescaler_t prescal;
if(pscen==0) prescal=kRTWDOG_ClockPrescalerDivide1;
else if(pscen==1) prescal=kRTWDOG_ClockPrescalerDivide256;
delay_ms(10);
RTWDOG_GetDefaultConfig(&rtwdog_config);
rtwdog_config.testMode =kRTWDOG_UserModeEnabled;
rtwdog_config.clockSource =(rtwdog_clock_source_t)src;
rtwdog_config.prescaler =prescal;
rtwdog_config.timeoutValue =toval;
rtwdog_config.enableWindowMode=false;
rtwdog_config.enableInterrupt =false;
rtwdog_config.enableRtwdog =true;
rtwdog_config.windowValue =win;
RTWDOG_Init(RTWDOG,&rtwdog_config);
3) 喂狗
static inline void RTWDOG_Refresh(RTWDOG_Type *base);
- 若
CMD32EN=1:一次性写入0xB480A602 - 若
CMD32EN=0:分两次写入0xB480→0xA602
4) 中断使能与优先级(如需)
RT1052_NVIC_SetPriority(RTWDOG_IRQn,4,0);
NVIC_EnableIRQ(RTWDOG_IRQn);
5) 中断服务函数
void RTWDOG_IRQHandler(void)
中断内无法喂狗(255 总线周期 ≈ 1.7 µs 内无法完成刷新),仅做简短善后处理。
实验现象
- DS0 常态常亮
- 持续按键 KEY_UP 即喂狗,不会复位
- 一旦超过
TOVAL未喂狗,MCU 重启,DS0 熄灭一次
10.2 硬件设计
本实验用到的硬件资源有:
1) 指示灯 DS0
2) KEY_UP 按键
3) RT 看门狗
前面两个在之前都有介绍,RT 看门狗属于 RT1052 的内部资源,只需要软件设置好即可正常工作。我们通过 DS0 来指示是否产生了复位,通过 KEY_UP 按键来实现喂狗操作。
10.3 软件设计
这里,我们在之前的 WDOG1 看门狗实例内增添部分代码来实现这个实验。在 HARDWARE 文件夹下面新建一个 RTWDOG的文件夹,用来保存与看门狗相关的代码。然后打开工程,新建 rtwdog.c 和 rtwdog.h 两个文件,并保存在 RTWDOG 文件夹下,并将 RTWDOG 文件夹加入头文件包含路径。
同时记得导入对应的 FSLLIB库—— fsl_rtwdog.c
下面写 rtwdog.c 和 rtwdog.h代码
#include "rtwdog.h"
#include "lpuart.h"
#include "delay.h"
#include "led.h"rtwdog_config_t rtwdog_config; //RTWDOG配置寄存器//初始化RTWDOG
//presc: 分频值,0 不分频,1 256分频
//cnt: 计数值// src : 时钟源选择.0,bus clock;1,LPO clock;2,INTCLK;3,ERCLK;
// bus clock:150Mhz; LPO clock和INTCLK都是32.768Khz; ERCLK约500Khz
//pscen: 分频器使能.0,不使能.1,使能固定256分频.
//toval: 看门狗计数器溢出最大值(cnt超过该值将产生复位).范围:0~65535
// win : 看门狗计数器窗口值.范围:0~65535,0表示不使用窗口模式.
// 注意:刷新CNT必须是在win≤刷新时≤toval,这个区间,否则将产生复位.
//溢出时间=(256^pscen)*toval/src;
//一般建议用
void MYRTWDOG_Init(u8 src,u8 pscen,u16 toval,u16 win)
{rtwdog_clock_prescaler_t prescal;CLOCK_EnableClock(kCLOCK_Wdog3); //使能RTWDOG//初始化RTWDOGif(pscen==0)prescal=kRTWDOG_ClockPrescalerDivide1; //不分频else if(pscen==1)prescal=kRTWDOG_ClockPrescalerDivide256;//256分频delay_ms(10); //切换时钟前要等待一段时间RTWDOG_GetDefaultConfig(&rtwdog_config); //先使用默认参数配置RTWDOGrtwdog_config.testMode=kRTWDOG_UserModeEnabled; //用户模式rtwdog_config.clockSource=(rtwdog_clock_source_t)src;//时钟源选择rtwdog_config.prescaler=prescal; //分频rtwdog_config.timeoutValue=toval; //超时值rtwdog_config.enableWindowMode =false; //关闭窗口功能rtwdog_config.enableInterrupt=false; //关闭中断rtwdog_config.enableRtwdog=true; //使能看门狗rtwdog_config.windowValue=win; //窗口值(默认上面关闭了窗口功能)RTWDOG_Init(RTWDOG,&rtwdog_config); //初始化看门狗RT1052_NVIC_SetPriority(RTWDOG_IRQn,4,0); //抢占优先级4,子优先级0NVIC_EnableIRQ(RTWDOG_IRQn); //使能RTWDOG中断
}//RTWDOG中断服务函数
void RTWDOG_IRQHandler(void)
{//FLG=1,产生了超时中断if((RTWDOG_GetStatusFlags(RTWDOG)&kRTWDOG_InterruptFlag)==kRTWDOG_InterruptFlag){ //无法在此处喂狗,只能做善后工作,且务必要短.} RTWDOG_ClearStatusFlags(RTWDOG,kRTWDOG_InterruptFlag); //清除中断标志位
}//喂狗
void RTWDOG_Feed(void)
{RTWDOG_Refresh(RTWDOG);
}
RTWDOG_IRQHandler 函数,是 RTWDOG 的中断服务函数,可以做一些善后工作,本章我们并没有用到。
RTWDOG_Feed函数,用于刷新RT看门狗计数器,即喂狗。就是对库函数RTWDOG_Refresh的简单封装。
RTWDOG_Init 函数,用于初始化 RTWDOG。该函数有 4 个参数:src 用于选择时钟源,一般我们选择 LPO_CLK;pscen 用于设置是否使用 256 分频,可根据自己的需要设置;toval 用于设置看门狗溢出时间,决定了多久需要喂狗一次;win 用于设置窗口值,当 win 设置为 0 时,不使用窗口模式。该函数的设置步骤,就是按我们前面介绍的 4 个步骤来设置的,该函数并没有使能 RGWDOG 的中断!
#ifndef _RTWDOG_H
#define _RTWDOG_H
#include "sys.h"void MYRTWDOG_Init(u8 src,u8 pscen,u16 toval,u16 win);
void RTWDOG_Feed(void);
#endif


下面写 main.c代码
#include "sys.h"
#include "lpuart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "exti.h"
#include "wdog.h"
#include "rtwdog.h"int main(void)
{u8 key=0;MPU_Memory_Protection(); //初始化MPURT1052_Clock_Init(); //配置系统时钟DELAY_Init(600); //延时函数初始化LPUART1_Init(115200); //初始化串口1RT1052_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);//优先级分组4
#ifdef LED_DEBUGu8 led0sta=1,led1sta=1; //LED0,LED1的当前状态LED_Init(); //初始化LED
#endif
#ifdef KEY_DEBUGKEY_Init(); //初始化KEY
#endif
#ifdef LPUART_DEBUGu8 len; //接收数据长度u16 times=0; //延时计数器LED0(0); //先点亮红灯
#endif
#ifdef EXTIX_DEBUGEXTIX_Init(); //初始化外部中断
#endif
#ifdef WDOG_DEBUGWDOG1_Init(3,2); //初始化看门狗1,2秒溢出,提前1秒进入中断,方便喂狗LED0(0); //先点亮LED灯delay_ms(300); //延时300ms再初始化看门狗,LED0的变化"可见"
#endifLED_Init(); //初始化LED KEY_Init(); //初始化KEYdelay_ms(100); //延时100ms再初始化看门狗,LED0的变化"可见"MYRTWDOG_Init(1,0,32768,0); //初始化RT看门狗,1秒溢出,非窗口模式LED0(0); //先点亮LED灯while(1){key=KEY_Scan(0);if(key==WKUP_PRES) //如果按键按下,则喂狗.{RTWDOG_Feed();} delay_ms(10);
#ifdef WDOG_DEBUGLED0(1); //关闭DS0,如不复位,DS0将一直处于关闭状态.delay_ms(100);
#endif
#ifdef EXTIX_DEBUGprintf("Int example driver!\r\n");delay_ms(1000);
#endif
#ifdef KEY_DEBUGkey=KEY_Scan(0); //得到键值if(key){ switch(key){ case WKUP_PRES: //控制LED0,LED1互斥点亮led1sta=!led1sta;led0sta=!led1sta;break;case KEY2_PRES: //控制LED0翻转led0sta=!led0sta;break;case KEY1_PRES: //控制LED1翻转 led1sta=!led1sta;break;case KEY0_PRES: //同时控制LED0,LED1翻转 led0sta=!led0sta;led1sta=!led1sta;break;}LED0(led0sta); //控制LED0状态LED1(led1sta); //控制LED1状态}else delay_ms(10);
#endif // KEY_DEBUG
#ifdef LPUART_DEBUGif(LPUART_RX_STA&0x8000){ len=LPUART_RX_STA&0x3fff;//得到此次接收到的数据长度printf("\r\n发送的消息为:\r\n");LPUART_WriteBlocking(LPUART1,LPUART_RX_BUF,len);//发送接收到的数据printf("\r\n\r\n");//插入换行LPUART_RX_STA=0;}else{times++;if(times%5000==0){printf("\r\nALIENTEK RT1052开发板 串口实验\r\n");}if(times%200==0)printf("请输入数据,以回车键结束\r\n"); if(times%30==0)LED0_Toggle;//闪烁LED,提示系统正在运行.delay_ms(10); }
#endif // LPUART_DEBUG}
}
该函数我们通过 RTWDOG_Init 函数初始化 RT 看门狗,设置其使用 LPO_CLK 时钟源,1秒溢出,不使用窗口模式。然后,点亮 DS0,并进入死循环。在死循环里面,我们必须不停的按 KEY_UP 按键,否则 1 秒钟以后,DS0 就会灭掉(灭的时间为 100ms 左右),表示发生了看门狗复位。
10.4 下载验证
将代码下载(仅 flexspi_debug_release 目标工程支持下载)到号令者 RT1052 后,可以看到DS0 亮了,然后如果我们不按 KEY_UP 按键,则 DS0 亮约 1 秒后,会发生看门狗复位,DS0 灭一会(约 100ms)后,又重新点亮,依次循环。如果我们不停的按 KEY_UP 按键(按下+松开),就可以看到 DS0 不再灭了,保持常亮,表示喂狗成功。
总结
RTWDOG(RT 看门狗)与普通 WDOG 的主要区别在于:RTWDOG 为向上计数、支持窗口模式且时钟可选分频,具备更高时间精度和严格的刷新时序(必须在 WIN ≤ CNT < TOVAL 区间内按特定写序列喂狗,且解锁后需在很短总线周期内完成配置),适合需要精确时序或窗口约束的场景;普通 WDOG 为向下计数、无窗口限制、超时粒度较粗(以 0.5 s 为步进),使用和刷新更简单,适合常规复位保护。
OK!谢谢大家!
