stm32 窗口看门狗[操作寄存器+库函数]

发布者:美好的人生最新更新时间:2017-02-06 来源: eefocus关键字:stm32  窗口看门狗  操作寄存器  库函数 手机看文章 扫描二维码
随时随地手机看文章

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
01137.28
122714.56
245529.12
391058.25

 

本例直接寄存器实现4种测试模式,测试窗口看门狗的复位原理。

  • 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]:为窗口值。

 

代码如下:    (system.h 和 stm32f10x_it.h 等相关代码参照 stm32 直接操作寄存器开发环境配置

User/main.c

#include 	 
#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; 
  
}

User/stm32f10x_it.c

#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;  //清除中断标志位
}

Library/src/wdg.c 和  Library/inc/wdg.h 参见 stm32 独立看门狗[操作寄存器+库函数]

 

在中断函数 stm32f10x_it.c WWDG_IRQChannel()中 必须判断 计数值小于 窗口值之后才可以喂狗,不加此判断直接喂狗会导致复位,原因不详。

 

此中断是在计数器计数到0x40时触发,必然会小于窗口设定值 ,除非是此中断不止在此条件下触发,启动WWDG计数器可能也会导致中断。猜测一下而已 。。。

 

库函数操作

 

main.c

#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

stm32f10x_it.c

#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();
}


关键字:stm32  窗口看门狗  操作寄存器  库函数 引用地址:stm32 窗口看门狗[操作寄存器+库函数]

上一篇:stm32 TIM定时器 PWM脉冲输出[操作寄存器+库函数]
下一篇:stm32 AD模数转换[操作寄存器+库函数]

推荐阅读最新更新时间:2024-03-16 15:32

stm32中的数据类型定义
STM32F10X.H 1 #include core_cm3.h 2 #include system_stm32f10x.h 3 #include stdint.h 4 5 /** @addtogroup Exported_types 6 * @{ 7 */ 8 9 /*! STM32F10x Standard Peripheral Library old types (maintained for legacy purpose) */ 10 typedef int32_t s32; 11 typedef int16_t s16; 12 typedef int8_t s8; 13 14 typed
[单片机]
关于使用STM32 SPI3的一些总结
总结一下spi3的问题,因为spi3的nss口与JTAG有共用引脚,所以配置错误会导致SPI3无法使用。需要注意以下三点就可以了:  1.将PA15配置为普通IO口,GPIO_Mode_Out_PP  2.开启AFIO时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);  3.关闭JTAG功能,使能SWD  GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE) ; 其他的SPI口正常配置,因为板子重启后默认为JTAG模式,虽然在调试时使用了SWD,但PA15依然不是普通的IO口,当把它重新配置时,一定要开启AFIO时钟,
[单片机]
STM32 系统时钟和SysTick定时器
1.STM32的时钟系统 在STM32中,一共有5个时钟源,分别是HSI、HSE、LSI、LSE、PLL (1)HSI是高速内部时钟,RC振荡器,频率为8MHz; (2)HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围是4MHz – 16MHz; (3)LSI是低速内部时钟,RC振荡器,频率为40KHz; (4)LSE是低速外部时钟,接频率为32.768KHz的石英晶体; (5)PLL为锁相环倍频输出,严格的来说并不算一个独立的时钟源,PLL的输入可以接HSI/2、HSE或者HSE/2。倍频可选择为2 – 16倍,但是其输出频率最大不得超过72MHz。 其中,40kHz的LSI供独
[单片机]
基于STM32单片机的盆栽系统设计
一.系统设计 本次盆栽系统的设计使用STM32单片机作为控制中心,通过光敏模块检测光照强度,通过DHT11测量温湿度,通过土壤湿度传感器检测土壤湿度,检测到的数据通过LCD显示屏显示,当土壤湿度低于下限时,继电器控制灌溉,当土壤湿度高于上限时,继电器控制除湿,当温度低于阈值时,继电器控制加热,当光强低于阈值时,继电器控制补光。 图1 系统框图 二.硬件设计 本设计所采用的STM32F103C8T6是以Cortex-3为核心的单片机,它的功能是实现软件的执行,并对外部的器件、模块进行控制。该系统由LCD显示模块,温湿度检测模块,光敏电阻模块,湿度检测模块,继电器模块组成。 图2 硬件电路 三.软件设计 系统的软件实现过程中首
[单片机]
基于<font color='red'>STM32</font>单片机的盆栽系统设计
利用STM32定时器的PWM输出功能,直接获取PWM波形
本实验向大家展示如何输出占空比固定的PWM波形。 1.工程的建立: 2.主函数代码: 3.pwm_output.c代码: 4.output.h代码: 5.结果: 6.结果显示不出来的请看上几节的文章,已解决。
[单片机]
STM32的烧录文件.bat 解析
@echo off setlocal :: Be sure to install the ST-LINK drivers and Utility application for Windows :: Location of ST-LINK_CLI.exe, which is part of the Utility application :: set STLINKUTIL= C:\Program Files (x86)\STMicroelectronics\STM32 ST-LINK Utility\ST-LINK Utility\ST-LINK_CLI.exe set STLINKUTIL= C:\Program Files (
[单片机]
浅析基于STM32的除以0运算话题
有人使用STM32G4系列芯片开发产品。他发现程序中如果遇到除以0的操作时,会跑进出错异常中断而影响程序运行。他想知道能否通过设置,即使发生除以0操作也不让程序跑进异常中断,并期望此时的除法运行结果【也就是商】直接等于当前变量类型所支持的最大值,比如,若被除数为16位变量,则经过该除以零操作后直接为其赋值为0xffff。【实际应用中客户的需求往往也是五彩斑斓的。^_^】 事实上是否可以如该STM32用户所愿呢?我们不妨一起看看。 首先,这个问题不属于STM32外设相关的,而是内核相关的。客户选用的是Cortex M4的内核STM32芯片,那我们就从M4内核手册中寻找相关内容。 我们通过查看ARM M4的内核手册,可以看
[单片机]
浅析基于<font color='red'>STM32</font>的除以0运算话题
详解STM32单片机堆栈
学习STM32单片机的时候,总是能遇到“堆栈”这个概念。分享本文,希望对你理解堆栈有帮助。 对于了解一点汇编编程的人,就可以知道,堆栈是内存中一段连续的存储区域,用来保存一些临时数据。堆栈操作由PUSH、POP两条指令来完成。而程序内存可以分为几个区: 栈区(stack) 堆区(Heap) 全局区(static) 文字常亮区程序代码区 程序编译之后,全局变量,静态变量已经分配好内存空间,在函数运行时,程序需要为局部变量分配栈空间,当中断来时,也需要将函数指针入栈,保护现场,以便于中断处理完之后再回到之前执行的函数。 栈是从高到低分配,堆是从低到高分配。 普通单片机与STM32单片机中堆栈的区别 普通单片机启动时,不需要用b
[单片机]
详解<font color='red'>STM32</font>单片机堆栈
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved