【STM32F103】WDG看门狗

news2024/11/19 9:26:44

本系列在之前介绍时钟树的文章中有稍微提一下看门狗WDG(Watch Door Dog)。

简单来说,可以当成是一个计数器,一旦这个计数器溢出则单片机复位。因为我们需要每隔一段时间就把这个计数器的值清零(喂狗)。

IWDG独立看门狗

看门狗也是有种类的,分为独立看门狗和窗口看门狗,区别就在于喂狗的时机。独立看门狗比较随意,只要不让计数器溢出即可,至于什么时候喂的狗,这种小事无关紧要。

而窗口看门狗对喂狗的时机有要求,喂早不行,喂晚也不行,也就是比较精确。

我们先看看框图,了解一下独立看门狗的硬件结构。

看得出来跟我们的计数器还是很像的,都有预分频器,重装载寄存器,以及一个计数器,这边看得到这个计数器是递减计数器,所以我们可以知道跟计数器不一样的是,独立看门狗的计数模式是向下计数模式,且我们无法更改。

另外还需要注意的是各个寄存器的位数,预分频器是八位,重装载寄存器和计数器是12位。

并且从左边可以看得出来,提供给独立看门狗的时钟源是LSI,40KHz的,这一点我们在时钟树中也可以得到验证。

综上可以计算出一次看门狗最多可以看多久的门:(1s/40k)*(2^8)*(2^12)=26.2144s

从下面官方手册给出的例子也可以看出上面的计算是正确的。

差不对有独立看门狗有了基本的认知之后,我们来依次看看寄存器。

键寄存器IWDG_KR

这是一个只写寄存器,从上面的描述我们看得出,这个寄存器算是一个总控制寄存器,我们“喂狗”的操作实际上就是在这个寄存器写入0xAAAA。

写入0x5555后允许访问两个寄存器,我们不知道那是什么寄存器没关系,先稍微记下,后面会接着介绍。

写入0xCCCC则启动看门狗工作。

预分频器寄存器IWDG_PR

IWDG_PR就是预分频寄存器,所以我们要写入预分频寄存器,就要在键寄存器中写入0x5555。

上面框图中说预分频器是8位的,但是我们这个预分频寄存器却是32位的,而且能用的只有3位。

小伙伴们先不要迷糊,我们看看官方手册中对于预分频寄存器的描述就明了了,预分频器的值并不是我们随便指定一个8位数字的,而是通过可写入的3位去指定预分频因子,从而去修改预分频器的值,因此可以指定的预分频器的值就是上面列出的4,8,6,32,64,128,256。

还有一个要求是需要IWDG_SR寄存器的PVU位为0时才能读出准确的值。

重装载寄存器IWDG_RLR

重装载寄存器比较好理解了,就是直接写入要写入的值就行了。

当我们给键寄存器写入0xAAAA,也就是喂狗的时候,重装载寄存器会把里面的值写到计数器里。

除了要给键寄存器写入0x5555允许访问这个重装载寄存器之外,还有一个要求是需要IWDG_SR寄存器的RVU位为0时才能读出准确的值。

状态寄存器IWDG_SR

这个寄存器一共能用的就两个位,用处分别在前两个寄存器中说了,相当于是使能位。只有这两个位置0之后,上面的预分频寄存器和重装载寄存器才能正确读出值。

固件库函数

了解了独立看门狗的相关寄存器之后,我们也就大致知道我们需要做什么了。

接下来看看涉及到独立看门狗的固件库函数。

这是官方手册中给出的表格,我们实操的时候就按照这个顺序去配置即可。

IWDG_WriteAccessCmd

这个函数就是使能或者是使能IWDG_PR和IWDG_RLR两个寄存器的,根据上面截图中的代码我们也能够看得出,这个函数实际上就是写IWDG_SR这个寄存器的,跟我们上面所述的也符合。

IWDG_SetPrescaler

这个函数是用来设置预分频器的,我们只能根据提供的几种分频因子去设置。

IWDG_SetReload

这个函数设置重装载寄存器,但是没有什么限制,只需要满足填入的数字是在12位的范围内即可。

