【正点原子STM32】IWDG 独立看门狗(简介、工作原理、IWDG寄存器配置操作步骤、IWDG溢出时间计算、IWDG配置步骤、独立看门狗流程)

一、IWDG简介

  • IWDG有什么作用?

二、IWDG工作原理
三、IWDG框图
四、IWDG寄存器

  • 键寄存器(IWDG_KR)
  • 预分频器寄存器 (IWDG_PR)
  • 重装载寄存器(IWDG_RLR)
  • 状态寄存器(IWDG_SR)
  • 寄存器配置操作步骤

五、IWDG溢出时间计算

  • IWDG溢出时间计算公式(HAL库)
  • 寄存器设置分频系数的方法
  • IWDG溢出时间计算公式(寄存器)
  • IWDG最短最长超时时间

六、IWDG配置步骤
七、编程实战:验证不及时喂狗,系统将复位重启
八、总结

一、IWDG简介

在这里插入图片描述
IWDG(Independent Watchdog,独立看门狗)的基本概念:

  1. IWDG的全称: IWDG全称为Independent Watchdog,它是一种用于监控系统运行的硬件设备。

  2. IWDG的本质: IWDG是一个递减的计数器,如果在一段时间内没有被重新加载(喂狗),则会产生系统复位信号。它是为了防止系统由于某些原因(例如程序错误或系统死锁)导致无响应。

  3. IWDG的时钟: IWDG的时钟通常由独立的RC(Resistor-Capacitor)振荡器提供。这使得IWDG能够在待机(Standby)和停止(Stop)模式下运行,即使主系统时钟停止,IWDG仍然能够正常工作。

  4. 复位触发条件: IWDG的计数器递减,当计数器的值减至0x000时,会产生复位。这种设计保证了即使系统出现问题,也会在一定时间内进行复位。

  5. 喂狗: 喂狗是指在IWDG计数器减至0之前,通过重新加载计数器的值来防止复位。通过定期喂狗,可以确保系统正常运行,否则IWDG会在计数器减至0时触发复位。

IWDG通常是嵌入式系统中的一个重要功能,用于提高系统的稳定性和可靠性。在实际应用中,程序员需要根据系统的实际需求配置IWDG,并在合适的位置定期喂狗,以确保系统不会因为某些异常情况而一直停滞。
在这里插入图片描述
STM32F10xxx闪存编程手册

IWDG有什么作用?

在这里插入图片描述
IWDG的作用的关键点:

  1. 检测异常: IWDG主要用于检测系统中的异常情况,包括但不限于外界电磁干扰、硬件异常或软件异常。当系统出现无法处理的异常时,可能导致程序失控、死循环等问题,此时IWDG可以通过触发复位来使系统重新启动,从而恢复正常运行。

  2. 电磁干扰: 在一些嵌入式系统中,特别是一些对抗电磁干扰要求较高的应用场景,IWDG可以起到一种保护作用。外界的电磁干扰有可能导致系统产生错误,而IWDG则能够在检测到异常时及时复位系统,以保障系统的稳定性。

  3. 硬件异常: 除了电磁干扰,IWDG还能够监测到一些硬件异常,比如电源波动、时钟故障等。这些硬件异常可能导致系统运行不正常,而IWDG可以在检测到这些异常时采取措施。

  4. 最后手段: IWDG通常被看作是异常处理的最后手段。当其他的异常处理机制都无法正常工作或者不可靠时,IWDG可以作为一个保险机制,确保在极端情况下系统可以重新启动。

  5. 应用场景: IWDG适用于对系统稳定性要求较高、对时间精度要求较低的场合。在一些嵌入式产品中,特别是一些安全关键系统或长时间运行的系统中,使用IWDG可以提高系统的可靠性。

  6. 依赖性: 尽管IWDG是一个有力的异常处理手段,但设计时应避免对它的过度依赖。最好的做法是在系统设计和软件编程中尽量避免异常的发生,使得IWDG只在极端情况下起到最后的保护作用。

二、IWDG工作原理

在这里插入图片描述
IWDG的工作原理:

  1. 时钟源 (Src CLK): IWDG的工作始于一个时钟源,该时钟源通常是一个独立的RC振荡器。这个时钟源提供了IWDG的时基。

  2. 预分频器 (PSC): 时钟源进入预分频器,预分频器用于将时钟源的频率进行分频。预分频因子决定了IWDG的时钟频率,进而影响计数器的递减速度。

  3. IWDG时钟 (IWDG CLK): 经过预分频后的时钟被用作IWDG的时钟,这个时钟将用于递减计数器。

  4. 递减计数器 (CNT): 递减计数器是IWDG的核心组件。它以IWDG时钟的速率递减,当计数器减至零时,触发相应的操作,通常是产生复位信号。

  5. 重装载寄存器 (RELOAD): 在IWDG工作期间,可以通过将重装载寄存器的值写入CNT寄存器,重置计数器。这就是“喂狗”的概念。如果在计数器递减至零之前及时进行重装载,系统就不会因为IWDG的复位而重新启动。

  6. 复位: 当计数器递减至零时,IWDG触发相应的操作,通常是系统复位。这样可以确保系统在长时间没有喂狗的情况下仍能重新启动,从而防止系统因为外界干扰或软硬件错误而陷入死循环或无法响应的状态。

