大家好,又见面了,我是你们的朋友全栈君。
咕咕咕之后想更会儿stm32哈哈哈,但是其实是之前自己写的笔记,想着以后就写在一起吧,我自己也更好去找到自己写的玩意~毕竟总所周知,博客都是写给自己的。
(虽然好像现在自己都看不懂了我的天哪)
一.什么是看门狗
在stm32中,我们会学到独立看门狗和窗口看门狗的实验。第一眼肯定是一脸懵逼啊,啥是看门狗啊?
看门狗在日常生活中,大概的印象就是,起到一个保证安全,防止外来人员搞事的作用。
stm32中的看门狗也起着差不多的意思:
看门狗就是起到一个监督单片机是否正在正常运行的作用。如果程序运行异常(跑飞),那么让系统复位,程序重新执行。
看一下百科解释:
在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞,而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统的陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测单片机程序运行状态的模块或者芯片,俗称“看门狗”(watchdog)
那么看门狗怎么去实现这些操作呢?再讨论这个之前,我们先来看看stm32中的看门狗有哪些?
1.两种看门狗
STM32F10xxx内置两个看门狗,提供了更高的安全性、时间的精确性和使用的灵活性。两个看门狗设备(独立看门狗和窗口看门狗)可用来检测和解决由软件错误引起的故障;当计数器达到给定的超时值时,触发一个中断(仅适用于窗口型看门狗)或产生系统复位。
独立看门狗(IWDG):
独立看门狗由专用的低速时钟(LSI)驱动,即使主时钟发生故障它也仍然有效。
IWDG最适合应用于那些需要看门狗作为一个在主程序之外,能够完全独立工作,并且对时间精度要求较低的场合。
窗口看门狗(WWDG):
窗口看门狗由从APB1时钟分频后得到的时钟驱动,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的操作。
WWDG最适合那些要求看门狗在精确计时窗口起作用的应用程序。
但是单独看这个确实。。。有点迷,就有点印象哈。 但是大概应该也对看门狗有了一点概念,至少你知道了有两种看门狗。 那么我们现在详细来介绍一下独立看门狗(窗口看门狗留在下一个主题)
2.独立看门狗
之前看独立看门狗的介绍,我们知道他由一个专门的时钟驱动
这里给出更详细的介绍一下:
STM32 的独立看门狗由内部专门的 40Khz 低速时钟驱动,即使主时钟发生故障,它也仍然有效。这里需要注意独立看门狗的时钟是一个内部 RC 时钟,所以并不是准确的 40Khz,而是在 30~60Khz 之间的一个可变化的时钟,只是我们在估算的时候,以 40Khz 的频率来计算,看门狗对时间的要求不是很精确,所以,时钟有些偏差,都是可以接受的。
我们这里可以理解为:他在主程序之外工作,可以监视主程序是否正常运行。
ok,那么他是怎么工作的?
先简单一点:
独立看门狗可以先设置一个时间(比如1s),如果超过这个时间,那么就代表主程序出了异常,然后让系统复位,程序重新执行。–在这里这个时间的流逝我们理解成一个倒计时
但是很多时候主程序本身就是一个死循环–肯定运行不止1s啊
于是我们需要在主程序之中重置这个时间(倒计时重新开始),如果主程序出现了问题—那么倒计时无法重置,但是我们的看门狗任然在运行,最终超过时间,看门狗让系统复位,程序重新执行。
我觉得我大概是理解了。。。
那么怎么去开启看门狗,又怎么去重置时间呢?
身为单片机—那只能用相关的寄存器去操作了
二.独立看门狗相关寄存器
咱先不去分析单独的寄存器啊,先去直接上框图:
先总体把握一下:这里我觉得官方说的就很好:
在键寄存器(IWDG_KR)中写入0xCCCC,开始启用独立看门狗;此时计数器开始从其复位值0xFFF递减计数。当计数器计数到末尾0x000时,会产生一个复位信号(IWDG_RESET)。 无论何时,只要在键寄存器IWDG_KR中写入0xAAAA, IWDG_RLR中的值就会被重新加载到计数器,从而避免产生看门狗复位 。
其实这里也就是看门狗原理的实现,倒计时就是计数器计数到末尾的时间
并且应该注意一下的是–
IWDG_PR和IWDG_RLR寄 存 器 具 有 写 保 护 功 能 。
要 修 改 这 两 个 寄 存 器 的 值 , 必 须 先 向IWDG_KR寄存器中写入0x5555。
以不同的值写入这个寄存器将会打乱操作顺序,寄存器将重新被保护。
重装载操作(即写入0xAAAA)也会启动写保护功能。
那先看一下键寄存器:
1.键寄存器(IWDG_KR)
但是我们会发现键寄存器其实只是写这三个值–那怎么自己设置时间呢?
所以主要看另外两个寄存器了–IWDG_PR,IWDG_RLR
2.设置倒计时的两个寄存器–**IWDG_PR,**IWDG_RLR
先看图吧
ok,重点都标出来了,但是好像看了跟没看一样
再结合一下公式:
*Tout=(4*2^prer)rlr / 40 ms
(其中prer是IWDG_PR寄存器2进制化为十进制的值,rlr就是IWDG_RLR中的值)
Tout就是看门狗每次的倒计时T
公式的推导参考:https://blog.csdn.net/qq_37957854/article/details/105644138
所以通过对两个寄存器写入,我们就可以设置倒计时了—不要忘了写入之前的操作
还有一个寄存器来着。。这个就看一下就行:
3.状态寄存器(IWDG_SR)
状态寄存器指示预分频值和递减计数器是否正在被更新。
疑问:这个寄存器需要我们自己操作吗?
三.看门狗相关库函数讲解
1.看门狗相关库函数
代码语言:javascript复制void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);
//取消写保护:0x5555使能
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler);
//设置预分频系数:写PR
void IWDG_SetReload(uint16_t Reload);
//设置重装载值:写RLR
void IWDG_ReloadCounter(void);
//喂狗:写0xAAAA到KR
void IWDG_Enable(void);
//使能看门狗:写0xCCCC到KR
FlagStatus IWDG_GetFlagStatus(uint16_t IWDG_FLAG);
//状态:重装载/预分频 更新
大概有些印象就行
几乎传入的参数也全都是具体的数值–分别就是设置那几个寄存器的值
我们现在直接看实验,首先是实验的目的:
2.实验目的
我们会在main.c函数中创建主程序:
即开始实验后,先延迟一会,然后让一个LED亮起。
并在死循环中设置–如果按下按键,那么喂狗。
一般情况下应该就是直接喂狗,这里是为了检验看门狗,就显得很不符合常理
如果不按下按键,那么就不会喂狗,也就是说—程序会一直重启,LED呈现闪烁的效果
如果按时按下按键,程序开始喂狗,那么程序不会重启,LED灯常亮
3.开始写代码(源码分析)–运行看门狗步骤
ps:这里不分析在哪个文件,直接分析函数和代码
首先还是得
启动看门狗(初始化)
代码语言:javascript复制void IWDG_Init(u8 prer,u16 rlr)
{
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //使能对寄存器IWDG_PR和IWDG_RLR的写操作
IWDG_SetPrescaler(prer); //设置IWDG预分频值:设置IWDG预分频值为64
IWDG_SetReload(rlr); //设置IWDG重装载值
IWDG_ReloadCounter(); //按照IWDG重装载寄存器的值重装载IWDG计数器
IWDG_Enable(); //使能IWDG
}
首先就是这个init函数的两个参数,表明自己没有设置rlr和prer,
要我们在初始化的时候自己设置**(自己设置倒计时)**
主体上:
-
- 先解除对两个寄存器的写操作,
- 然后再分别设置寄存器,
-
- 并重新加载一遍两个寄存器—这里的代码是 *IWDG_ReloadCounter();* (这里可以留意一下吧)
- 最后让看门狗开始执行。
然后
在main函数里面
代码语言:javascript复制 int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
uart_init(9600); //串口初始化为9600
LED_Init(); //初始化与LED连接的硬件接口
KEY_Init(); //按键初始化
delay_ms(300); //让人看得到灭
IWDG_Init(4,625); //与分频数为64,重载值为625,溢出时间为1s
LED0=0; //点亮LED0
while(1)
{
if(KEY_Scan(0)==WKUP_PRES)IWDG_ReloadCounter(); //如果WK_UP按下,则喂狗
delay_ms(10);
};
}
就两个操作和看门狗有关
第10行,引用初始化函数 并引入两个需要的数值— 套公式(寄存器的文章里面)
第14行 喂狗
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/145930.html原文链接:https://javaforall.cn