IWDG_Enable

使能独立看门狗,不需要参数。

IWDG_ReloadCounter

喂狗,实际上就是把重装载寄存器的值写到计数器里。

实验代码

接下来我们就实际地演示一下独立看门狗应该如何使用。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    GPIO_InitTypeDef itd;
    itd.GPIO_Mode=GPIO_Mode_Out_PP;                  
    itd.GPIO_Pin=GPIO_Pin_0;   
    itd.GPIO_Speed=GPIO_Speed_2MHz;                
    GPIO_Init(GPIOA,&itd);
    GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);    //灭灯
    Delay_ms(3000);
    
    GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);  //亮灯    如果LED时亮时灭则是触发了看门狗复位
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
    IWDG_SetPrescaler(IWDG_Prescaler_256);
    IWDG_SetReload(155);    //1s ≈ (1/40000)*256*(155+1)    看门狗喂狗时间定时1s以内
    IWDG_Enable();
    IWDG_ReloadCounter();
    
    while(1){
        Delay_ms(800);          //每0.8s喂狗一次.
        IWDG_ReloadCounter();
    }
    
}

上面代码中我设置了一个GPIO口去触发LED,一开始先灭LED灯三秒,然后点亮。

接下来触发看门狗为1s之内喂一次狗。在主循环函数里每0.8秒喂一次狗。

那么如果是触发了看门狗复位,则LED会先灭三秒,后亮,当触发看门狗复位时程序从头执行,LED再次灭三秒,然后重复上述步骤。

若是不会触发看门狗复位,那么LED灭三秒之后则是常亮不灭。

测试之后,在我这里的现象是当主循环函数中的延时函数延时950毫秒时,看门狗仍是不复位。

但是当延时函数延时955毫秒时,则看门狗开始复位,也就是说哪怕在我们的程序里看来喂狗的时间不超过设置的1秒,但是看门狗仍然会复位。

得出的结论就是独立看门狗的精度不够高,仅能帮助我们处理时间精度不高的问题。

WWDG窗口看门狗

我们照例是来看看框图。看得出来窗口看门狗和独立看门狗的硬件设计差别还是挺大的。

首先它们的时钟源不一样,窗口看门狗的时钟源来自RCC,之前独立看门狗我们不需要打开RCC外设时钟是因为它的时钟源是来自LSI的,而使用窗口看门狗的时候我们就需要打开RCC时钟外设了。

其次窗口看门狗的计数器只有六位,并且从框图上看也没找到重装载计数器。

从上面框图左侧的流程图也看得出窗口看门狗的逻辑流程。

当T6:0 大于W6:0的时候,比较器输出逻辑1,同时WWDG_CR寄存器写入,则小个的那个与门输出逻辑1,和这个逻辑一起写入或门的还有T6这个位,这俩任何一个是逻辑1都会使得或门输出逻辑1。

最后那个大个的与门还连接着WDGA,因此可以猜测,WDGA或许就是窗口看门狗的使能位。

另外再说说T6这个位,它所在的寄存器有着T6:0一共七个位,但是名字却是6位递减计数器。

结合着上面逻辑图,我们大胆猜测,T6不是计数用的位,而是计数溢出时的表示位,这样也可以说得通为什么它连着或门了。因为计数器溢出则需要看门狗复位,而喂狗的时间比设定值更早了也需要复位,因此两个条件一起通向或门。

时序图

根据时序图我们可以了解到窗口看门狗具体的流程了。

W[6:0]是设置不允许刷新(喂狗)的值的,也就是喂狗的最早时间的。

从这段时间开始到达超时时间之间才是可以喂狗的时间。

当我们超过了超时时间后,T6位从1降至0,并且触发复位。所以我们可以得知T6位为0的时候看门狗复位。

控制寄存器WWDG_CR

首先是我们之前说过的WDGA,它果然就是看门狗的激活位,只有它置1了才会启动看门狗。

剩下7位,上面介绍说的是计数器的值从0x40变为0x3f的时候看门狗复位。