整个过程通过控制时钟源、预分频、递减计数器和重装载寄存器,实现了对系统的监控和复位功能,确保系统在异常情况下能够恢复到正常工作状态。

三、IWDG框图

在这里插入图片描述
IWDG的框图和各个组成部分的功能描述的一些关键点:

  1. 低速内部(LSI) RC振荡器: IWDG的时钟源是LSI(低速内部)RC振荡器。在启用IWDG后,LSI时钟会自动开启。需要注意的是,LSI的时钟频率可能不够精确,因此在计算时需要注意。

  2. 预分频器寄存器 (IWDG_PR): 8位预分频器用于对LSI时钟进行预分频,从而得到IWDG的时钟。通过调整预分频因子,可以调整IWDG的工作频率,影响计数器的递减速度。

  3. 状态寄存器 (IWDG_SR): 状态寄存器用于监测IWDG的状态,其中包括计数器的运行状态和复位状态。

  4. 递减计数器 (IWDG_CNT): 12位递减计数器是IWDG的核心部分。它以预分频后的时钟为基准递减,当计数器减至零时,触发相应的操作。

  5. 密钥寄存器 (IWDG_KR): 密钥寄存器用于对IWDG进行操作的授权。写入指定值后,才能对IWDG进行启动、重装载等操作。

  6. 重载寄存器 (IWDG_RLR): 重载寄存器用于设置IWDG的重装载值,即重新加载计数器的值。通过定期对该寄存器进行写入,可以避免IWDG触发复位。

  7. 看门狗功能供电: IWDG的功能是由 V D D V_{DD} VDD电压域供电的,这意味着即使在停止模式和待机模式下,IWDG仍然能够正常工作。

整个框图清晰地展示了IWDG的各个组成部分,并说明了它们之间的关系和作用。这样的硬件设计使得IWDG能够在异常情况下提供可靠的系统监控和复位功能。
在这里插入图片描述

四、IWDG寄存器

键寄存器(IWDG_KR)

键寄存器可以看作是独立看门狗的控制寄存器
在这里插入图片描述
   在键寄存器(IWDG_KR)中写入 0xCCCC,开始启用独立看门狗;此时计数器开始从其复位值 0xFFF 递减计数。当计数器计数到末尾 0x000 时,会产生一个复位信号(IWDG_RESET)。无论何时,只要键寄存器 IWDG_KR 中被写入 0xAAAA,IWDG_RLR 中的值就会被重新加载到计数器中从而避免产生看门狗复位。
   IWDG_PR 和 IWDG_RLR 寄存器具有写保护功能。要修改这两个寄存器的值,必须先向IWDG_KR 寄存器中写入 0x5555。将其他值写入这个寄存器将会打乱操作顺序,寄存器将重新被保护。重装载操作(即写入 0xAAAA)也会启动写保护功能。
  (若选择了硬件看门狗则不受此命令字限制)
在这里插入图片描述

预分频器寄存器 (IWDG_PR)

在这里插入图片描述
  该寄存器用来设置看门狗时钟(LSI)的分频系数,最低为 4,最高位 256,该寄存器是一个 32 位的寄存器,但是我们只用了最低 3 位,其他都是保留位。

预分频器寄存器(IWDG_PR)是独立看门狗(IWDG)中的一个寄存器,用于设置预分频因子,从而调整IWDG的时钟频率。IWDG的时钟频率直接影响计数器的递减速度。

预分频器寄存器 (IWDG_PR) 用于设置 IWDG 的预分频因子,从而确定 IWDG 的时钟频率。这个预分频因子决定了递减计数器的速度,进而影响看门狗的定时周期。IWDG_PR 寄存器是一个 3 位的寄存器,可以设置的预分频因子如下:

Bit 2:0 PR[2:0]: Prescaler divider
          000: f(LSI) / 4
          001: f(LSI) / 8
          010: f(LSI) / 16
          011: f(LSI) / 32
          100: f(LSI) / 64
          101: f(LSI) / 128
          110: f(LSI) / 256
          111: f(LSI) / 256
  • 000: IWDG时钟 = LSI / 4
  • 001: IWDG时钟 = LSI / 8
  • 010: IWDG时钟 = LSI / 16
  • 011: IWDG时钟 = LSI / 32
  • 100: IWDG时钟 = LSI / 64
  • 101: IWDG时钟 = LSI / 128
  • 110: IWDG时钟 = LSI / 256
  • 111: IWDG时钟 = LSI / 256

这里的f(LSI)表示低速内部(LSI)RC振荡器的频率。通过设置PR位,可以选择不同的预分频因子,从而得到不同的IWDG时钟频率。

例如,如果设置PR位为010,则预分频因子为16,IWDG的时钟频率将是LSI时钟频率的1/16。这会使得计数器的递减速度减缓,增加喂狗的时间间隔。

在使用IWDG时,你可以根据实际需求选择适当的预分频因子,以平衡系统对看门狗的监测精度和系统响应速度的要求。

通过选择适当的预分频因子,可以调整 IWDG 的时钟频率,以满足特定的定时需求。更小的预分频因子将导致更快的计数器递减速度,而更大的预分频因子将导致更慢的计数器递减速度。在实际应用中,需要根据具体的系统需求和预期的看门狗定时周期来选择合适的预分频因子。

