STM32F103五分钟入门系列(十三)独立看门狗IWDG

Posted 自信且爱笑‘

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32F103五分钟入门系列(十三)独立看门狗IWDG相关的知识,希望对你有一定的参考价值。

学习板:STM32F103ZET6

一、独立看门狗(IWDG)简介

1、什么是看门狗

看门狗是为了避免程序跑飞而设置的,在程序正常运行情况下,会一直“喂狗”,使程序不会复位。可以这样理解:在一个定时器中断中,中断服务函数里是整个程序的复位,在定时器之外,会一直给定时器重装载初值(相当于喂狗),程序一直执行正常的话,定时器不会发生中断,即不会进入中断服务函数,不会执行复位程序;当程序跑飞时,由于没有“喂狗”,定时器计数到0(如向下计数时),发生中断,执行中断服务函数里的复位程序,程序重新开始执行。

2、独立看门狗应用场合

由于独立看门狗时钟源由LSI时钟提供,并不精确,所以IWDG最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。

二、独立看门狗时钟

从时钟框图可以看到,看门狗的时钟为内部低速时钟40KHZ,我们知道LSI和HSI都是有内部RC振荡电路生成的,输出不稳定,所以这个时钟大约为40KHZ,并不精准。

三、独立看门狗的相关寄存器

(1)键寄存器(IWDG_KR)

该寄存器是低16位有效的32位寄存器。从上图得到以下信息:

①IWDR_KR寄存器是只写寄存器
②IWDR_KR写入0XAAAA,才算“喂狗”,且一定时间间隔必须写入,否则程序复位
③IWDR_KR写入0X5555表示允许访问IWDG_PR和IWDG_RLR寄存器,未写入时这两个寄存器处于保护状态,无法进行写操作
④IWDR_KR写入0XCCCC,启动看门狗

所以一般程序可以如下:

	IWDG->KR=0x5555;//取消IWDG_PR和IWDG_RLR寄存器保护
	
	IWDG->PR=   //设置这俩个寄存器
	IWDG->RLR=
	IWDG->KR=0xAAAA;//开始时给重装载寄存器装载初值
	IWDG->KR=0xCCCC;//启动看门狗
	
	//程序中喂狗(程序其它地方)
	IWDG->KR=0xAAAA;//喂狗

(2)预分频寄存器(IWDG_PR)

该寄存器是只有低3位有效的32位寄存器,之前的IWDG_KR寄存器中也强调过,要对IWDG_PR寄存器操作,必须先对IWDG_KR写入0x5555。

我们知道,独立看门狗的时钟是40KHZ的LSI,经过本寄存器设置预分频系数后,独立看门狗的时钟会变为40KHZ/预分频因子。

(3)重装载寄存器(IWDG_RLR)

该寄存器并不像SysTick定时器的重装载寄存器一样,该寄存器不需要手动装载初值,只需设置好装载值后,每次给IWDG_KR寄存器写入0xAAAA,即可装载初值。

(4)状态寄存器(IWDG_SR)

该寄存器只有位0和位1有效,位0指示预分频值更新、位1指示重装载值更新;置1时表示正在更新,置0时表示更新完成。

通过该寄存器还可以获取目前看门狗装载值、预分频器更新状态:

while(IWDG->SR|0x00000002)
{

}//重装载值更新中


f(!(IWDG->SR|0x00000002))
{

}//重装载值更新完成

四、独立看门狗编程顺序

①取消寄存器写保护(向 IWDG_KR 写入 0X5555)

②设置独立看门狗的预分频系数和重装载值(IWDG_PR和IWDG_PLR)

③重载计数值喂狗(向 IWDG_KR 写入 0XAAAA)

④启动看门狗(向 IWDG_KR 写入 0XCCCC)

⑤程序的其他地方喂狗(向 IWDG_KR 写入 0XAAAA)

五、例子(寄存器版)

例:按下KEY_UP后,喂狗,正常状态下,LED0处于亮灯状态。(当没有喂狗时,程序被复位,此时LED0会灭了再被点亮)