0x40是 100 0000

0x3f是 011 1111

所以实际上计数的确实和上面的框图说的一样是六位,因为第七位不直接参与计数,当它从1变为0之后触发复位。

从上面描述我们也看的出预分频器的设置也不是我们随随便便给个值就行的,预分频系数固定为4096*2^WDGTB,因此预分频系数全靠WDGTB来设置。

配置寄存器WWDG_CFR

这个配置寄存器分为三个部分。

第一部分是中断使能位,当计数器达到0x40的时候触发,即看门狗马上就要复位的时候中断。

第二部分是设置WDGTB也就是预分频系数的,能供我们选择的只有1,2,4,8。所以我们的选择并不多。

第三部分是设置窗口值,也就是设置最早的喂狗时间。

有一个需要注意的点,就是这边设置最早喂狗时间的方式是将喂狗时计数器的值和这个窗口值比较,因此这个值实际上是计数器能够记的最大的时间和最早喂狗时间的差值,因此应该填入初始化计数器的那个计数的最大值减去最早喂狗时间能记的数的值。

固件库函数

中断什么的我们就不介绍了,我们就说怎么基础地使用窗口看门狗,主要用的就是我红框框出来的函数。

设置预分频数和设置窗口值没什么可说的,就是普普通通的设置,注意的就是设置预分频器的值的函数给的参数需要是它提供的几种。

窗口看门狗比较不一样的是它喂狗和使能都是要提供参数的,而独立看门狗是不需要的,这也是窗口看门狗没有重装载寄存器的代价。

有一点注意的就是设置计数器的值的时候需要把第7位也就是T6置为1,因为T6为0的时候,窗口看门狗就复位了。

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

int main(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
    
    RCC_ClearFlag();
    
    GPIO_InitTypeDef itd;
    itd.GPIO_Mode=GPIO_Mode_Out_PP;                  
    itd.GPIO_Pin=GPIO_Pin_0;   
    itd.GPIO_Speed=GPIO_Speed_2MHz;                
    GPIO_Init(GPIOA,&itd);
    GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);    //灭灯
    Delay_ms(3000);
    GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);  //亮灯    如果LED时亮时灭则是触发了看门狗复位
    
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
    
    WWDG_SetPrescaler(WWDG_Prescaler_8);    //8分频,则每个计数为0.00091秒,即0.91毫秒   
    WWDG_SetWindowValue(43|0x40);      //最早喂狗时间为0.91*(54-43) ≈ 10ms  数值需要|100 0000 因为要和计数器做比较
    WWDG_Enable(54|0x40);               //最迟喂狗时间为0.91*(54+1) ≈ 50ms  数值需要|100 0000 防止一开始就触发复位
    
    while(1){
        Delay_ms(30);          //每30ms喂狗一次.
        WWDG_SetCounter(54|0x40);
    }
}

经过测试,最早喂狗时间设为10ms,最迟喂狗时间设为50ms。

当主循环中的延时函数延时了10ms的时候看门狗复位,延时函数延时了49ms的时候看门狗复位。可见窗口看门狗的时间还是非常精确的,误差都在1ms之内,并且由于计算的时候就是有小数点误差的,因此实际的误差可能还会更小。因此在时间精度要求比较高的任务中,我们使用的是窗口看门狗。

缺点也是有的,第一个就是计时时间比较短,最多也就五十多毫秒。

第二个缺点就是窗口时间(最早喂狗时间)相对计算的比价绕。简单来说,就是比如我这边给计数器的初始值是n,也就是说计数器的最大值就是n。如果我要求最早喂狗时间转换为计数次数的话是可以记m次,那么设置的窗口值就是n-m。实际计算的时候会稍微麻烦一点:

计数次数等于time/((1s/36MHz)*4096*2^WDGTB)

最后要提醒大家的是,上面用到的与窗口看门狗相关的固件库函数,除了设置预分频器的函数之外,其他的函数的参数都需要|0x40,目的就是使得第7位是1,具体原因在上面已经介绍过了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1491998.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【主题广范|见刊快】2024年可再生能源与智能电网国际学术会议(ICRESG 2024)