重装载寄存器(IWDG_RLR)

在这里插入图片描述
  该寄存器用来保存重装载到计数器中的值。该寄存器也是一个 32 位寄存器,只有低 12 位是有效的。

重装载寄存器(IWDG_RLR)是 IWDG 的一个重要寄存器,用于设置 IWDG 的重载值。这个值决定了递减计数器的初始值,也就是看门狗的计数周期。当递减计数器递减到零时,会触发相应的操作,通常是产生复位信号。

IWDG_RLR 是一个 12 位的寄存器,可以设置的范围是 0 到 0xFFF(4095)。这个数值表示递减计数器的初始值。在 IWDG 启动后,计数器开始递减,当递减计数器减至零时,会产生复位。为了防止复位发生,需要定期“喂狗”(重新加载计数器)。

重装载寄存器的使用步骤:

  1. 初始化 IWDG_RLR,设置递减计数器的初始值。这通常在系统初始化的时候进行。
IWDG_RLR = 0x0FFF; // 设置重载值,决定计数周期
  1. 启动 IWDG。一旦 IWDG 启动,递减计数器开始递减。
IWDG_KR = 0xAAAA; // 启动 IWDG
  1. 定期“喂狗”,重新加载计数器。这通常在程序的主循环中或者其他适当的位置进行。
IWDG_KR = 0xAAAA; // 喂狗,重新加载计数器

通过调整重装载寄存器的值,可以实现对看门狗定时周期的控制,满足系统的监控和复位需求。

状态寄存器(IWDG_SR)

在这里插入图片描述
状态寄存器 (IWDG_SR) 是 IWDG(Independent Watchdog,独立看门狗)的一个寄存器,用于监控 IWDG 的运行状态。IWDG_SR 寄存器的位域描述了 IWDG 的状态信息。以下是 IWDG_SR 寄存器的主要位域:

  1. Bit 0 - RVU: 重装载值更新

    • 0: 重装载寄存器的值没有被更新。
    • 1: 重装载寄存器的值已经被更新。
  2. Bit 1 - PVU: 预分频器值更新

    • 0: 预分频器寄存器的值没有被更新。
    • 1: 预分频器寄存器的值已经被更新。
  3. Bit 2 - WVU: 窗口寄存器值更新

    • 0: 窗口寄存器的值没有被更新。
    • 1: 窗口寄存器的值已经被更新。
  4. Bit 3 - KEY: 密钥值

    • 0: 密钥寄存器的值没有被更新。
    • 1: 密钥寄存器的值已经被更新。

使用状态寄存器的步骤:

  1. 检查 RVU、PVU、WVU、KEY 位: 在对 IWDG 进行任何配置之前,可以检查这些位,确保相关寄存器的值已经被更新。

  2. 配置重载值(RLR)、预分频器值(PR)和窗口寄存器值(WINR): 根据系统需求配置相应的寄存器。

  3. 更新密钥寄存器(KR): 将 IWDG_KR 寄存器写入 0x5555,然后写入 0xAAAA,以更新相关寄存器的值。

  4. 检查状态寄存器位: 可以通过检查 RVU、PVU、WVU、KEY 位来确认更新是否成功。

总体而言,状态寄存器用于提供关于 IWDG 配置的更新状态信息,确保相关寄存器的值在使用前已经被更新。

寄存器配置操作步骤

在这里插入图片描述
配置STM32上独立看门狗(IWDG)的寄存器的操作。下面是对每个步骤的详细解释:

  1. 使能IWDG:
    通过在键寄存器(IWDG_KR)中写入0xCCCC,可以使能IWDG。这个操作告诉IWDG开始工作,启动递减计数器。

  2. 使能寄存器访问:
    通过在键寄存器(IWDG_KR)中写入0x5555,可以使能对IWDG相关寄存器的访问。这个步骤通常在修改IWDG配置之前进行,确保能够对寄存器进行写操作。

  3. 配置预分频器:
    通过将预分频器寄存器(IWDG_PR)的值设置为0到7之间的数值,可以配置IWDG的预分频器。预分频器用于将IWDG的时钟源进行分频,以设置递减计数器的计数速度。

  4. 写入重载寄存器:
    通过对重载寄存器(IWDG_RLR)进行写操作,设置递减计数器的初始值。这个值决定了IWDG的计数周期。

  5. 等待寄存器更新:
    在写入寄存器配置后,等待寄存器更新。可以通过检查状态寄存器(IWDG_SR)的值,确认相关寄存器的更新状态。通常等待IWDG_SR等于0x0000 0000。

  6. 刷新计数器:
    最后,通过在键寄存器(IWDG_KR)中写入0xAAAA来刷新计数器。这个操作相当于“喂狗”,重新加载计数器的值,以防止IWDG产生复位信号。

这些步骤确保了IWDG的正确配置和运行,以提供对系统的监控和保护。

五、IWDG溢出时间计算

在这里插入图片描述

IWDG溢出时间计算公式(HAL库)

在HAL库中,IWDG(Independent Watchdog,独立看门狗)的溢出时间 T o u t T_{out} Tout 可以通过以下公式计算:

T o u t = p s c × r l r f IWDG T_{out} = \frac{psc \times rlr}{f_{\text{IWDG}}} Tout=fIWDGpsc×rlr

