一、看门狗基础
1、看门狗功能:
由于单片机的工作常常会受到来自外界电磁场的干扰,造成各种寄存器和内存的数据混乱,会导致程序指针错误等,程序运行可能会陷入死循环。程序的正常运行被打断,由单片机控制的系统无法继续正常工作,导致整个系统的陷入停滞状态。此时往往需要重启,使得程序回归正常的运行状态。看门狗就是为了预防程序运行混乱和陷入死循环的情况, 当发生情况时,能够重启统。
2、看门狗本质:
看门狗本质是一个定时器。看门狗定时器正常工作时自动计数,程序正常运行时定期将其复位清零(称为“喂狗”),如果系统在某处卡死或跑飞,该定时器将溢出(未及时“喂狗”),看门狗定时器就为系统产生一个复位信号,使系统复位,然后重新恢复正常的工作状态。
二、cc2530 看门狗
1、cc2530看门狗资源
cc2530的看门狗定时器包括一个 15 位计数器,它的频率由 32kHz 时钟源提供。看门狗(WDT)可以配置为一个看门狗定时器或一个通用的定时器,但用户不能获得 15 位计数器的内容。具有四个特性:
- 四个可选的定时器间隔
- 看门狗模式
- 定时器模式
- 在定时器模式下产生中断请求
(1)看门狗模式:WDT运行在一个频率为32.768KHz(当使用32KHz XOSC)的看门狗定时器时钟上,当软件在选定时间间隔内不能清除WDT时,计数器达到选定定时器的间隔值后,看门狗定时器就为系统产生一个复位信号,系统复位。
(2)定时器模式:WDT运行在一个频率为32.768KHz(当使用32KHz XOSC)的看门狗定时器时钟上,可以被配置为一个间隔定时器,有四个超时期限可以配置1.9ms,15.625ms,0.25s,1s。这样可以用于在选定的时间间隔产生中断。
2、寄存器
WDT可以配置为一个看门狗定时器或一个通用的定时器,运行模式由WDCTL寄存器控制。
(1)WDCTL.MOED[1:0]该位用于启动WDT处于看门狗模式还是定时器模式。
(2)WDCTL.INT[1:0]该位选择定时器间隔定义为32 kHz振荡器周期的规定数,有4个时间间隔供选择。
(3)WDCTL.CLR[3:0]当运行在定时器模式,定时器可以通过写1到CLR[0](不管其他3位)被清除为0x0000(但是不停止);当运行在看门狗模式,写入 0xA 到 WDCTL.CLR[3:0],然后在一个看门狗周期写入 0x5 到同一个寄存器位,定时器计数就可以被清除(计数归零)。
3、看门狗模式
在系统复位之后,看门狗定时器就默认被禁用。要设置 WDT 在看门狗模式,必须设置 WDCTL.MODE[1:0]位为 10 。然后看门狗定时器的计数器从 0 开始递增。
在看门狗模式下,计数器达到选定定时器的间隔值,看门狗定时器就为系统产生一个复位信号。如果在计数器达到选定 定时器的间隔值之前,执行了一个看门狗清除序列,计数器就复位到 0,重新计数。
看门狗清除:在一个看门狗时钟周期内,写入 0xA 到 WDCTL.CLR[3:0],然后写入 0x5 到同一个寄存器位。如果这个序列没 有在看门狗周期结束之前执行完毕,看门狗定时器就为系统产生一个复位信号。
使用代码如下所示:
#include <ioCC2530.h>
#define uint unsigned int
#define uchar unsigned char
//定义控制LED灯的端口
#define LED1 P1_0
#define LED2 P1_1 //定义LED2为P11口控制
//函数声明
void Delayms(uint xms); //延时函数
void InitLed(void); //初始化P1口
/****************************
//延时函数
*****************************/
void Delayms(uint xms) //i=xms 即延时i毫秒
{
uint i,j;
for(i=xms;i>0;i--)
for(j=587;j>0;j--);
}
//初始化LED灯
void InitLed(void)
{
P1DIR |= 0x03; //P1_0、P1_1定义为输出
P1INP |= 0X03; //打开下拉
LED1 = 0; //LED1灯熄灭
LED2 = 0; //LED2灯熄灭
}
//初始化看门狗
void Init_Watchdog(void)
{
WDCTL = 0x00; //这是必须的,打开IDLE才能设置看门狗
WDCTL |= 0x08; //00001000设置看门狗模式,选择时间间隔一秒
}
//喂狗函数,即看门狗清除
void FeetDog(void)
{
//在一个看门狗时钟周期内,写入 0xA 到 WDCTL.CLR[3:0],然后写入 0x5 到同一个寄存器位。
WDCTL = 0xa0;
WDCTL = 0x50;
}
void main(void)
{
InitLed(); //调用初始化函数
Init_Watchdog();
LED1=1;
while(1)
{
LED2=~LED2; //仅指示作用。
Delayms(300);
LED1=0;
//通过注释测试,观察LED1,系统在不停复位。
FeetDog();//防止程序跑飞
}
}
注意:在看门狗模式下,一旦定时器使能,就不可以禁用定时器,因此,如果 WDT 位已经运行在看门狗模式下 ,再往 WDCTL.MODE[1:0]写入 00 或 10 就不起作用了。
4、普通定时器模式
当我们的程序不需要看门狗时,WDT可以被设置为一般的定时器使用,把 WDCTL.MODE[1:0]位设置为 11,WDT被设置为一般定时器模式,定时器间隔由 WDCTL.INT[1:0]位设置。定时器就开始后从 0开始计数,当计数器达到选定间隔值,定时器将产生一个中断请求(IRCON2.WDTIF/IEN2.WDTIE)。
在定时器模式下,可以通过写入 1 到 WDCTL.CLR[0]来清除定时器内容。当定时器被清除,计数器的内容就置为 0。写入 00 或 01 到 WDCTL.MODE[1:0]来停止定时器,并清除它为 0。
使用代码如下所示:通过看门狗定时器实现LED灯1s周期性闪烁
#include<iocc2530.h>
#define LED P1_1
void initLED()
{
P1SEL &=~0X1B;
P1DIR |=0x1B;
P1 &=~0X1B;
}
void initWDT()
{
WDCTL =0X0C; //00001100 配置看门狗模式以及间隔时间
IEN2 |=0X20; //看门狗的中断控制为5 0010 0000
EA=1; //打开总中断
}
#pragma vector = WDT_VECTOR //WDT中断服务函数
__interrupt void WDT_more()
{
WDTIF=0; //清除标志位
LED=~LED;
}
void main()
{
initLED();
initWDT();
while(1)
{}
}
注意:在定时器操作期间,定时器间隔不能改变,且当定时器开始时必须设置。在定时器模式下,当达到定时器间隔时,不会产生复位。