LED和KEY的代码之前总结过了,可以详见:STM32F103五分钟入门系列(五)按键实验(库函数+寄存器)

这里直接附代码:

//led.h
#ifndef LED_H
#define LED_H
void LED_Init(void);

#endif
//led.c
#include "sys.h"
#include "stm32f10x.h"
#include "led.h"
void LED_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct_B;
	GPIO_InitTypeDef GPIO_InitStruct_E;
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE ,ENABLE);
	
	GPIO_InitStruct_B.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStruct_B.GPIO_Pin=GPIO_Pin_5;
	GPIO_InitStruct_B.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOB,&GPIO_InitStruct_B);
	
	GPIO_InitStruct_E.GPIO_Mode=GPIO_Mode_Out_PP;
	GPIO_InitStruct_E.GPIO_Pin=GPIO_Pin_5;
	GPIO_InitStruct_E.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOE,&GPIO_InitStruct_E);
	
	GPIO_SetBits(GPIOB, GPIO_Pin_5);//PB5置高电平
	//GPIO_WriteBit(GPIOB, GPIO_Pin_5,1);
	//GPIO_Write(GPIOB,0x0020);              //慎用
	//PBout(5)=1;
	GPIO_SetBits(GPIOE, GPIO_Pin_5);//PE5置高电平
	//GPIO_WriteBit(GPIOE, GPIO_Pin_5,1);
	//GPIO_Write(GPIOE,0x0020);              //慎用
	//PEout(5)=1;
}
//key.h
#ifndef KEY_H
#define KEY_H
void KEY_Init(void);
#endif
//key.c
#include "stm32f10x.h"
#include "sys.h"
#include "key.h"
void KEY_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct_A;
	GPIO_InitTypeDef GPIO_InitStruct_E;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOE , ENABLE);//使能GPIOA和GPIOE(PA0 PE2、3、4)
	
	GPIO_InitStruct_A.GPIO_Mode=GPIO_Mode_IPD;
	GPIO_InitStruct_A.GPIO_Pin=GPIO_Pin_0 ;
	GPIO_InitStruct_A.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStruct_A);//PA0 key_up  下拉输入
	
	GPIO_InitStruct_E.GPIO_Mode=GPIO_Mode_IPU;
	GPIO_InitStruct_E.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
	GPIO_InitStruct_E.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOE, &GPIO_InitStruct_E);//PE2、3、4 key0、key1、key2 上拉输入
	
	GPIO_SetBits(GPIOE,GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4);
	GPIO_ResetBits(GPIOA, GPIO_Pin_0);
}

接下来写独立看门狗实验,寄存器版比较简单

首先看一下预分频系数和重装载值怎么搞。

LSI约为40KHZ,就当它是准确的40KHZ,预分频系数为4、8、16…
如预分频系数为16时,设置1s喂狗。

则独立看门狗时钟为40kHZ/16,,每计数一次的时间:16/40ms,则1s需要计数:40000/16=2500;所以可以设置:

分频系数为16,即IWDG_PR寄存器的值为010,即0x02
重装载初值为2500,即IWDG_RLR寄存器的值为:2500

需要注意的是,重装载值寄存器IWDG_RLR只有低12位有效,所以最大重装载值为:2^12-1=4095

mian.c中代码:

//main.c
#include "stm32f10x.h"
#include "led.h"
#include "key.h"
#include "sys.h"
#include "delay.h"
 int main(void)
 {	
	 KEY_Init();
	 LED_Init();
	 delay_init();
	 
	 delay_ms(500);//为了看到程序复位
	 PBout(5)=0;//点亮LED0
	 
	 IWDG->KR=0x5555;//取消IWDG_PR和IWDG_RLR寄存器保护
	 IWDG->PR=0x02;
	 IWDG->RLR=2500;//设置分频系数和重装载值
	 //正常操作应该是先位与运算清空寄存器,再位或运算赋值
	 
	 IWDG->KR=0xAAAA;//初始状态下,装载初值
	
	 IWDG->KR=0xCCCC;//启动看门狗
	 while(1)
	 {
		if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0))//检测key_up按下
		{
			IWDG->KR=0xAAAA;//喂狗
		}
	 }
	  
 }

