STM32 看门狗

看门狗就是定期查看芯片内部的情况,一旦发生错误就向芯片发送重启信号,从而实现无人职守时持续工作。看门狗在程序中的中断拥有最高优先级。

工作原理:看门狗芯片与单片机的一个IO引脚相连,通过程序控制定时的往看门狗芯片发送脉冲(称为喂狗),当单片机由于其他原因导致跑飞或进入死循环,就不能执行喂狗,看门狗芯片没有接收到单片机的信号,则看门狗芯片向单片机复位引脚发送复位信号,则实现了单片机的自动复位。STM32 M4芯片集成了看门狗到内部,化身为一个计数器,当设定的计数值减法计数到0的时候,就会触发复位中断。需要定时的刷新计数值(喂狗),防止计数值到达0产生复位。

独立看门狗(IWDG):Independent Watch Dog
监测并解决软件导致的故障,当计数器达到超时值时,触发一个中断或产生系统复位。

独立看门狗由专用的低速时钟(LSI)驱动,因此在主时钟发生故障时,看门口仍然可以保持运行。
主时钟一般频率都比较高,比较容易收到外界条件的干扰,稳定性较差,低速时钟由于频率低,抗干扰能力比较强,能够保证在主时钟发生故障的情况下仍然能够运行,提高系统的稳定性。

IWDG主要特性:
1、自由运行递减计数器
2、时钟由独立的振荡器提供,
3、当递减计数器到达0x000时产生复位。

/*添加复位检测代码,反映出当前程序是否有问题,如果看门口复位太多,则需要检查程序*/
//检查当前复位是否由看门狗导致
if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)
{	
	printf("iwdg reset cpu\r\n");
	//清空标志位
	RCC_ClearFlag();
}
else
{
	//普通复位
	printf("normal reset cpu\r\n");
}

//使能看门口寄存器
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);

//设置看门狗的时钟,分频 32kHz/256=125Hz,就是一秒完成125次计数
IWDG_SetPrescaler(IWDG_Prescaler_256);

//设置看门狗计数值125  一秒内没有刷新计数值,就会复位一次
IWDG_SetReload(125);

//刷新独立看门狗的计数值,重新计数,就是喂狗动作
IWDG_ReloadCounter();

/* 使能独立看门狗 */
IWDG_Enable();

//建议:不要在main中喂狗,main中执行的代码比较多,难以确定喂狗的时刻。
//没有操作系统,利用定时器中断喂狗
//有操作系统,在任务中喂狗,任务相当于线程

定时器喂狗程序

void tim3_init(void)
{
	//使能定时器1的时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	
	/* 定时器的时间的配置,中断频率为1000Hz,也就是说中断周期时间为1ms 
		最大的定时器时间约为6.5535s
		TIM_TimeBaseStructure.TIM_Period =65535;
	
		如果要进行2秒的定时
		TIM_TimeBaseStructure.TIM_Period = (10000*2)-1;	
	
		如果要进行1秒的定时
		TIM_TimeBaseStructure.TIM_Period = (10000)-1;

		如果要进行100毫秒的定时
		TIM_TimeBaseStructure.TIM_Period = (10000/10)-1;	
	*/	
	
	//配置定时器3的属性,定时的时间 = 时钟源/频率
	TIM_TimeBaseStructure.TIM_Period = (10000/10)-1;						//定时时间100ms
	TIM_TimeBaseStructure.TIM_Prescaler =8400-1;							//第一分频,设置预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;					//第二分频,1分频
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;				//向上计数
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
	
	

	//配置NVIC的中断优先级
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
		
	
	//定时器3的中断配置
	TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);
	
	//使能定时器3工作
	TIM_Cmd(TIM3, ENABLE);


}

//独立看门狗的标志位
static volatile uint32_t g_iwdg_cnt=0;

int main(void)
{
	volat g_iwdg_cnt
	
	/* Check if the system has resumed from IWDG reset ,检查当前系统复位是否有看门狗复位导致*/
	if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)
	{
		/* IWDGRST flag set */
		printf("iwdg reset cpu\r\n");
	

	}
	else if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) != RESET)
	{
		/* WWDGRST flag set */
		printf("wwdg reset cpu\r\n");
	

	}	
	else
	{
		/* IWDGRST flag is not set */
		printf("normal reset cpu\r\n");

	}
	
	/* Clear reset flags,清空所有复位标记 */
	RCC_ClearFlag();	
	
	/* Enable write access to IWDG_PR and IWDG_RLR registers,解锁 */
	IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
	
	/* IWDG counter clock: LSI/256 ,独立看门狗的时钟频率=32KHz/256=125Hz,只要独立看门狗进行125次计数的时候,就代表1秒时间的到达*/
	IWDG_SetPrescaler(IWDG_Prescaler_256);


	//设置看门狗的计数值,计数值就决定独立看门狗的复位时刻,125:1秒复位一次,也告诉我们必须在1秒之内对看门狗进行喂狗(刷新计数值),否则CPU会复位。
	IWDG_SetReload(125);
	
	
	/* Reload IWDG counter,刷新独立看门狗的计数值 */
	IWDG_ReloadCounter();
	
	/* Enable IWDG (the LSI oscillator will be enabled by hardware) ,使能独立看门狗工作*/
	IWDG_Enable();
	
	//定时器3的初始化
	tim3_init();
	
	
	while(1)
	{
#if 1  	//1秒内喂狗		
		//刷新计数值
		//如果在裸机代码当中,放在main函数里面运行的话,很难确定喂狗的时刻
		//推荐1)看门狗喂狗是放在定时器中断进行喂狗
		//    2)如果有实时操作系统的支持,可以放在任务(线程)里面进行喂狗
		
		//IWDG_ReloadCounter();
		delay_ms(900);
		printf("main is running...\r\n");
		//等待蓝牙数据
		//播放音乐
		//控制数码管
		//......
		
		//while(PEin(6)==0);
		
		//在末尾添加g_iwdg_cnt
		g_iwdg_cnt=0;
#else 
		//1秒之外进行喂狗
		//刷新计数值
		IWDG_ReloadCounter();

		delay_ms(1100);
#endif		
	
	}
}