其中:

  • T o u t T_{out} Tout 是看门狗的溢出时间。
  • f IWDG f_{\text{IWDG}} fIWDG 是看门狗的时钟源频率。
  • p s c psc psc 是看门狗的预分频系数。
  • r l r rlr rlr 是看门狗的重装载值。

这个公式描述了看门狗计数器的计数时间,即在重新加载计数器之前的时间。通常, T o u t T_{out} Tout 可以用来估算系统的监视时间,确保系统在这个时间内喂狗,防止看门狗产生复位信号。

推导IWDG溢出时间的公式

推导IWDG溢出时间的公式涉及时钟源频率、预分频系数和重装载值等参数。以下是一个简化的推导过程:

  1. IWDG时钟源频率 f IWDG f_{\text{IWDG}} fIWDG
    在HAL库中,IWDG的时钟源通常是LSI(低速内部振荡器)。该频率通常在芯片手册中给出,以 H z Hz Hz为单位。假设为 f IWDG f_{\text{IWDG}} fIWDG

  2. IWDG预分频系数 p s c psc psc
    预分频系数 p s c psc psc 用于将时钟源的频率进行分频,以降低计数器的计数速度。 p s c psc psc 的值可以设置为0到7之间的整数。

  3. IWDG重装载值 r l r rlr rlr
    重装载值 r l r rlr rlr 决定了IWDG计数器的初始值,即溢出时间的起点。 r l r rlr rlr 也是可以根据系统需求设置的值。

  4. IWDG计数器的溢出时间 T out T_{\text{out}} Tout
    IWDG的计数器溢出时间可以通过以下公式计算:
    T out = p s c × r l r f IWDG T_{\text{out}} = \frac{psc \times rlr}{f_{\text{IWDG}}} Tout=fIWDGpsc×rlr

推导的步骤:

  1. 计算分频后的时钟频率:
    通过时钟频率 f IWDG f_{\text{IWDG}} fIWDG 和看门狗预分频系数 p s c psc psc 的除法得到分频后的时钟频率 f IWDG p s c \frac{f_{\text{IWDG}}}{psc} pscfIWDG。这个值表示IWDG实际工作时的时钟频率,即一秒钟内IWDG可以进行的计数次数。

  2. 计算一次计数需要的时间:
    取上一步计算的分频后时钟频率的倒数,即 1 f IWDG p s c \frac{1}{\frac{f_{\text{IWDG}}}{psc}} pscfIWDG1,这个值表示IWDG进行一次计数所需的时间。

  3. 计算溢出时间:
    将上一步得到的一次计数时间乘以看门狗重装载值 r l r rlr rlr,即 p s c f IWDG × r l r \frac{psc}{f_{\text{IWDG}}} \times rlr fIWDGpsc×rlr,得到的结果就是看门狗的溢出时间。

这个公式的推导基于时钟源的分频、重装载值和时钟频率的关系。确保 T out T_{\text{out}} Tout 不超过IWDG的设定溢出时间,以免系统因未及时喂狗而触发复位。

寄存器设置分频系数的方法

在STM32系列的IWDG中,预分频系数 p s c psc psc 与寄存器 I W D G _ P R IWDG\_PR IWDG_PR 的设置关系为:

p s c = 4 × 2 p r e r psc = 4 \times 2^{prer} psc=4×2prer

其中:

  • p r c r prcr prcr I W D G _ P R IWDG\_PR IWDG_PR 寄存器的设置值。

这个公式表达了预分频系数 p s c psc psc I W D G _ P R IWDG\_PR IWDG_PR 寄存器的值之间的关系。通过调整 I W D G _ P R IWDG\_PR IWDG_PR 的值,可以间接地影响 p s c psc psc,从而调整IWDG的时钟频率。在设置IWDG时,需要根据具体的应用和需求选择合适的 I W D G _ P R IWDG\_PR IWDG_PR 的值,以满足对看门狗的计数速度的要求。

IWDG溢出时间计算公式(寄存器)

在使用寄存器配置IWDG时,计算溢出时间的公式可以表示为:

T o u t = ( 4 × 2 p r e r ) × r l r f IWDG T_{out} = \frac{(4 \times 2^{prer}) \times rlr}{f_{\text{IWDG}}} Tout=fIWDG(4×2prer)×rlr

其中:

  • T o u t T_{out} Tout 是IWDG的溢出时间。
  • f IWDG f_{\text{IWDG}} fIWDG 是IWDG的时钟源频率,通常是LSI的频率。
  • p r e r prer prer I W D G _ P R IWDG\_PR IWDG_PR 寄存器的设置值,决定了预分频系数。
  • r l r rlr rlr 是IWDG的重装载值,决定了计数器的初始值。

这个公式描述了IWDG计数器的溢出时间,即在重新加载计数器之前的时间。确保 T o u t T_{out} Tout 不超过IWDG的设定溢出时间,以免系统因未及时喂狗而触发复位。

IWDG最短最长超时时间

