在 STC89C52 单片机中,看门狗控制寄存器的固定地址为 0xE1
。此地址由芯片厂商在硬件设计时确定,但是它在头文件中并未给出,因此在使用看门狗系统时需要声明下这个特殊功能寄存器
sfr WDT_CONTR = 0xE1;
本案将用一个小灯的工作状况来展示看门狗工作性质。
首先看下看门狗的工作性质:
在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成各种寄存器和内存的数据混乱,会导致程序指针错误,不在程序区,取出错误的程序指令等,都有可能会陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续正常工作,导致整个系统的陷入停滞状态,发生不可预料的后果。
看门狗,又叫 watchdog,从本质上来说就是一个定时器电路,一般有一个输入和一个输出,其中输入叫做喂狗,输出一般连接到另外一个部分的复位端,一般是连接到单片机。 看门狗的功能是定期的查看芯片内部的情况,一旦发生错误就向芯片发出重启信号。看门狗命令在程序的中断中拥有最高的优先级。(来自百科)
1. 看门狗复位机制
-
内部自动复位
当看门狗超时(计数器溢出)时,芯片内部会自动触发复位信号,直接重启单片机内核和所有外设。-
无需RST引脚动作:复位由内部逻辑完成,不依赖外部RST引脚电平变化。
-
RST引脚状态:复位期间,RST引脚可能保持高电平(需外部上拉电阻维持),但复位动作本身由内部完成。
-
-
2.
WDT_CONTR
寄存器的作用 -
功能:
WDT_CONTR
是 看门狗控制寄存器,用于配置看门狗定时器(Watchdog Timer, WDT)的工作模式、分频系数和喂狗操作。 -
关键功能位(以 STC89C52 为例):
位 名称 功能描述 5 EN_WDT 看门狗使能位(1=启用,0=关闭) 4 CLR_WDT 喂狗位(写 1 清除计数器) 3 IDLE_WDT 空闲模式看门狗控制(1=计数,0=暂停) 2-0 PS[2:0] 分频系数选择位(控制溢出时间)
看门狗寄存器设置:WDT_CONTR = 0x35; //延时2.27S
4. 为何需要这样设置?
-
目的:
通过sfr WDT_CONTR = 0xE1;
将看门狗控制寄存器绑定到 C 语言变量,使得程序员可以通过操作变量直接配置看门狗,例如:WDT_CONTR = 0x35; // 二进制 0011 0101
-
详细配置解析(以
0x35
为例):-
EN_WDT=1:启用看门狗。
-
CLR_WDT=1:喂狗操作(需周期性执行)。
-
IDLE_WDT=0:空闲模式下看门狗暂停计数。
-
PS[2:0]=101:分频系数为
2^(5+1)=64
,决定溢出时间。 -
2. 计算示例(PS=5, Fosc=11.0592MHz)
T溢出=12×64×32768/11,059,200≈2.275秒
-
设计一个简单程序验证下看门狗系统:
#include"reg52.h"
#include "macro_and_const.h"
sfr WDT_CONTR = 0xE1;
sbit ENLED = P1^4; // 使能引脚P1.4 这几个部分是38译码器是笔者硬件电路方面的要求
sbit ADDR0 = P1^0; // 地址线0
sbit ADDR1 = P1^1; // 地址线1
sbit ADDR2 = P1^2; // 地址线2
sbit ADDR3 = P1^3; // 地址线3(E3使能)
sbit led = P0^0;
/*******************************************
延时一毫秒函数
*******************************************/
void Timer0_Init() {
TMOD |= 0x01; // 模式1(16位定时器)
TH0 = 0xFC; // 初值,定时1ms(11.0592MHz)
TL0 = 0x66;
TR0 = 1; // 启动定时器
}
void delay(uint ms) {
uint i;
for (i = 0; i < ms; i++) {
TH0 = 0xFC; TL0 = 0x66; // 重载初值
while (!TF0); // 等待溢出
TF0 = 0; // 清除标志
}
}
void main(void)
{
Timer0_Init();
WDT_CONTR = 0x35;//设置看门狗时间2.27s
ADDR3 = 1; // E3=1使能
ADDR2 = 1; // A2=1
ADDR1 = 1; // A1=1
ADDR0 = 0; // A0=0 → Y6有效
ENLED = 0; // E1&E2使能(低电平)
led = 0;
delay(200);
led = 1;
delay(200); //LED闪烁3下
led = 0;
delay(200);
led = 1;
delay(200);
led = 0;
WDT_CONTR = 0x35;
while(1)
{
led = 0;
delay(2000);//延时2s
WDT_CONTR = 0x35; //喂狗
}
}
/*--------------------------------------------------------------------------
MACROANDCONST.H
--------------------------------------------------------------------------*/
#ifndef _MACRO_AND_CONST_H_
#define _MACRO_AND_CONST_H_
/*无符号整形*/
typedef unsigned int uint16;
typedef unsigned int UINT;
typedef unsigned int uint;
typedef unsigned int UINT16;
typedef unsigned int WORD;
typedef unsigned int word;
/*有符号整形*/
typedef int int16;
typedef int INT16;
/*无符号长整形*/
typedef unsigned long uint32;
typedef unsigned long UINT32;
typedef unsigned long DWORD;
typedef unsigned long dword;
/*有符号长整形*/
typedef long int32;
typedef long INT32;
/*有符号字符形*/
typedef signed char int8;
typedef signed char INT8;
/*无符号字整形*/
typedef unsigned char boolean;
typedef unsigned char BOOLEAN;
typedef unsigned char uchar;
typedef unsigned char UCHAR;
typedef unsigned char UINT8;
typedef unsigned char uint8;
typedef unsigned char BOOL;
typedef unsigned char bool;
/*C51编译器的扩展类型*/
typedef bit byte;
typedef bit BYTE;
#ifndef EOF
#define EOF -1
#endif
#ifndef NULL
#define NULL ((void *) 0)
#endif
#ifndef enable
#define enable 1
#endif
#ifndef disable
#define disable 0
#endif
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#endif
这个是头文件
这个程序的现象是闪3下,然后LED一直点亮,因为看门狗触发的时间是2.27S,延时是2S,及时喂了狗,因此程序一直在while循环里跑。
看一下视频:及时喂狗程序一直运行_哔哩哔哩_bilibili
如果把循环里的延时语句修改一下改成3s即
while(1)
{
led = 0;
delay(3000);//延时3s
WDT_CONTR = 0x35; //喂狗
}
延时过长未能及时喂狗,因此单片系统复位了。所以现在的现象是闪烁3下,然后延时2.27S(这时LED灯是常亮的),系统复位后马上又闪烁三下,接着延时2.27S,一直这么循环。
看一下视频:
看门狗溢出一直复位_哔哩哔哩_bilibili
可以看到LED闪烁3下后延迟一段时间又开始闪烁,这个延迟时间就是看门狗设置的时间2.27S。无论这个延时语句是多少秒要超过2.27S,它的延时时间都是保持在2.27S。