void TIM3_IRQHandler(void)
{
	
	//检查是否有更新事件触发
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET)
	{
		//添加代码
		g_iwdg_cnt++;
		
		//100*100ms=20s
		if(g_iwdg_cnt >= 200)
		{
			//等待看门狗超时复位
			while(1);
		}
		
		IWDG_ReloadCounter();
		
		//清空标志位,告诉CPU,我已经处理完毕,可以接收新的一次中断请求
		TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
	}


}

窗口看门狗(WWDG):Window Watch Dog

窗口看门狗常被用来监测,由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而造成的软件故障,必须在限定的时间窗口内刷新计数器,否则导致MCU复位。
窗口看门狗需要在实时操作系统下运行,可以监测系统错误

WWDG的主要特性:
1、可编程的自由运行计递减数器,
2、复位条件:
当递减计数器值小于0x40时复位,
在窗口外重载递减计数器时复位
3、提前唤醒中断(EWI):当递减计数器等于0x40时被触发

喂狗注意事项:必须在窗口范围内喂狗。
提前喂狗,cpu复位
超时喂狗,cpu复位

程序设计:

/* 检查是否窗口看门狗导致的复位,如果发现由窗口看门
狗导致的复位,输出打印信息*/
if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) != RESET)
{
/* WWDGRST flag set */
printf("wwdg reset cpu\r\n");
/* Clear reset flags */
RCC_ClearFlag();
}
else
{
/* WWDGRST flag is not set */
printf("normal reset cpu\r\n");
}

/* WWDG configuration ,窗口看门狗的配置*/
/* Enable WWDG clock ,使能看门狗的时钟*/
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
/* 窗口看门狗的时钟 = (PCLK1 (42MHz)/4096)/8 = 1281 Hz (~780 us) */
WWDG_SetPrescaler(WWDG_Prescaler_8);

/* Set Window value to 80; WWDG counter should be refreshed only when the counter
is below 80 (and greater than 0x40) otherwise a reset will be generated
设置窗口的上限值为 80
*/
WWDG_SetWindowValue(80);
/* 设置计数值的初值为 127,则窗口看门狗的最大超时时间 = 780 us * 64 = 49.92 ms
这个时候窗口刷新时间如下
~780 * (127-80) = 36.6ms < refresh window < ~780 * 64 = 49.9ms
*/
WWDG_Enable(127);
//WWDG NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn; //窗口看门狗中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0; //抢占优先级 0
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级 0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化 VIC 寄
存器
//清空提前唤醒中断标志位
WWDG_ClearFlag();
//使能提前唤醒中断
WWDG_EnableIT();

// 看门狗中断服务函数
void WWDG_IRQHandler(void)
{
	if(WWDG_GetFlagStatus()==SET)
	{
	//进行喂狗
	WWDG_SetCounter(127);
	//清空提前唤醒中断标志位
	WWDG_ClearFlag();
	}
}

STM32代码


static volatile uint32_t g_wwdg_cnt=0;

