实验现象:
这是基于窗口看门狗的实验,刚开始初始化时LED2闪了一下,后来就保持亮着,而LED1却不断的在闪烁,这是因为中断函数运行的缘故。
实验平台:
基于STM32F103C8T6的彩屏开发板
实验步骤:
1)使能WWDG 时钟
WWDG 不同于IWDG,IWDG 有自己独立的40Khz 时钟,不存在使能问题。而WWDG
使用的是PCLK1 的时钟,需要先使能时钟。
2)设置WWDG_CFR 和WWDG_CR 两个寄存器
在时钟使能完后,我们设置 WWDG 的CFR 和CR 两个寄存器,对WWDG 进行配置。包
括使能窗口看门狗、开启中断、设置计数器的初始值、设置窗口值并设置分频数WDGTB 等。
3)开启WWDG 中断并分组
在设置完了 WWDG 后,需要配置该中断的分组及使能。这点通过我们之前所编写的
MY_NVIC_Init 函数实现就可以了。
4)编写中断服务函数
在最后,还是要编写窗口看门狗的中断服务函数,通过该函数来喂狗,喂狗要快,否则当
窗口看门狗计数器值减到0X3F 的时候,就会引起软复位了。在终端服务函数里面也要将状态
寄存器的EWIF 位清空。
实验代码:
wwdg.h
#ifndef WWDG_H
#define WWDG_H
void WWDG_Init(u8,u8,u8);//声明看门狗的初始化函数
void WWDG_Reset(void);//重新给递减计数器赋值
#endif
wwdg.c
#include"common.h"
#include"wwdg.h"
#include"led.h"
//tr :T[6:0],用于存储计数器的值
//wr :W[6:0],用于存储窗口值
//fprer:窗口看门狗的实际设置
u8 WWDG_CNT=0x7f;
void WWDG_Init(u8 tr ,u8 wr,u8 fprer )
{
RCC->APB1ENR|=1<<11; //开启窗口看门狗的时钟
WWDG_CNT=tr&WWDG_CNT; //主要是为了防止用户写错数据造成巨大偏差
WWDG->CFR|=fprer<<7; //预分频时基设置
WWDG->CFR|=1<<9; //开启提前唤醒中断
WWDG->CFR&=0xff8; //保证上面两个设置的正确性
WWDG->CFR|=wr; //给递减计数器赋初值
WWDG->CR|=WWDG_CNT; //给窗口寄存器赋值
WWDG->CR|=1<<7; //启用看门狗
MY_NVIC_Init(2,3,WWDG_IRQChannel,2);//设置中断的分组和优先级
}
//重新给递减计数器赋值
void WWDG_Reset(void)
{
WWDG->CR=0x7f;
}
//中断服务函数
void WWDG_IRQHandler(void)
{
u8 tr,wr;
tr=(WWDG->CR&0x7f);//读取窗口寄存器的值
wr=(WWDG->CFR&0x7f);//读取递减计数器的值
if(tr<wr)//当递减计数器的值小于窗口的才能给递减计数器重新复制,不然会复位的
WWDG_Reset();
WWDG->SR=0x0; //去除提前唤醒中断标志
LED1=!LED1; //LED反向
}
第一个函数void WWDG_Init(u8 tr,u8 wr,u8 fprer)用来
设置WWDG的初始化值。包括看门狗计数器的值和看门狗比较值等。注意到这里有个全局变量WWDG_CNT,该变量用来保存最初设置WWDG_CR计数器的值。在后续的中断服务函数里面,就又把该数值放回到WWDG_CR上。
WWDG_Set_Counter 函数比较简单,就是用来复位窗口看门狗的计数器值的。该函数很简
单。
最后中断服务函数里面,一定要先比较窗口计数器的值是否小于看门狗的窗口值,如果不
小于,则不要修改,如果小于,才能进行修改。我们通过LED1 不停的取反,来观测中断服务函
数的执行了状况。我们再把这几个函数名加入到头函数里面去,以方便其他文件调用。
主函数
#include<stm32f10x_lib.h>
#include"common.h"
#include"led.h"
#include"key.h"
#include"wwdg.h"
int main(void)
{
Stm32_Clock_Init(9); //系统时钟设置
delay_init(72); //延时初始化
LED_Init(); //LED初始化
KEY_Init(); //按键的初始化
WWDG_Init(0x7f,0x5f,3);
LED2=0;
delay_ms(300);
while(1)
{
LED2=1;
}
}
|