【主题广范|见刊快】2024年可再生能源与智能电网国际学术会议(ICRESG 2024) 2024 International Conference Renewable Energy and Smart Grid 本次会议汇聚了来自全球各地的专家学者,共同探讨可再生能源与智能电网领域的最新研究成果、技术进展和未来发展趋势。会…

linux kernel物理内存概述(六)

目录 伙伴系统 1、什么是伙伴? 2、伙伴系统的分配原理 3、伙伴系统回收 伙伴系统 1、什么是伙伴? 伙伴必须是大小相同并且在物理上连续的两个或者多个页。 2、伙伴系统的分配原理 首先根据内存分配接口函数gfp_t gfp_mask,找到内存分…

vue iis 配置

下载安装两个IIS模块 1). 传送门:URL Rewrite 2). 传送门:Application Request Routing 注 : 只有在 服务器的主页 有Application Request Routing 部署VUE网站 生成网站 在VUE项目打包生成出发布文件,即文件夹 dist,此处忽略 复制到你需要存放网站的…

【OpenGL】(1) 专栏介绍:OpenGL 库 | 3D 计算机图形应用 | GPGPU 计算 | 3D 建模和 3D动画 | 渲染技术介绍

🔗 《C语言趣味教程》👈 猛戳订阅!!! 💭 写在前面:本专栏主要内容是关于 3D 计算机图形技术的学习,重点是学习与此技术相关的 3D 实时渲染 (3D real-time rendering) 技术。我们会以…

c语言经典测试题11

1.题1 #include <stdio.h> int main() { int a[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, *p a 5, *q NULL; *q *(p5); printf("%d %d\n", *p, *q); return 0; }上述代码的运行结果是什么呢&#xff1f; 我们来分析一下&#xff1a;我们创建了一个数…

什么是AJAX?它的运用场景有哪些?

文章目录 前言一、什么是AJAX二、AJAX原理是什么三、为什么需要AJAX四、AJAX的使用五、AJAX的应用场景 前言 AJAX 即 Asynchronous Javascript And XML&#xff08;异步JavaScript和XML&#xff09;&#xff0c;是指一种创建交互式网页应用的网页开发技术。 AJAX 是一种用于创…

网络协议栈--应用层--HTTP协议

目录 本节重点理解应用层的作用, 初识HTTP协议 一、应用层二、HTTP协议2.1 认识URL2.2 urlencode和urldecode2.3 HTTP协议格式2.4 HTTP的方法2.4 HTTP的状态码2.5 HTTP常见的Header属性 三、最简单的HTTP服务器3.1 HttpServer.hpp3.2 HttpServer.cc3.3 HttpClient.cc3.4 log.hp…

MySQL之表基本操作及重要概念

前言 表就相当于文件夹中的excel文件&#xff0c;表中的每一条记录就是excel中的一条记录&#xff0c;字段就是表格的表头&#xff0c;记录就是表格中的每一行数据本文将详细介绍表相关操作、mysql存储引擎、字段数据类型及约束条件等知识。 存储引擎 计算机中存储的文件格式…

Discuz IIS上传附件大于28M失败报错Upload Failed.修改maxAllowedContentLength(图文教程)

下图&#xff1a;Discuz X3.5的系统信息&#xff0c;上传许可为1024MB(1GB) 论坛为局域网论坛&#xff0c;仅供内部同事交流使用&#xff01; 使用官方最新的Discuz! X3.5 Release 20231221 UTF-8 下图&#xff1a;选择上传附件&#xff08;提示可以最大上传100M&#xff09;…

新模型Claude 3实测!各项能力超强,确实比GPT-4好用

2024最新教程Claude 3注册账号&#xff0c;小白教程包教包会 过去不到一个月&#xff0c;OpenAI 扔出 Sora 这个重磅炸弹后成为全球焦点&#xff0c;不断推出的视频更是赚足眼球、热度不减。昨晚&#xff0c;Anthropic 突然惊喜上线&#xff0c;时隔八个月携着 Claude 3 走来&…