int main(void)
{

	int32_t rt = 0;
	

	
	/* GPIOA GPIOE GPIOF硬件时钟使能,就是让GPIOA GPIOE GPIOF工作 */
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);	
	

	
	
	/* 配置PE13 PE14为输出模式,让这根引脚具有输出高低电平的功能 */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14;	//第13 14号引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;			//输出模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;			//推挽输出,增强驱动能力,引脚的输出电流更大
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;		//引脚的速度最大为100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;		//没有使用内部上拉电阻
	GPIO_Init(GPIOE, &GPIO_InitStructure);	
	
	
	/* 配置PF9 PF10为输出模式,让这根引脚具有输出高低电平的功能 */
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;	//第9 10号引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;			//输出模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;			//推挽输出,增强驱动能力,引脚的输出电流更大
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;		//引脚的速度最大为100MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;		//没有使用内部上拉电阻
	GPIO_Init(GPIOF, &GPIO_InitStructure);
	
	GPIO_SetBits(GPIOF,GPIO_Pin_9|GPIO_Pin_10);
	GPIO_SetBits(GPIOE,GPIO_Pin_13|GPIO_Pin_14);
	
	//配置中断优先级分组选择第二组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	//串口1初始化波特率为115200bps
	usart1_init(115200);
	
	delay_ms(500);
	
	
	/* Check if the system has resumed from IWDG reset ,检查当前系统复位是否有看门狗复位导致*/
	if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)
	{
		/* IWDGRST flag set */
		printf("iwdg reset cpu\r\n");
	

	}
	else if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) != RESET)
	{
		/* WWDGRST flag set */
		printf("wwdg reset cpu\r\n");
	

	}	
	else
	{
		/* IWDGRST flag is not set */
		printf("normal reset cpu\r\n");

	}
	
	/* Clear reset flags,清空所有复位标记 */
	RCC_ClearFlag();	
	
	/* WWDG configuration */
	/* Enable WWDG clock ,使能窗口看门狗的时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
	
	/* WWDG clock counter = (PCLK1 (42MHz)/4096)/8 = 1281 Hz (~780 us)  
	
	   窗口看门狗的时钟频率= (PCLK1 (42MHz)/4096)/8 = 1281 Hz (-1,780 us T=1/f)
	*/
	WWDG_SetPrescaler(WWDG_Prescaler_8);
	
	/* Set Window value to 80; WWDG counter should be refreshed only when the counter
	is below 80 (and greater than 64) otherwise a reset will be generated */
	WWDG_SetWindowValue(80);
	
	
	/* Enable WWDG and set counter value to 127, WWDG timeout = ~780 us * 64 = 49.92 ms 
	In this case the refresh window is: 
			~780 * (127-80) = 36.6ms < refresh window < ~780 * 64 = 49.9ms
			
	设置看门狗的初始值为127
	*/
	WWDG_Enable(127);
	
	WWDG_ClearFlag();
	
	//使能窗口看门狗唤醒中断
	WWDG_EnableIT();
	
	//配置窗口看门狗的中断优先级
	NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);


	while(1)
	{
		
		
		//末尾添加一行代码
		g_wwdg_cnt=0;
	}

}


void WWDG_IRQHandler(void)
{
	if(WWDG_GetFlagStatus()==SET)
	{
		g_wwdg_cnt++;
		
		//约10秒时间
		if(g_wwdg_cnt >= 200)
		{
			while(1);
		}
		
		//喂狗
		WWDG_SetCounter(127);
	
		
	
		//清空标志位
		
		WWDG_ClearFlag();
	}
}
  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
STM32看门狗(Watchdog)是一种硬件机制,用于监测程序是否正常运行。如果程序发生死循环或者挂起等异常情况,看门狗会在一定时间内未收到喂狗信号时,自动重启系统,确保系统能够正常运行。 下面是使用STM32看门狗的步骤: 1. 配置看门狗定时器 通过设置看门狗计数器(IWDG_PR)和重载值(IWDG_RLR)来配置看门狗定时器。这里以STM32F103为例,设置看门狗定时器时钟为40KHz,重载值为625,则看门狗定时器的定时时间为625/40KHz=15.625ms。 ```c RCC->APB1ENR |= RCC_APB1ENR_IWDGEN; // 使能看门狗时钟 IWDG->KR = 0x5555; // 开始寄存器操作 IWDG->PR = 4; // 分频系数为256,时钟为40KHz IWDG->RLR = 625; // 设置重载值,定时时间为15.625ms IWDG->KR = 0xAAAA; // 操作完成 ``` 2. 喂狗 在程序正常运行时,需要定期喂狗,以避免看门狗的复位。喂狗的方法是向看门狗喂狗寄存器(IWDG_KR)写入0xAAAA,然后再写入0x5555。 ```c IWDG->KR = 0xAAAA; // 喂狗 IWDG->KR = 0x5555; ``` 3. 启动看门狗 配置好看门狗定时器和喂狗后,需要启动看门狗,使其开始工作。启动看门狗的方法是向看门狗控制寄存器(IWDG_KR)写入0xCCCC。 ```c IWDG->KR = 0xCCCC; // 启动看门狗 ``` 4. 处理看门狗超时复位 在程序运行过程中,需要处理看门狗超时复位,以避免程序出现死循环或挂起等异常情况。当看门狗定时器到达重载值时,会自动触发复位,导致系统重启。程序需要在重启后重新初始化系统,并处理异常情况。 ```c if (RCC->CSR & RCC_CSR_IWDGRSTF) { // 判断是否是看门狗复位 RCC->CSR |= RCC_CSR_RMVF; // 清除复位标志位 // 处理异常情况 ... } ``` 以上就是STM32看门狗的使用步骤。需要注意的是,在配置看门狗时,要确保看门狗的定时时间足够长,以保证程序能够正常运行。另外,在程序中也要定期喂狗,以避免看门狗的复位。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值