在STM32系列中,IWDG的时钟源通常是LSI(低速内部振荡器),其频率为40kHz和32kHz。根据这个时钟源频率,我们可以计算IWDG的最短和最长超时时间。

  1. 最短超时时间:
    由于IWDG是一个12位的递减计数器,最短超时时间为计数器值为1时的时间。因此,最短超时时间 $ T_{\text{min}}$ 可以通过以下公式计算:
    T min = 1 LSI频率 T_{\text{min}} = \frac{1}{\text{LSI频率}} Tmin=LSI频率1

  2. 最长超时时间:
    最长超时时间取决于IWDG的重装载值 r l r rlr rlr 的设置。假设 r l r rlr rlr 设置为最大值(即4095),最长超时时间 T max T_{\text{max}} Tmax 可以通过以下公式计算:
    T max = 4095 × 4 × 2 p r e r LSI频率 T_{\text{max}} = \frac{4095 \times 4 \times 2^{prer}}{\text{LSI频率}} Tmax=LSI频率4095×4×2prer

其中, p r e r prer prer I W D G _ P R IWDG\_PR IWDG_PR 寄存器的设置值,决定了预分频系数。确保 T max T_{\text{max}} Tmax 不超过IWDG的设定溢出时间,以免系统因未及时喂狗而触发复位。

IWDG最短最长超时时间(F1)

在这里插入图片描述

IWDG最短最长超时时间(F4/F7/H7)

在这里插入图片描述

六、IWDG配置步骤

在这里插入图片描述

HAL库相关函数介绍

在这里插入图片描述
HAL_IWDG_Init 函数和 HAL_IWDG_Refresh 函数是HAL库中用于初始化和刷新IWDG的两个函数。

  1. HAL_IWDG_Init 函数:
HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg)
  • 输入参数: IWDG_HandleTypeDef 结构体,包含IWDG的基地址和初始化参数。
  • 功能: 使能IWDG,设置预分频系数和重装载值等。
  • 具体操作:
    • 使用给定的 IWDG_InitTypeDef 结构体中的参数,配置IWDG的预分频系数和重装载值。
    • 启用IWDG时钟。
    • 使用配置好的参数初始化IWDG。
  1. HAL_IWDG_Refresh 函数:
HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg)
  • 输入参数: IWDG_HandleTypeDef 结构体,包含IWDG的基地址。
  • 功能: 将重装载寄存器的值重载到计数器中,喂狗。
  • 具体操作:
    • 通过IWDG的键寄存器 (IWDG_KR) 将重装载值加载到递减计数器。
    • 此函数用于定期刷新IWDG,以防止计数器溢出导致系统复位。

IWDG_HandleTypeDef 结构体包含IWDG的基地址和初始化参数,而 IWDG_InitTypeDef 结构体包含预分频系数和重装载值等参数。这两个函数配合使用,能够实现对IWDG的初始化和刷新操作。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
stm32f1xx_hal.c

#include "stm32f1xx_hal.h"

#ifdef HAL_IWDG_MODULE_ENABLED
#define HAL_IWDG_DEFAULT_TIMEOUT ((6UL * 256UL * 1000UL) / LSI_VALUE)

HAL_StatusTypeDef HAL_IWDG_Init(IWDG_HandleTypeDef *hiwdg)
{
  uint32_t tickstart;

  /* Check the IWDG handle allocation */
  if (hiwdg == NULL)
  {
    return HAL_ERROR;
  }

  /* Check the parameters */
  assert_param(IS_IWDG_ALL_INSTANCE(hiwdg->Instance));
  assert_param(IS_IWDG_PRESCALER(hiwdg->Init.Prescaler));
  assert_param(IS_IWDG_RELOAD(hiwdg->Init.Reload));

  /* Enable IWDG. LSI is turned on automatically */
  __HAL_IWDG_START(hiwdg);

  /* Enable write access to IWDG_PR and IWDG_RLR registers by writing
  0x5555 in KR */
  IWDG_ENABLE_WRITE_ACCESS(hiwdg);

  /* Write to IWDG registers the Prescaler & Reload values to work with */
  hiwdg->Instance->PR = hiwdg->Init.Prescaler;
  hiwdg->Instance->RLR = hiwdg->Init.Reload;

  /* Check pending flag, if previous update not done, return timeout */
  tickstart = HAL_GetTick();

  /* Wait for register to be updated */
  while (hiwdg->Instance->SR != 0x00u)
  {
    if ((HAL_GetTick() - tickstart) > HAL_IWDG_DEFAULT_TIMEOUT)
    {
      return HAL_TIMEOUT;
    }
  }

  /* Reload IWDG counter with value defined in the reload register */
  __HAL_IWDG_RELOAD_COUNTER(hiwdg);

  /* Return function status */
  return HAL_OK;
}

HAL_StatusTypeDef HAL_IWDG_Refresh(IWDG_HandleTypeDef *hiwdg)
{
  /* Reload IWDG counter with value defined in the reload register */
  __HAL_IWDG_RELOAD_COUNTER(hiwdg);

  /* Return function status */
  return HAL_OK;
}

#endif /* HAL_IWDG_MODULE_ENABLED */

stm32f1xx_hal.h

#ifndef __STM32F1xx_HAL_DEF
#define __STM32F1xx_HAL_DEF

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "stm32f1xx.h"
#include "Legacy/stm32_hal_legacy.h"
#include <stddef.h>

/* Exported types ------------------------------------------------------------*/

/**
  * @brief  HAL Status structures definition
  */
typedef enum
{
  HAL_OK       = 0x00U,
  HAL_ERROR    = 0x01U,
  HAL_BUSY     = 0x02U,
  HAL_TIMEOUT  = 0x03U
} HAL_StatusTypeDef;