上述程序需要注意的是一定要延时一个时间,否则没有喂狗导致程序重新执行,但是LED灭一下,根本看不出变化。

通过上述代码,下载调试后发现:在KEY_UP未按下时,LED0每亮1s,灭0.5s,当长按KEY_UP时,LED0保持常亮状态。

六、独立看门狗常用库函数

独立看门狗的常用库函数定义在stm32f10x_iwdg.h中:

(1)取消PR、RLR寄存器写保护函数IWDG_WriteAccessCmd()

参数:

操作:

可以看到该函数就是将KR写入0x5555,来取消PR、RLR寄存器写保护

(2)设置分频因子函数IWDG_SetPrescaler()

参数:

操作:

可以看到,该函数是将16进制数写入PR寄存器,其分频因子对应的16进制数:

(3)设置重装载值函数IWDG_SetReload()

参数:

该参数由我们计算得来,由于RLR寄存器是低12位有效,所以该值<=0xFFF

操作:

直接将重装载初值写入到RLR寄存器

(4)重装载初值函数(喂狗)IWDG_ReloadCounter

参数:

操作:

直接对KR寄存器写入0xAAAA,喂狗。

(5)启动独立看门狗函数IWDG_Enable()

参数:

操作:

给KR寄存器写入0xCCCC,启动独立看门狗。

(6)独立看门狗状态获取函数IWDG_GetFlagStatus()

参数:

参数FLAG=0x0001|0x0002=0x0003

当独立看门狗处于更新状态时:(IWDG->SR & IWDG_FLAG) != (uint32_t)RESET,返回SET,表示正在更新,否则不在更新状态。

操作:
直接获取SR寄存器位0和位1的值

返回值:

返回SET(!0)表示处于更新中
返回RESET(0)表示不在更新中

七、例子(库函数版)

库函数版也比较简单,直接把刚刚例子中寄存器部分替换为库函数

代码如下:

//mian.c
#include "stm32f10x.h"
#include "led.h"
#include "key.h"
#include "sys.h"
#include "delay.h"
int main(void)
 {	
	 KEY_Init();
	 LED_Init();
	 delay_init();
	 
	 delay_ms(500);//为了看到程序复位
	 PBout(5)=0;//点亮LED0
	 
	 //IWDG->KR=0x5555;//取消IWDG_PR和IWDG_RLR寄存器保护
	  IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
	 
	 //IWDG->PR=0x02;//设置重装载值
	 IWDG_SetPrescaler(IWDG_Prescaler_16);
	 
	 //IWDG->RLR=2500;//设置分频系数和重装载值
	  IWDG_SetReload(2500);//设置分频系数和重装载值
	 //正常操作应该是先位与运算清空寄存器,再位或运算赋值
	 
	//IWDG->KR=0xAAAA;//初始状态下,装载初值
	 IWDG_ReloadCounter();
	 
	 //IWDG->KR=0xCCCC;//启动看门狗
	 IWDG_Enable();
	 while(1)
	 {
		if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0))//检测key_up按下
		{
			//IWDG->KR=0xAAAA;//喂狗
			IWDG_ReloadCounter();
		}
	 }  
 }

以上是关于STM32F103五分钟入门系列(十三)独立看门狗IWDG的主要内容,如果未能解决你的问题,请参考以下文章

STM32F103五分钟入门系列(十四)窗口看门狗WWDG

STM32F103(二十三)通用同步异步收发器(USART)

STM32F103(二十三)通用同步异步收发器(USART)

STM32F103ZET6独立看门狗

STM32F103五分钟入门系列(十六)输入捕获(精雕细琢-.-)

STM32F103五分钟入门系列外部中断大汇总