【Java EE 】认识文件与Java文件操作

目录 &#x1f340;认识文件&#x1f338;树型结构组织 和 目录&#x1f338;文件路径&#xff08;Path&#xff09;&#x1f338;其他知识 &#x1f333;Java 中操作文件&#x1f338;File 概述&#x1f33b;属性&#x1f33b;构造方法&#x1f33b;方法 &#x1f338;代码示例…

西安雁塔未来人工智能计算中心算力成本分析

先看一例旧闻&#xff1a;西部“最强大脑”落户雁塔——30亿亿次超算能力助力创新之城建设 其中提到一期算力为 300PFLOPS FP16&#xff08;每秒30亿亿次半精度浮点计算&#xff09;&#xff0c;项目总投资约为19亿元。 这个算力是什么概念呢&#xff1f; 我们以深度学习训练中…

100%开源大模型OLMo:代码/权重/数据集/训练全过程公开,重定义AI共享

前言 近日&#xff0c;艾伦人工智能研究所联合多个顶尖学术机构发布了史上首个100%开源的大模型“OLMo”&#xff0c;这一举措被认为是AI开源社区的一大里程碑。OLMo不仅公开了模型权重&#xff0c;还包括了完整的训练代码、数据集和训练过程&#xff0c;为后续的开源工作设立…

C语言回顾学习

一、数据类型 1.常量 2.float浮点表示 3.字符型 4.char&#xff08;大小写&#xff09; #include <stdio.h> //根据数字输出字符--int值可以直接输出为char int main() {int value;while (1){scanf("%d",&value);if(value<65||value>122){printf(&…

【Redis】RedisTemplate和StringRedisTemplate的区别

两者的关系是 StringRedisTemplate 继承 RedisTemplate 。 两者的数据是不共通的&#xff1a;也就是说 StringRedisTemplate 只能管理 StringRedisTemplate 里面的数据&#xff0c;RedisTemplate 只能管理 RedisTemplate 中的数据。 RedisTemplate 看这个类的名字后缀是 Temp…

android开发游戏加速器,Android架构组件Room功能详解

Java基础 Java Object类方法HashMap原理&#xff0c;Hash冲突&#xff0c;并发集合&#xff0c;线程安全集合及实现原理HashMap 和 HashTable 区别HashCode 作用&#xff0c;如何重载hashCode方法ArrayList与LinkList区别与联系GC机制Java反射机制&#xff0c;Java代理模式Jav…

UOS 20 安装redis 7.0.11 安装redis 7.0.11时 make命令 报错 /bin/sh: cc: command not found

UOS 20 安装redis 7.0.11 1、下载redis 7.0.112、安装redis 7.0.113、启动停止redis 7.0.114、安装过程问题记录 UOS 20 安装redis 7.0.11 安装redis 7.0.11时 make命令 报错 /bin/sh: cc: command not found、zmalloc.h:50:31: fatal error: jemalloc/jemalloc.h: No such fil…

jquery选择器有哪些

jQuery是一个功能强大的JavaScript库&#xff0c;它提供了丰富的选择器来帮助开发者更方便地选择和操作DOM元素。以下是jQuery的一些常用选择器及其示例代码&#xff1a; 1.基本选择器&#xff1a; // 通过ID选择元素 $("#myId").css("color", "red…

java实现文件上传到本地

很多时候我们都需要进行文件上传和下载的操作&#xff0c;具体怎么实现网上的代码其实也是挺多的&#xff0c;刚好我的项目中也遇到了文件上传和下载的需求&#xff0c;本篇博文具体讲解上传操作&#xff0c;下篇博文讲解下载操作。 我们具体来想一想要将一个从前端传来的文件…

一命通关二分搜索

二分法 简介 和双指针一样&#xff0c;二分法也是一种优化方法&#xff0c;或者说二分法就是双指针的一类。不过&#xff0c;二分法的思想比双指针诞生更早也更广泛&#xff0c;在我们日常生活里也无时不刻在使用二分的思想。 比如我们想回顾某些影片&#xff0c;但是只记得…