1、看门狗简介
看门狗定时器用于在用户程序出错并无法喂狗后对系统进行中断和复位处理。使用可编程的看门狗定时器,用户可改变定时器时间去应对不同的应用程序。该看门狗定时器有如下主要功能:
• 独立的频率可以设定的看门狗时钟振荡器
• 看门狗定时器可触发中断或复位
• 支持低功耗模式
看门狗的功能模块图如下所示:
图1 看门狗结构图
2、看门狗寄存器
ME32F030的看门狗寄存器列表如下。
图2 看门狗寄存器列表
2-1 看门狗模式寄存器
MOD 寄存器通过WDEN和WDRESET位的组合控制看门狗的操作。看门狗超时可以产生看门狗复位或中断。如果在睡眠模式中发生看门狗中断,则看门狗中断会唤醒系统。
图3 看门狗模式寄存器1
在这里需要注意的是,因为看门狗定时器可产生中断或复位两种模式,因此在使用时要先确定工作模式。具体的寄存器设置如下:
图4 看门狗模式寄存器2
2-2 看门狗定时器常数寄存器
寄存器WDTC决定超时值。每当喂狗序列产生时,TC的内容就会重新载入看门狗定时器。复位时,值0x00 FFFF会预载。写入小于0xFF的值会使0xFF载入TC。因此,最小超时间隔为TWDCLK×256×4。如果MOD中的WDPROTECT位为,则在看门狗计数器小于 WARNINT和WINDOW的值之前,尝试更改TC值将引起看门狗设置WDTOF标志。
图5 看门狗常数寄存器
2-3 看门狗喂狗命令寄存器
向该寄存器依序写入0xAA 和0x55将使 WDTC 的值重新载入看门狗定时器。非法的喂狗序列,可产生WDTOF标志置位。
图6 看门狗命令寄存器
2-4 看门狗定时器寄存器
WDTV 寄存器用于读取看门狗定时器的当前值。
2-5 看门狗警告中断比较值寄存器
WDWARNINT寄存器决定将产生看门狗中断的看门狗定时器值。当看门狗定时器与 WDWARNINT定义的值匹配时,将在后续WDCLK后产生中断。当计数器的低10位与 WARNINT的 10 位具有相同值,且计数器其余高位均为0时,便触发看门狗警告中断。在看门狗超时之前会有最长1023个看门狗定时器计数(4096个看门狗时钟)时间。如果 WARNINT设为0,则将与看门狗事件同时产生中断。
2-6 看门狗窗口比较值寄存器
WDWINDOW寄存器决定在执行看门狗喂狗时允许的WDTV最大值。如果喂狗有效序列在WDTV达到WDWINDOW中的值之前完成,则将发生看门狗喂狗错误事件。 WDWINDOW会复位为WDTV最大的可能值,因此窗口不会生效。如果WDWINDOW的值小于0x100,将无法成功进行看门狗喂狗。
3、看门狗操作函数
在例程LIB->common->Drivers->Source文件夹内有wdt.c文件,这个就是提供的看门狗库函数文件,提供的函数如下:
3-1 看门狗初始化
看门狗的初始化函数,首先使能看门狗时钟,然后将模式默认为中断模式。
- void WDT_Init (void)
- {
- SYSCON->SYSAHBCLKCTRL_b.WDT_CLK =1; //使能看门狗时钟
- WDT->MOD_b.WDRESET=0;//默认为中断模式
- return;
- }
通过关闭看门狗时钟来取消看门狗功能。
- void WDT_Deinit(void)
- {
- SYSCON->SYSAHBCLKCTRL_b.WDT_CLK=0;//关闭看门狗时钟
- return;
- }
看门狗的喂狗操作,依序向寄存器写入0xAA和0x55来进行喂狗。
- void WDT_Feed (void)
- {
- WDT->FEED_b.WDFEED = 0xAA;
- WDT->FEED_b.WDFEED = 0x55;
- return;
- }
设置看门狗的超时时间,单位为ms。设置的超时时间上限为10 S,超时后会根据模式产生中断和复位。
- void WDT_SetIntervalinMiliSec(uint32_t ms)
- {
- volatile uint32_t ticks;
- //看门狗超时上限为10S
- if (ms>10000)
- ms=10000;
- SYSCON->WDTOSCCTRL_b.WDTCLKSRC=0;
- SYSCON->WDTOSCCTRL_b.DIVSEL=ms/1600+1;
- ticks=MainClock/(1000*SYSCON->WDTOSCCTRL_b.DIVSEL);
- ticks=(ticks*ms)>>2;
- if (ticks>0xFFFFFF)
- ticks=0xFFFFFF;
- //设置看门狗超时时间
- WDT->TC_b.WDTC=ticks;
- ticks=0;
- while(ticks++<0xFFF);
- return;
- }
使能看门狗的超时复位功能后,一旦没有及时喂狗,看门狗会触发MCU的复位操作。
- void WDT_EnableResetSystem(void)
- {
- WDT->MOD_b.WDRESET=1;//使能看门狗超时复位系统
- return;
- }<code></code>
3-6 看门狗锁定
执行函数后,看门狗会处于锁定状态,不可再修改,除非系统复位。
- void WDT_EnableLock (void)
- {
- WDT->MOD_b.WDLOCKCLK=1;
- WDT->MOD_b.WDLOCKDP=1;
- WDT->MOD_b.WDLOCKEN=1;
- return;
- }
接下来写个小例程来测试下看门狗的运行情况,程序源码如下。
- int main(void)
- {
- //初始化串口
- PA_2_INIT(PA_2_TX0);
- UART_Open(UART0,9600,UART_NO_PARITY,0);
- UART_PutString(UART0,"System Reset...");//串口提示系统复位
- //初始化触摸按键
- PA_12_INIT(PA_12_TOUCH5);//PA12引脚复用为TOUCH5引脚
- itouch_init(TOUCH5);//初始化TOUCH5引脚
- //配置看门狗
- WDT_Init ();//看门狗初始化
- WDT_SetIntervalinMiliSec(10000);//设置看门狗超时时间10秒
- WDT_EnableResetSystem();//看门狗模式设为复位模式
- WDT_Enable_Timer;//启动看门狗
- WDT_Feed();//喂狗
- while (1)
- {
- SYS_DelaymS(1000);
- if(itouch.status&TOUCH5)//触摸按键检测
- {
- WDT_Feed();//喂狗
- UART_PutString(UART0,"WatchDog Feed...");//串口提示已喂狗
- }
- }
- }
程序编译无误后,便可以下载仿真调试了。这个实验不需要打断点测试,直接全速运行即可。首先我们不进行任何操作,观察串口工具的输出信息。通过串口工具记录的接收时间,我们发现MCU确实是每隔10秒便复位一次。
图7 运行实例
上面的情况是因为没有及时进行喂狗操作,发生了看门狗复位。接下来每隔一小段时间,便触摸下按键进行喂狗操作,此时观察到MCU没有再发生复位。而当我们不再去触摸按键喂狗后,MCU便又发生复位,而且距离上次喂狗刚好过去了10秒钟。
图8 运行实例
看门狗定时中断实例
1、看门狗时钟
在上一章节的学习中,我们使用了看门狗的系统复位功能,通过触摸按键触发喂狗的方式,演示了看门狗的复位功能。这一章节再讲解下看门狗的定时中断功能。既然提到了定时功能,那就需要先介绍下看门狗的时钟系统。
看门狗定时器模块使用两个时钟:PCLK和WDCLK。PCLK由系统时钟生成,供APB 访问看门狗寄存器使用。WDCLK由看门狗时钟振荡器中的wdt_clk生成,供看门狗定时器计数使用。wdt_clk时钟可以从IRC和看门狗振荡器中选择一个作为时钟源。
这两个时钟源之间存在一些同步逻辑。当MOD和TC寄存器通过APB操作更新时,新的值将由WDCLK时钟设定并生效。当看门狗定时器处于WDCLK时钟周期时,同步逻辑会先锁定WDCLK上计数器的值,然后使其与PCLK同步,以作为TV寄存器的值供 CPU 读取。
2、看门狗中断
首先介绍下看门狗警告中断比较值寄存器(WDWARNINT寄存器),它决定产生看门狗警告中断的看门狗定时器值。当计数器的低10位与WARNINT的10位具有相同值,且计数器其余高位均为0时,便触发看门狗警告中断。如例图所示,设置看门狗中断比较值寄存器的定时值位0x3FF,当看门狗计数器到03FF时,看门狗中断触发。
图1 看门狗中断
除了看门狗警告中断之外,还有看门狗超时中断。这个是通过看门狗模式寄存器的WDRESET位置1,来选择看门狗超时引发中断。模式寄存器的WDTOF位就是看门狗超时标志位。在看门狗超时、发生喂狗错误或当 WDPROTECT=1 且尝试向 WDTC 寄存器写入时,便会设置看门狗超时标志。通过软件向此位写入 0 可将该标志清零。 WDTOF 位置 1,都可以触发中断。在任何情况下,非看门狗超时引起的看门狗超时标志置位都不会触发系统复位。
3、看门狗中断例程
接下来写个小例程来测试下看门狗定时中断功能的运行情况,程序源码如下。
- int main(void)
- {
- //初始化串口
- PA_2_INIT(PA_2_TX0);
- UART_Open(UART0,9600,UART_NO_PARITY,0);
- UART_PutString(UART0,"System Reset...");//Send System Inital String
- WDT_Init ();//看门狗初始化
- WDT_SetIntervalinMiliSec(4000);//设置看门狗超时时间4秒
- WDT->WARNINT_b.WARNINT = 0x3FF;//警告中断定时值设置为最大值,方便演示
- NVIC_EnableIRQ(WDT_IRQn);//设置看门狗NVIC中断
- WDT_Enable_Timer;//启动看门狗
- WDT_Feed();//喂狗
- while(1);
- }
- void WDT_IRQHandler(void)//看门狗中断服务子程序
- {
- if(WDT->MOD_b.WDINT == 1)//警告中断
- {
- WDT_Feed();
- UART_PutString(UART0,"WDT Warning Int...");
- UART_ByteWrite(UART0,'\n');
- }
- if(WDT->MOD_b.WDTOF == 1)//超时中断
- {
- WDT_Feed();
- UART_PutString(UART0,"WDT Timeout Int...");
- UART_ByteWrite(UART0,'\n}
- WDT_ClearIntFlag();//清除看门狗中断
- return;
- }
程序编译无误后,便可以下载仿真调试了。首先全速运行,看下串口输出的信息。根据输出的信息我们发现只有看门狗警告中断信息输出,并没有超时中断信息。这是因为在警告中断发生后及时进行了喂狗操作。所以看门狗并不会超时。
图2 看门狗中断实例1
接下来我们可以把看门狗警告中断的喂狗函数WDT_Feed()屏蔽掉,然后再下载仿真看看效果。这时候我们就会看到看门狗超时中断的信息输出。因为警告中断后没有及时喂狗操作,导致看门狗超时发生。
图3 看门狗中断实例2
来源:老马识途单片机 https://www.toutiao.com/a6885897419184308743/