STM32-自学笔记(17.独立看门狗)

概述:独立看门狗(IWDG)

窗口看门狗主要用于对某个局部应用程序进行监控,防止其过早或过晚地执行,其正常工作的前提是STM32的主时钟正常工作。因此窗口看门狗“触手能及”的范围是有限的,很有必要再配备一个能对全局应用程序进行监控的看门狗,与窗口看门狗形成功能上的互补,为STM32应用程序的运行稳定与可靠性再添一层保险。这就是IWDG的由来。

功能上的差异必然是以硬件结构上的差异来达成的。

IWDG的特性:从本实质上分析,IWDG仍然遵循一般看门狗的结构,及其核心仍应该是一个定时计数电路。其次,窗口看门狗之所以具有局限性,最主要原因是他的驱动时钟来自于APB1总线。IWDG既然被要求用以从全局的角度监控应用程序的运行,则其一定在某种程度上是“脱离”STM32内部时钟总线的。

从STM32的技术参考文档可知,STM32的IWDG具有以下基本特性:

  • 拥有完全自由运行的递减计数器
  • 驱动时钟由独立的RC振荡器提供(可在停止和待机模式下工作)。
  • 看门狗被激活后,在计数器计数至0x000时产生复位。

可以看到,IWDG使用独立的RC振荡器提供时钟驱动,其运行不在依赖于STM32的时钟总线。IWDG的硬件结构如下图:

IWDG位于VDD供电区,使用VDD供给工作所需电源。这意味着即便STM32的ARM CorTex-M3内核停止工作(内核工作于1.8V供电区,停止工作的情况不仅包括内核断电,还包括内核进入停机模式和待机模式),IWDG仍然能够正常工作。综上所述,STM32的IWDG模块在时钟驱动源于供电源上较窗口看门狗进行了改动,达到了与STM32在一定程度上“隔离”的效果,从而能完成其监控全局程序的任务。

实验设计

软件设计(程序设计):

  • 配置RCC、GPIO、EXTI、USART寄存器组。
  • 配置IWDG,预分频为32分频,重载值为349。
  • IWDG没有提供类似窗口看门狗的“早期唤醒中断”的中断源,所以要配置SysTick定时器,产生250ms时间间隔,用以进行周期性地喂狗操作。
  • 配置NVIC,赋予EXIT0较高级的先占优先级,同时赋予SysTick较低的先占优先级。对于IWDG的使用,读者应该关注以下两个要点。

(1).  IWDG的配置流程

为了增加程序的安全与稳定性,STM32的IWDG拥有寄存器读/写保护功能,所以必须按照既定的操作原则才能正确地读/写IWDG地各个寄存器。操作原则如下:

  1. 在设置IWDG的预分频值和重载值之前,必须向IWDG的键寄存器写入0x5555。
  2. 重载IWDG计数值的方法是向键寄存器中写入0xAAAA。
  3. 启用IWDG的方法是向键寄存器中写入0xCCCC。

总结起来就是,初始化IWDG必须以0x5555>>重载计数值>>0xAAAA>>0xCCCC的数据流顺序写入。任何不同于此操作流程的数据写入操作,都将使IWDG回到受保护状态,要重新写入0x5555才能再次对其进行操作。

(2).  IWDG的溢出时间计算

与WWDG类似,假设STM32的内部RC振荡器频率为32kHz(实际上STM32内部RC振荡器的频率并不稳定,依环境因素为30~60kHz不等,官方给出的值为40kHz,此处为方便计算取32kHz),而IWDG分频值为32分频,那么容易得到IWDG的单次计数周期为:P=1*32/32khz=1ms

而程序设置IWDG的初始值为349,因此可知IWDG的溢出时间为(注意从349递减计数至0时发生下溢):T=(349+1)*P=350ms

这就是本小节程序设计中IWDG发生一次溢出的大概时间间隔,应用程序必须以小于这一事件的周期进行喂狗操作,否则将发生IWDG复位事件。

主函数(main.c)

#include"stm32f10x_lib.h"

#include"stdio.h"

void RCC_Configuration(void);

void NVIC_Configuration(void);

void GPIO_Configuration(void);

void EXTI_Configuration(void);

void SysTick_Configuration(void);

void IWDG_Configuration(void);

void USART_Configuration(void);

int main(void)

{

RCC_Configuration();

NVIC_Configuration();

GPIO_Configuration();

EXTI_Configuration();

SysTick_Configuration();

IWDG_Configuration();

USART_Configuration();

if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST)!=RESET)

{

printf("\r\n The STM32 has been reset by IWDG  \r\n");

RCC_ClearFlag();          //清除看门狗复位标志

}

else

{

printf("\r\n The STM32 has been reset by IWDG before \r\n");

SysTick_Configuration();    //设置Systick定时器

IWDG_Configuration();       //设置IWDG

}

while(1);

}

设置系统各部分时钟   RCC_Configuration

void RCC_Configuration(void)

{

ErrorStatus HSEStartUpStatus;      //定义枚举类型变量 HSEStartUpStatus

RCC_DeInit();                     //复位系统时钟设置

RCC_HSEConfig(RCC_HSE_ON);         //开启HSE

HSEStatrtUpStatus=RCC_WaitForHSEStartUp();   //等待HSE起振并稳定

if(HSEStatrtUpStatus==SUCCESS)     //判断HSE是否起振成功,是则进入if()内部

{

RCC_HCLKConfig(RCC_SYSCLK_Div1);   //选择HCLK(AHB)时钟源为SYSCLK分频

RCC_PCLK2Config(RCC_HCLK_Div1);    //选择PCLK2时钟源为HCLK(AHB)1分频

RCC_PCLK1Config(RCC_HCLK_Div2);    //选择PCLK1时钟源为HCLK(AHB)2分频

FLASH_SetLatency(FLASH_Latency_2);  //设置Flash延时周期数为2

FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);   //使能Flash预取缓存

//选择PLL时钟源为 HSE 1 分频,倍频数为9,则PLL=8MHz *9=72MHz

RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);

