zoukankan      html  css  js  c++  java
  • STM32F4 窗口看门狗(WWDG)

    概述

      为了方便阅读,可以先阅读本人《STM32F407 独立看门狗 (IWDG)》

    https://www.cnblogs.com/ding-ding-light/p/14472107.html
    

      与独立看门狗不同的是,窗口看门狗没有独立的时钟源,它是挂载在APB1下的一个片上外设,与独立看门狗类似,窗口看门狗也需要进行“喂狗”,只不过喂狗的时机被设置成计数器值需要在一个范围之内喂狗,不在这个范围之内喂狗或者低于这个范围的下限系统将发生复位,而这个范围便是上限值和下限值,其中下限值被设定死了是0x40,上限值由用户设置(最大为127)。

    寄存器


      以上为窗口看门狗的功能框图,首先来自其中PCLK1时钟被WDG分频器分频后进入窗口看门狗;
      寄存器WWDG_CR为看门狗计数器的值每隔一个时钟周期递减一次;
      寄存器WWDG_CFR保存了预先设置好的上限值,当当前计数器的值T6:0>W6:0时,比较器输出为1,当这个时候进行写寄存器WWDG_CR,接下来的与门会输出1,在输入到或门也将输出1,便会触发复位,前提是寄存器WWDG_CR的WDGA位被置1表示允许窗口看门狗复位发生,这也对应了我之前所说的,当不在上限值和下限值这个范围之内喂狗便会触发复位;
      上图中可以看出另外发生窗口看门狗复位的一种情况是T6为0时,也就是当前计数值已经小于0x40了,前提也是WWDG_CR的WDGA位被置1;
      还有一个寄存器WWDG_CFR的EWI用于选择是否触发中断,当计数器值被减到正好0x40时,可以在中断函数中便可以选择设置一个喂狗的标志位,在主函数中进行喂狗,具体原因独立看门狗已经讲过了,不在赘述。还有一个WDGTB位时用于选择分频器。

    窗口看门狗初始化

      通过上面的讲解,我相信初始化过程已经很明了了,有如下步骤:
        1.打开WWDG的硬件时钟;
        2.选择分频器;
        3.设置窗口看门狗的上限值;
        4.配置计数器的值;
        5.NVIC配置;
        6.使能窗口看门狗中断。

    实验程序

    #include "stm32f4xx.h"
    #include <stdio.h>
    
    static GPIO_InitTypeDef 		GPIO_InitStructure;
    static NVIC_InitTypeDef   		NVIC_InitStructure;
    static USART_InitTypeDef   		USART_InitStructure;
    
    volatile uint8_t		wwdg_event = 0;
    
    #pragma import(__use_no_semihosting_swi)
    
    struct __FILE { int handle; /* Add whatever you need here */ };
    FILE __stdout;
    FILE __stdin;
    
    int fputc(int ch, FILE *f) 
    {
    	USART_SendData(USART1,ch);
    		
    	//等待数据发送成功
    	while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
    	return ch;
    }
    
    void _sys_exit(int return_code) {
    
    }
    
    void delay_us(uint32_t n)
    {
    	SysTick->CTRL = 0; // Disable SysTick
    	SysTick->LOAD = n*168-1; // 计数值 
    	SysTick->VAL  = 0; // Clear current value as well as count flag
    	SysTick->CTRL = 5; // Enable SysTick timer with processor clock(168MHz)
    	while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set
    	SysTick->CTRL = 0; // Disable SysTick	
    }
    
    void delay_ms(uint32_t n)
    {
    	while(n--)
    	{
    		SysTick->CTRL = 0; // Disable SysTick
    		SysTick->LOAD = 168000-1; // 计数值 Count from n to 0 (168000-1+1=168000 cycles)
    		SysTick->VAL = 0; // Clear current value as well as count flag
    		SysTick->CTRL = 5; // Enable SysTick timer with processor clock(168MHz)
    		while ((SysTick->CTRL & 0x00010000)==0);// Wait until count flag is set
    		SysTick->CTRL = 0; // Disable SysTick	
    	}
    }
    
    void usart1_init(uint32_t baud)
    {
    	//使能端口A硬件时钟
    	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
    	//使能串口1硬件时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
    	//配置PA9、PA10为复用功能引脚
    	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9|GPIO_Pin_10;
    	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
    	GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed;
    	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;	
    	GPIO_Init(GPIOA,&GPIO_InitStructure);
    	//将PA9、PA10连接到USART1的硬件
    	GPIO_PinAFConfig(GPIOA, GPIO_PinSource9,  GPIO_AF_USART1);
    	GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
    	//配置USART1的相关参数:波特率、数据位、校验位
    	USART_InitStructure.USART_BaudRate = baud;//波特率
    	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据位
    	USART_InitStructure.USART_StopBits = USART_StopBits_1;//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);
    	//使能串口1工作
    	USART_Cmd(USART1,ENABLE);
    }
    
    void usart1_send_str(char *str)
    {
    
    	char *p = str;
    	
    	while(*p!='')
    	{
    		USART_SendData(USART1,*p);
    		
    		p++;
    		//等待数据发送成功
    		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
    	}
    }
    
    void WWDG_NVICDisable(void)
    {
    	NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;
    	NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
    	NVIC_Init(&NVIC_InitStructure);
    }
    
    void WWDG_NVICEnable(void)
    {
    	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);
    }
    
    void wwdg_init(void)
    {
    	//打开WWDG的硬件时钟
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
    	//配置预分频值
    	//窗口看门狗的硬件时钟频率=(42MHz/4096)/8=1281Hz
    	//所以窗口看门狗的硬件时钟周期=1/1281
    	//到达时间窗口需要:1/1281*(127-80)=37毫秒
    	WWDG_SetPrescaler(WWDG_Prescaler_8);
    	//窗口的上限值
    	WWDG_SetWindowValue(80);
    	//配置它的计数值为127看,并使能窗口看门狗工作
    	WWDG_Enable(127);
    	WWDG_NVICEnable();
    	//使能提前唤醒中断
    	WWDG_EnableIT();
    }
    
    int main(void)
    {
    	//串口1初始化波特率为115200bps
    	usart1_init(115200);
    	delay_ms(500);
    	//发送数据
    	usart1_send_str("This is wwdg test
    ");
    	//检测是否由窗口看门狗导致的复位
    	if (RCC_GetFlagStatus(RCC_FLAG_WWDGRST) == SET)
    	{
    		printf("wwdg reset cpu
    ");
    	}
    	//清空标志位
    	RCC_ClearFlag();
    	//窗口看门狗的初始化
    	wwdg_init();
    	while(1)
    	{
    		//延时40ms已经到达窗口时间
    		delay_ms(40);
    		//该变量在中断函数中被改变,在这里需要使用到时,需要关闭中断,使该变量进行临界区
    		WWDG_NVICDisable();  
    		if(1 == wwdg_event)
    		{
    			//刷新计数值(将计数值恢复为127) == 喂狗操作
    			WWDG_SetCounter(127);	
    		}
    		WWDG_NVICEnable();
    	}
    }
    
    void WWDG_IRQHandler(void)
    {
    	if(WWDG_GetFlagStatus()==SET)
    	{
    		wwdg_event = 1;
    		//清空提前唤醒中断标志位
    		WWDG_ClearFlag();
    	}
    }
    

    总结

      1.注意寄存器WWDG_CFR的中断位在置1后,此中断只有在复位后才由硬件清零,所以要关闭中断时只能在NVIC中关闭;
      2.注意时间的计算;

    相关下载

    链接:https://pan.baidu.com/s/13qhRg5jOU4eqtZRiMOF9jg 
    提取码:czd2 
    复制这段内容后打开百度网盘手机App,操作更方便哦
    
  • 相关阅读:
    【作业】Python面向对象
    Python使用使用第三方源(国内源:豆瓣)下载包文件 超快!!!
    【案例】Python
    【个人笔记】Python
    定义函数相关内容
    列表,for循环相关.
    while应用和函数学习
    斗地主发牌器
    字符串索引切片.
    随机生成20以内加减法,5次答题并统计正确和错误题数
  • 原文地址:https://www.cnblogs.com/ding-ding-light/p/14472285.html
Copyright © 2011-2022 走看看