STC15W201S系列单片机 实现外部电路的软件看门狗程序设计

本人目前是一个普通一本刚升大四的的实习生,实习岗位是嵌入式软件开发。
随手记录总结一下实习项目经验。

目的:用STC15W201S实现对外部主芯片电路的看门狗(以下统称外部看门狗);同时确保自身稳定,也设计自身的看门狗程序(以下统称内部看门狗)。

描述:外部主芯片定时向STC15W201S的引脚P3.3发送STATUS1脉冲信号,STC15W201S检测信号,若超过一段时间未检测到脉冲信号,通过引脚P1.0发送POWERCONTROL长脉冲信号给电源将其断电重启。

实现:主芯片每6s发送一个500ms的高电平喂狗脉冲信号,考虑某些意外因素和项目考虑,看门狗设计成每30s判断一次该30s内喂狗脉冲次数,大于等于4次则说明主芯片正常,否则为不正常;若超过3分钟的不正常状态,则发送60s的低电平信号重启电源。

思路:外部看门狗,由于引脚P3.3为外部中断1的引脚,可以用中断定时器来判断发过来的脉冲信号是否为喂狗信号。内部看门狗则使用芯片自带的看门狗寄存器功能。

下图为STC15W201S系列单片机引脚图:
(图像取自STCMCU官网文档)图像取自STCMCU官网文档

本项目所需的内容不多
由于该单片机有两个定时/计数器T0和T2,作为定时器,T0有4种工作方式选择,T2只有一种(16位自动重装载)。本模块只需要T0和T2都用16位自动重装载,T0用于累计计算外部看门狗脉冲长度,T2用于内部看门狗循环喂狗。

外部看门狗
将外部中断1设为上升和下降沿均可触发,当上升沿触发时,开定时器0,当下降沿触发,关定时器0,计算这一个脉冲的长度,当大于300ms时,判断为喂狗脉冲。

内部看门狗
使用的看门狗寄存器和定时器2来设计,看门狗寄存器设计为4.19秒预装时间,超过4.19秒将重启单片机,定时器2的中断设计为每0.5秒喂一次狗,可以判断单片机运行状况是否正常。

(PS:本来想画流程图,但是这CSDN的模板写不了就算了)

代码如下

//设时钟频率为12Mhz

#include <reg51.h>

#define Fosc 12000000UL //震荡频率
#define Core 13043U	//15F/L/Wxx型号的Core

#define WDG_TIMEVAL 30000 //看门狗时间 单位(ms)
#define POWER_TIMEVAL 60000  //重启电源时间 单位(ms)
#define T0_WDG_NUM 6  //50ms定时器0计数次数,脉冲时间为6*50ms=300ms

sfr  AUXR = 0x8e;//定时器辅助特殊寄存器
sfr  WDT_CONTR = 0xc1; //看门狗特殊寄存器
sfr  T2H = 0xD6;//定时器2高8位寄存器
sfr  T2L = 0xD7;//定时器2低8位寄存器
sfr  IE2 = 0xAF;//中断寄存器2(用于控制定时器2中断允许)

sbit  POWER_CONTRAL = P1^0;
sbit   STATUS1 = P3^3;

//1:上升沿中断,0:下降沿中断
bit  FLAG;
//定时器0重装载次数
unsigned int time0_num;
//30s内喂狗次数
unsigned int wdg_num;
//3分钟内未喂狗次数
unsigned int no_wdg_num;
//定时器2重装载次数
unsigned int time2_num;

/*延时函数 单位(ms)*/
void delay_ms(unsigned int t)
{
    unsigned int i;
    do{
        i = Fosc / Core;
        while(--i);
    }while(--t);
}
/*使能中断INT1函数*/
void Init_interrupt1()
{
 IT1 = 0;   //中断源选择位。0上升沿或者下降沿均可触发;1下降沿触发
 EX1 = 1;   //INT1中断允许位,使能INT1中断 
}
/*使能定时器0和定时器1及初始化函数*/
void Init_timer0()
{
 AUXR = 0x00;   //定时器0为12T模式,12分频速度 1us
 TMOD = 0x00; //定时器0为模式0(16位自动重装载);定时2固定为16位自动
 TH0 = 0x3C;
 TL0 = 0xB0;  //定时器0装载值为50,000,即50ms
 ET0 = 1;  //允许定时器0中断
}
/*本芯片的看门狗初始化*/
void Init_watchdog()
{
 AUXR = 0x10;   //定时器0为12T模式,12分频速度 1us;开定时器2,12分频,定时器2启动
 T2H = 0x3C;
 T2L = 0xB0;  //定时器2装载值为50,000,即50ms
 IE2 = 0x04;  //允许定时器2中断
 WDT_CONTR = 0x3E;//清零,启动看门狗,4.19s
}
/*外部中断1(INT1)响应函数*/
void exint1() interrupt 2
{
 	FLAG = INT1;  //保存INT1口的状态
	if(FLAG)//为上升沿
 	{
  		TR0 = 1;//开定时器0
  		time0_num = 0;
 	}
 	else //为下降沿
 	{
  		TR0 = 0;//关定时器0
  		if(time0_num>T0_WDG_NUM)//脉冲长度大于300ms则喂狗
  		{
   			++wdg_num;
  		}
  		time0_num = 0;
 	}
}
/*定时器0中断响应函数*/
void tm0_isr() interrupt 1 using 1
{
   ++time0_num;
}
/*定时器2中断响应函数*/
void t2_isr() interrupt 12 using 1
{
 	++time2_num;
 	if(time2_num>10)//每0.5s喂一次狗
 	{
  		WDT_CONTR = 0x3E;//看门狗寄存器初始化
  		time2_num = 0}
}

void main(void)
{
 	POWER_CONTRAL = 1;//初始化引脚
 	STATUS1 = 1;
 	
	time0_num = 0;
	time2_num = 0;
	wdg_num = 0;
	no_wdg_num = 0; 
	Init_timer0();//初始化定时器0
	Init_watchdog();//初始化本芯片看门狗
	Init_interrupt1();//初始化中断1
 	EA = 1;    //CPU的总中断允许控制位,使能总中断
 	while(1)
  	{
  		delay_ms(WDG_TIMEVAL);//延时30s,判断30s内有无喂狗
  		if(wdg_num>3)//30s内喂狗超过3次,正常运行
  		{ 
   			no_wdg_num = 0;
  		}
  		else//未超过4次,标志30秒内未通信
  		{
   			++no_wdg_num;  
   			if(no_wdg_num>5)//连续3min没有喂狗,开关电源
   			{
    				POWER_CONTRAL=0;
    				delay_ms(POWER_TIMEVAL);
    				POWER_CONTRAL=1;
    				no_wdg_num = 0;
   			} 
 	 	}
  		wdg_num = 0;
	 }
}

设计的主要问题是中断和定时器的各种寄存器的选择,都可以在STCMCU官网上可以查询,找到模板。程序灵活多变,可根据需求更改逻辑。

猜你喜欢

转载自blog.csdn.net/weixin_43727672/article/details/96135353