/**
  * @brief  HAL Lock structures definition
  */
typedef enum
{
  HAL_UNLOCKED = 0x00U,
  HAL_LOCKED   = 0x01U
} HAL_LockTypeDef;

/* Exported macro ------------------------------------------------------------*/
#define HAL_MAX_DELAY      0xFFFFFFFFU

#define HAL_IS_BIT_SET(REG, BIT)         (((REG) & (BIT)) != 0U)
#define HAL_IS_BIT_CLR(REG, BIT)         (((REG) & (BIT)) == 0U)

#define __HAL_LINKDMA(__HANDLE__, __PPP_DMA_FIELD__, __DMA_HANDLE__)               \
                        do{                                                      \
                              (__HANDLE__)->__PPP_DMA_FIELD__ = &(__DMA_HANDLE__); \
                              (__DMA_HANDLE__).Parent = (__HANDLE__);             \
                          } while(0U)

#define UNUSED(X) (void)X      /* To avoid gcc/g++ warnings */

#define __HAL_RESET_HANDLE_STATE(__HANDLE__) ((__HANDLE__)->State = 0U)

#if (USE_RTOS == 1U)
/* Reserved for future use */
#error "USE_RTOS should be 0 in the current HAL release"
#else
#define __HAL_LOCK(__HANDLE__)                                           \
                                do{                                        \
                                    if((__HANDLE__)->Lock == HAL_LOCKED)   \
                                    {                                      \
                                       return HAL_BUSY;                    \
                                    }                                      \
                                    else                                   \
                                    {                                      \
                                       (__HANDLE__)->Lock = HAL_LOCKED;    \
                                    }                                      \
                                  }while (0U)

#define __HAL_UNLOCK(__HANDLE__)                                          \
                                  do{                                       \
                                      (__HANDLE__)->Lock = HAL_UNLOCKED;    \
                                    }while (0U)
#endif /* USE_RTOS */

#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) /* ARM Compiler V6 */
#ifndef __weak
#define __weak  __attribute__((weak))
#endif
#ifndef __packed
#define __packed  __attribute__((packed))
#endif
#elif defined ( __GNUC__ ) && !defined (__CC_ARM) /* GNU Compiler */
#ifndef __weak
#define __weak   __attribute__((weak))
#endif /* __weak */
#ifndef __packed
#define __packed __attribute__((__packed__))
#endif /* __packed */
#endif /* __GNUC__ */


/* Macro to get variable aligned on 4-bytes, for __ICCARM__ the directive "#pragma data_alignment=4" must be used instead */
#if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) /* ARM Compiler V6 */
#ifndef __ALIGN_BEGIN
#define __ALIGN_BEGIN
#endif
#ifndef __ALIGN_END
#define __ALIGN_END      __attribute__ ((aligned (4)))
#endif
#elif defined ( __GNUC__ ) && !defined (__CC_ARM) /* GNU Compiler */
#ifndef __ALIGN_END
#define __ALIGN_END    __attribute__ ((aligned (4)))
#endif /* __ALIGN_END */
#ifndef __ALIGN_BEGIN
#define __ALIGN_BEGIN
#endif /* __ALIGN_BEGIN */
#else
#ifndef __ALIGN_END
#define __ALIGN_END
#endif /* __ALIGN_END */
#ifndef __ALIGN_BEGIN
#if defined   (__CC_ARM)      /* ARM Compiler V5*/
#define __ALIGN_BEGIN    __align(4)
#elif defined (__ICCARM__)    /* IAR Compiler */
#define __ALIGN_BEGIN
#endif /* __CC_ARM */
#endif /* __ALIGN_BEGIN */
#endif /* __GNUC__ */


/**
  * @brief  __RAM_FUNC definition
  */
#if defined ( __CC_ARM   ) || (defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))

#define __RAM_FUNC

#elif defined ( __ICCARM__ )
/* ICCARM Compiler
   ---------------
   RAM functions are defined using a specific toolchain keyword "__ramfunc".
*/
#define __RAM_FUNC __ramfunc

#elif defined   (  __GNUC__  )
/* GNU Compiler
   ------------
  RAM functions are defined using a specific toolchain attribute
   "__attribute__((section(".RamFunc")))".
*/
#define __RAM_FUNC __attribute__((section(".RamFunc")))

#endif

/**
  * @brief  __NOINLINE definition
  */
#if defined ( __CC_ARM   ) || (defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)) || defined   (  __GNUC__  )
/* ARM V4/V5 and V6 & GNU Compiler
   -------------------------------
*/
#define __NOINLINE __attribute__ ( (noinline) )

#elif defined ( __ICCARM__ )
/* ICCARM Compiler
   ---------------
*/
#define __NOINLINE _Pragma("optimize = no_inline")

#endif

#ifdef __cplusplus
}
#endif

#endif /* ___STM32F1xx_HAL_DEF */

七、编程实战:验证不及时喂狗,系统将复位重启

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

wdg.c

#include "./BSP/WDG/wdg.h"

IWDG_HandleTypeDef g_iwdg_handle;  // 定义IWDG的句柄