RCC_PLLCmd(ENABLE);                  //使能PLL

while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET);  //等待PLL输出稳定

RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);    //选择SYSCLK时钟源为PLL

while(RCC_GetSYSCLKSource()!=0x08);      //等待PLL成为SYSCLK时钟源

}

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE);    //打开APB2总线上的GPIOA和USART1时钟

}

设置各GPIO端口功能    GPIO_Configuration

void GPIO_Configuration(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

//设置PA.0为上拉输入(EXTI Line0)

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;

GPIO_Init(GPIOA,&GPIO_InitStructure);

//定义PA.0为外部中断0输入通道(EXIT0)

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);

//设置USART1的Tx脚(PA.9)为第2功能推挽输出功能

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;

GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;

GPIO_Init(GPIOA,&GPIO_InitStructure);

//设置USART1的Rx脚(PA.10)为浮空输入脚

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;

GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;

GPIO_Init(GPIOA,&GPIO_InitStructure);

}

设置EXIT参数    EXIT_Configuration

void EXTI_Configuration(void);

{

//定义初始化结构体EXTI_InitStructure

EXTI_InitTypeDef EXTI_InitStructure;

//设置外部中断0通道(EXIT_Line0)在下降沿时触发中断

EXTI_InitStructure.EXTI_Line=EXTI_Line0;

EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt

EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;

EXTI_InitStructure.EXTI_LineCmd=ENABLE;

EXTI_Init(&EXTI_InitStructure);

}

设置NVIC参数   NVIC_Configuration

void NVIC_Configuration(void)

{

//定义NVIC初始化结构体NVIC_InitStructure

NVIC_InitTypeDef NVIC_InitStructure;

//使用优先级分组2

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

//设置外部中断0通道(EXIT0),0级先占优先级,0级次占优先级

NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQChannel;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;

NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;

NVIC_Init(&NVIC_InitStructure);

//设置SysTick中断为1级先占优先级,0级次占优先级

NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick,1,0);

}

设置Systick定时器,重装载时间为250ms     Systick_Configuration

void Systick_Configuration(void)

{

//选择HCLK/8为Systick时钟源

SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);

//主频为72/8MHZ,配置计数值为9000*250可以得到250ms定时间隔

SysTick_SetReload(9000*250);

SysTick_CounterCmd(SysTick_Counter_Enable);        //启动SysTick计数

SysTick_ITConfig(ENABLE);                          //使能SysTick中断

}

设置IWDG,超时时间为350ms     IWDG_Counfiguration

void IWDG_Counfiguration(void)

{

//使能对寄存器IWDG_PR和IWDG_RLRD的写操作

IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);

//设置IWDG时钟为LSI经32分频,则IWDG计数器时钟=32kHz(LSI)/32=1kHz

IWDG_SetPrescaler(IWDG_Prescaler_32);

IWDG_SetReload(349);          //设置IWDG计数值为349

IWDG_ReloadCounter();         //重载IWDG计数值

IWDG_Enable();                //启动IWDG

}

设置USART1      USART_Configuration

void USART_Configuration(void)

{

USART_InitTypeDef USART_InitStructure;       //定义USART初始化结构体USART_InitStructure

USART_ClockInitTypeDef USART_ClockInitStructure;  //定义USART初始化结构体USART_ClockInitStructure

//波特率为9600bps;8位数据长度,1个停止位,无检验位;禁用硬件流控制;禁止USART时钟;时钟极性低;在第2个边沿捕获数据;最后一位数据的时钟脉冲不从SCLK输出

USART_InitStructure.USART_BaudRate=9600;

USART_InitStructure.USART_WordLength=USART_WordLength_8b;

USART_InitStructure.USART_StopBits=USART_StopBits_1;

USART_InitStructure.USART_Parity=USART_Parity_NO;

USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;

USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;

USART_Init(USART1,&USART_InitStructure);

USART_Cmd(USART1,ENABLE);         //使能USART1

}

将printf函数重定位到USART1                       fputc

int fputc (int ch,FILE*f)

UASRT_SendData(USART1,(u8)ch);

while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);

return ch;

中断服务程序

头文件

#include"stm32f10x_it.h"

#include"stdio.h"

SysTick定时器中断服务函数      SysTickHandler

void SysTickHandler(void)

{

IWDG_ReloadCounter();      //重载IWDG计数器

printf("\r\n The IWDG has been flashed \r\n");

}

外部中断0中断服务函数            EXTI0_IRQHandler

void EXTI0_IRQHandler(void)

{

while(1);

}

注意事项:

  1. IWDG使用的是STM32内部的RC振荡器供给驱动时钟,因此并无所谓“打开IWDG时钟”这类操作。
  2. STM32内部的RC振荡器频率并不稳定在某个值,甚至可以说变动的幅度比较大。因此读者在计算看门狗重装值的时候,请以RC震荡器运行在可达到的最低工作频率的情况计算,并将重装值设置到比所需的计算值稍微大一些为妙。
  3. 默认情况下,即便ARM Cortex-M3内核停止工作,IWDG仍将保持工作。
  4. IWDG复位仍然等同于一次软复位。
  5. IWDG在一次开启之后下次复位之前,不可以再被禁止。建议读者不要在IWDG工作时尝试改变他的工作参数。
  6. 读者应该已经注意到,和WWDG不同的是,IWDG的复位标志位于RCC寄存器组里(而WWDG的复位标志位于自身寄存器组里)。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值