stm32 窗口看门狗[操作寄存器+库函数]
- 独立看门狗是限制喂狗时间在0-x内,x由你的相关寄存器决定。喂狗的时间不能过晚。
- 窗口看门狗,所以称之为窗口就是因为其喂狗时间是一个有上下限的范围内,你可以通过设定相关寄存器,设定其上限时间和下限时间。喂狗的时间不能过早也不能过晚。窗口看门狗的上窗口就是配置寄存器WWDG->CFR里设定的W[6:0],下窗口是固定的0x40;当窗口看门狗的计数器在上窗口值之外,或是低于下窗口值都会产生复位。上窗口的值可以只有设定,7位二进制数最大只可以设定为127,最小又必须大于下窗口的0x40,所以其取值范围为40~127;窗口看门狗的核心是一个7位的递减计数器,只有当计数器的值在窗口范围内在可以执行喂狗操作,即更新此计数器的值,否则将导致复位操作。 在配置寄存器WWDG->CFR中可以为此计数器设定时钟分频系数,确定这个计数器可以定时的时间范围,从而确定窗口的时间范围。窗口看门狗的时钟来自于PCLK1,在时钟配置中,其频率为外部时钟经倍频器后的二分频时钟,即为36MHz,根据手册可以知道其定时时间计算方法:上窗口时间 T_min = 4096 (2^WDGTB)(WWDG_CR[6:0] - WWDG_CFR[6:0])/36 (us)下窗口时间 T_max = 4096 (2^WDGTB)(WWDG_CR[6:0] - 0x40)/36 (us)
36Mhz下相关窗口看门狗的喂狗时间范围:
WDGTB(计数器分频值) | 最早喂狗时间/us | 最晚喂狗时间/ms |
---|---|---|
0 | 113 | 7.28 |
1 | 227 | 14.56 |
2 | 455 | 29.12 |
3 | 910 | 58.25 |
- MODE_1 0 // 在30ms时喂狗,在窗口范围内喂狗,LED灯闪烁
- MODE_2 0 // 在10ms时喂狗,在窗口范围外导致复位 ,LED灯常亮
- MODE_3 0 // 在100ms时喂狗,在窗口范围外喂狗导致复位
MODE_4 1 // 主函数不执行喂狗,开启提前唤醒中断,在WWDG中断函数中喂狗
库函数实现在提前唤醒中断中,喂狗操作,PA4口LED正常闪烁。当外部中断发生(按下PA0按键),长时间不喂狗,引发窗口看门狗复位。直接操作寄存器相关寄存器如下:控制寄存器WWDG->CR: 低8位有效。第8位为WDGA,看门狗激活位。低7位[6:0]为看门狗计数器的计数值。配置寄存器WWDG->CFR:低十位有效。第10位为EWI:提醒唤起中断。 此位置1,当计数器值到达0x40时,将产生中断。第8,9位WDGTB:为计数器分频系数设置为:00: CK计时器时钟(PCLK1除以4096)除以1 01: CK计时器时钟(PCLK1除以4096)除以2
- 10: CK计时器时钟(PCLK1除以4096)除以4 11: CK计时器时钟(PCLK1除以4096)除以8低7位[6:0]:为窗口值。User/main.c
#include <stm32f10x_lib.h>
#include “system.h”
#include “wdg.h”
#define LED1 PAout(4)
//选择测试模式,一次置1一个测试
#define MODE_1 0 // 在30ms时喂狗,在窗口范围内喂狗
#define MODE_2 0 // 在10ms时喂狗,在窗口范围外导致复位
#define MODE_3 0 // 在100ms时喂狗,在窗口范围外喂狗导致复位
#define MODE_4 1 // 主函数不执行喂狗,开启提前唤醒中断,在WWDG中断函数中喂狗
void Gpio_Init(void);
int main(void)
{
Rcc_Init(9); //系统时钟设置
Wwdg_Init(127,100,3); //设定为只能在24.57ms~58.25ms内喂狗,时间计算方法参见wdg.c Wwdg_Init();
#if MODE_4
Nvic_Init(0,0,WWDG_IRQChannel,0); //设置抢占优先级为0,响应优先级为0,中断分组为0
#endif
Gpio_Init();
while(1){
LED1 = !LED1;
#if MODE_1
delay(30000); //延时30ms后喂狗,LED闪烁
Wwdg_Feed(); //喂狗
#elif MODE_2
delay(10000); //延时10ms,引发窗口看门狗复位,LED不闪烁
Wwdg_Feed(); //喂狗
#elif MODE_3
delay(100000); //延时100ms,引发窗口看门狗复位,LED不闪烁
Wwdg_Feed(); //喂狗
#elif MODE_4
delay(30000); //延时30ms后在中断中喂狗,LED闪烁
#endif
}
}
void Gpio_Init(void)
{
RCC->APB2ENR|=1<<2; //使能PORTA时钟
GPIOA->CRL&=0x0000FFFF; // PA0~3设置为浮空输入,PA4~7设置为推挽输出
GPIOA->CRL|=0x33334444;
}
#include “stm32f10x_it.h”
extern void Wwdg_Feed(void);
void WWDG_IRQHandler(void)
{
//必须判断 计数值小于 窗口值之后才可以喂狗,不加此判断直接喂狗会导致复位,原因不详
if((WWDG->CR&0x7F) < (WWDG -> CFR&0x7F)){
Wwdg_Feed();
}
WWDG->SR = 0x00; //清除中断标志位
}
#include “stm32f10x.h”
#include “stdio.h”
#define PRINTF_ON 1
void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void USART_Configuration(void);
void WWDG_Configuration(void);
void EXTI_Configuration(void);
int main(void)
{
RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
USART_Configuration();
EXTI_Configuration();
WWDG_Configuration();
while(1){
if(RCC_GetFlagStatus(RCC_FLAG_WWDGRST) != RESET)
{
printf("\r\n The Stm32 has been reset by WWDG .\r\n");
RCC_ClearFlag();
}
}
}
void EXTI_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
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);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA , &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOA , &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA , &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA , &GPIO_InitStructure);
}
void WWDG_Configuration(void)
{
WWDG_SetPrescaler(WWDG_Prescaler_8);
WWDG_Enable(0x7F);
WWDG_ClearFlag();
WWDG_EnableIT();
}
void RCC_Configuration(void)
{
/ 定义枚举类型变量 HSEStartUpStatus /
ErrorStatus HSEStartUpStatus;
/* 复位系统时钟设置*/
RCC_DeInit();
/* 开启HSE*/
RCC_HSEConfig(RCC_HSE_ON);
/* 等待HSE起振并稳定*/
HSEStartUpStatus = RCC_WaitForHSEStartUp();
/* 判断HSE起是否振成功,是则进入if()内部 */
if(HSEStartUpStatus == SUCCESS)
{
/* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */
RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */
RCC_PCLK2Config(RCC_HCLK_Div1);
/* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */
RCC_PCLK1Config(RCC_HCLK_Div2);
/* 设置FLASH延时周期数为2 */
FLASH_SetLatency(FLASH_Latency_2);
/* 使能FLASH预取缓存 */
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
/* 使能PLL */
RCC_PLLCmd(ENABLE);
/* 等待PLL输出稳定 */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
/* 选择SYSCLK时钟源为PLL */
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* 等待PLL成为SYSCLK时钟源 */
while(RCC_GetSYSCLKSource() != 0x08);
}
/* 打开APB2总线上的GPIOA时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP|RCC_APB1Periph_WWDG, ENABLE);
}
void USART_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
USART_ClockInitTypeDef USART_ClockInitStructure;
USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;
USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;
USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;
USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;
USART_ClockInit(USART1 , &USART_ClockInitStructure);
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);
}
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
#if PRINTF_ON
int fputc(int ch,FILE *f)
{
USART_SendData(USART1,(u8) ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);
return ch;
}
#endif
#include “stm32f10x_it.h”
#include “stdio.h”
extern vu32 Display;
void WWDG_IRQHandler(void)
{
WWDG_SetCounter(0x7F);
GPIO_WriteBit(GPIOA,GPIO_Pin_4,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_4)));
WWDG_ClearFlag();
}