/* IWDG初始化函数 */
void iwdg_init(uint8_t prer, uint16_t rlr)
{
    g_iwdg_handle.Instance = IWDG;           // 设置IWDG句柄的寄存器基地址为IWDG
    g_iwdg_handle.Init.Prescaler = prer;     // 设置IWDG的预分频系数
    g_iwdg_handle.Init.Reload = rlr;         // 设置IWDG的重装载值
    HAL_IWDG_Init(&g_iwdg_handle);           // 使用HAL库初始化IWDG
}

/* 喂狗函数 */
void iwdg_feed(void)
{
    HAL_IWDG_Refresh(&g_iwdg_handle);  // 使用HAL库刷新IWDG,防止看门狗复位系统
}

wdg.h

#ifndef __WDG_H
#define __WDG_H

#include "./SYSTEM/sys/sys.h"


void iwdg_init(uint8_t prer, uint16_t rlr);
void iwdg_feed(void);

#endif

main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/WDG/wdg.h"

int main(void)
{
    HAL_Init();                             // 初始化HAL库
    sys_stm32_clock_init(RCC_PLL_MUL9);     // 设置时钟为72MHz
    delay_init(72);                         // 延时初始化
    usart_init(115200);                     // 串口初始化为115200
    
    printf("您还没喂狗,请及时喂狗!!!\r\n");  // 打印提示信息

    iwdg_init(IWDG_PRESCALER_32, 1250);     // 预分频系数为32,重装载值为1250,溢出时间约为1s

    while (1)
    {
        delay_ms(1000);                     // 延时1秒
        iwdg_feed();                        // 喂狗,刷新看门狗计数器
        printf("已经喂狗\r\n");             // 打印喂狗提示信息
    }
}

IWDG的重装载值(Reload Value)的计算方式与溢出时间直接相关。溢出时间(Timeout)的计算公式如下:

Tout = PSC × RLR fIWDG \text{Tout} = \frac{\text{PSC} \times \text{RLR}}{\text{fIWDG}} Tout=fIWDGPSC×RLR

其中:

  • Tout \text{Tout} Tout 是看门狗溢出时间。
  • PSC \text{PSC} PSC 是预分频系数。
  • RLR \text{RLR} RLR 是重装载值。
  • fIWDG \text{fIWDG} fIWDG 是看门狗的时钟源频率。

在你的代码中,预分频系数( PSC \text{PSC} PSC)被设置为32,这是一个固定的值。时钟源频率( fIWDG \text{fIWDG} fIWDG)为40kHz。

如果要计算重装载值( RLR \text{RLR} RLR),可以根据预期的溢出时间来确定。在你的情况下,你希望溢出时间约为1秒。因此,可以通过重排上述公式解出 RLR \text{RLR} RLR

RLR = Tout × fIWDG PSC \text{RLR} = \frac{\text{Tout} \times \text{fIWDG}}{\text{PSC}} RLR=PSCTout×fIWDG

将数值代入,得到:

RLR = 1 × 40000 32 = 1250 \text{RLR} = \frac{1 \times 40000}{32} = 1250 RLR=321×40000=1250

所以,重装载值( RLR \text{RLR} RLR)为1250。
在这里插入图片描述
八、总结
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

幻兽帕鲁服务器Palworld游戏怎么更新?

自建幻兽帕鲁服务器进入Palworld游戏提示“您正尝试加入的比赛正在运行不兼容的游戏版本&#xff0c;请尝试升级游戏版本”什么原因&#xff1f;这是由于你的客户端和幻兽帕鲁服务器版本不匹配&#xff0c;如何解决&#xff1f;更新幻兽帕鲁服务器即可解决。阿里云百科aliyunba…

【Android】高仿京东三级类型列表Demo

本demo基于二级分类双列表联动Demo进行了改进&#xff0c;高仿实现了京东的三级类型列表。 京东的如图&#xff1a; 本demo的&#xff1a; 改进之处 实现了三级列表联动&#xff0c;二三级列表之间的滑动监听优化了一下&#xff0c;将二级类型选中交予自身的点击事件&#…

prometheus和alertmanager inhibit_rules抑制的使用

172.16.10.21 prometheus 172.16.10.33 altermanager 172.16.10.59 mysql服务&#xff0c;node探针以及mysql的探针 [rootk8s-node02 ~]# docker ps -a CONTAINER ID IMAGE …

asp.net core通过读取配置文件来动态生成接口

如果希望接口是每次通过配置文件生成的,这样设计一些低代码的方式来获得接口。 系统目录结构: 启动配置代码: using Microsoft.AspNetCore.Hosting; using System.Configuration; using System.Data.Entity; using Swashbuckle.AspNetCore.SwaggerGen; using System.Refle…

第94讲:MySQL主从复制过滤复制的概念以及使用

文章目录 1.主从复制过滤复制的概念2.通过从库层面实现过滤复制2.1.从库过滤复制的参数2.2.配置过滤复制2.3.验证复制的准确性 1.主从复制过滤复制的概念 在MySQL主从复制集群中&#xff0c;既可以对全库进行主从复制&#xff0c;也可以对数据库实例中的某个数据库进行主从复制…

ShardingSphere 相关实践

实现水平分表 同一个数据库&#xff0c;多个表&#xff0c;把数据分到多个表里面环境&#xff1a;spring boot 2.3.2.RELEASE create database course_db;use course_db;create table course_1 (cid bigint(20) primary key ,cname varchar(50) not null,user_id bigint(20) …

机器学习---可能近似正确(PAC)、出错界限框架

1. 计算学习理论概述 从理论上刻画了若干类型的机器学习问题中的困难和若干类型的机器学习算法的能力 这个理论要回答的问题是&#xff1a; 在什么样的条件下成功的学习是可能的&#xff1f; 在什么条件下某个特定的学习算法可保证成功运行&#xff1f; 这里考虑两种框架&…

Java后端须知的前端知识

Java后端须知的前端知识 HTML &#xff08;超文本标记语言&#xff09; W3C标准 结构&#xff1a;HTML表现&#xff1a;CSS行为&#xff1a;JavaScript 快速入门 <html><head><title></title></head><body><font color"red&q…

无人机除冰保障电网稳定运行

无人机除冰保障电网稳定运行 近日&#xff0c;受低温雨雪冰冻天气影响&#xff0c;福鼎市多条输配电线路出现不同程度覆冰。 为保障福鼎电网安全可靠运行&#xff0c;供电所员工运用无人机飞行技术&#xff0c;通过在无人机下方悬挂器具&#xff0c;将无人机飞到10千伏青坑线…

代码随想录算法训练营第二十二天 |235. 二叉搜索树的最近公共祖先,701.二叉搜索树中的插入操作,450.删除二叉搜索树中的节点(待补充)

235.二叉搜索树的最近公共祖先 1、题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 2、文章讲解&#xff1a;代码随想录 3、题目&#xff1a; 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 百度百科中最近公…

序列化流 ObjectInputStream 和 ObjectOutputStream 的基本使用【 File类+IO流知识回顾④】

序列化流 ObjectInputStream 和 ObjectOutputStream 的基本使用【 File类IO流知识回顾④】 序列化流序列化和反序列化如何实现序列化ObjectOutputStreamObjectInputStream 序列化流 什么是序列化&#xff1f;如何实现序列化&#xff1f;什么是反序列化&#xff1f;需要了解的类…

使用 Python 进行自然语言处理第 3 部分:使用 Python 进行文本预处理

一、说明 文本预处理涉及许多将文本转换为干净格式的任务&#xff0c;以供进一步处理或与机器学习模型一起使用。预处理文本所需的具体步骤取决于具体数据和您手头的自然语言处理任务。 常见的预处理任务包括&#xff1a; 文本规范化——将文本转换为标准表示形式&#xff0c;…

JVM篇----第十八篇

系列文章目录 文章目录 系列文章目录前言一、什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”?二、对象分配规则三、描述一下JVM加载class文件的原理机制?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到…

《Lua程序设计》-- 学习9

迭代器和泛型for 迭代器和闭包 迭代器&#xff08;iterator&#xff09;是一种可以让我们遍历一个集合中所有元素的代码结构。在Lua语言中&#xff0c;通常使用函数表示迭代器&#xff1a;每一次调用函数时&#xff0c;函数会返回集合中的“下一个”元素。 一个闭包就是一个…

Kotlin快速入门系列9

Kotlin对象表达式和对象声明 对象表达式 有时&#xff0c;我们想要创建一个对当前类有些许修改的对象同时又不想重新声明一个子类。如果是Java&#xff0c;可以用匿名内部类的概念来解决这个问题。kotlin的对象表达式和对象声明就是为了实现这一点(创建一个对某个类做了轻微改…

我们距离AGI还有多远

什么是AGI AGI&#xff08;人工通用智能&#xff09;是指能够像人类一样完成任何智能任务的人工智能系统。AGI的目标是创建一个全面智能的系统&#xff0c;可以解决广泛的问题并进行多种任务。这种系统能够在不同的环境中适应和学习&#xff0c;并且可以从不同的来源中获取信息…

Flink实战四_TableAPISQL

接上文&#xff1a;Flink实战三_时间语义 1、Table API和SQL是什么&#xff1f; 接下来理解下Flink的整个客户端API体系&#xff0c;Flink为流式/批量处理应用程序提供了不同级别的抽象&#xff1a; 这四层API是一个依次向上支撑的关系。 Flink API 最底层的抽象就是有状态实…

JAVA处理类似饼状图占比和100%问题,采用最大余额法

前言&#xff1a; 在做数据统计报表的时候&#xff0c;有两种方式解决占比总和达不到100%或者超过100%问题。 第一种方式是前端echart图自带的算分框架。 第二种方式是java后端取处理这个问题。 现存问题&#xff1a; 前端不通过饼状图的方式去展示各个分类的占比累加和为100%问…

CESS 激励测试网 v0.7.6 将于1月31日上线

Cumulus Encrypted Storage System (CESS) 是基于区块链的去中心化云存储网络和 CDN 网络&#xff0c;支持数据在线存储和实时共享&#xff0c;为 Web3 高频动态数据的存储和检索提供全栈解决方案。 CESS 数据价值网络是以 DePIN 理念建设的 Layer 1 基础设施&#xff0c;具有…

SAP下载word

事务代码&#xff1a;STRANS 启动转换器 步骤 1. 将参数填入模板&#xff0c;并另存为word 2003 xml文档 2.使用网页打开xml文档&#xff0c;并将xml拷贝到转换器tt:template中&#xff0c;添加参数 3.替换参数&#xff0c;部分xml可能存在错误或者跑偏根据实际情况检查修改 …