【正点原子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 divider000: f(LSI) / 4001: f(LSI) / 8010: f(LSI) / 16011: f(LSI) / 32100: f(LSI) / 64101: f(LSI) / 128110: f(LSI) / 256111: 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 writing0x5555 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句柄的寄存器基地址为IWDGg_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);     // 设置时钟为72MHzdelay_init(72);                         // 延时初始化usart_init(115200);                     // 串口初始化为115200printf("您还没喂狗,请及时喂狗!!!\r\n");  // 打印提示信息iwdg_init(IWDG_PRESCALER_32, 1250);     // 预分频系数为32,重装载值为1250,溢出时间约为1swhile (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。
在这里插入图片描述
八、总结
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

相关文章

【脑电信号处理与特征提取】P5-彭薇薇:脑电信号的预处理及数据分析要点

彭薇薇&#xff1a;脑电信号的预处理及数据分析要点 脑电 脑电是神经活动的测量方法&#xff0c;在不同位置测量有不同的方法。比如大脑皮层表面测量的是ECoG&#xff0c;在头皮测量的是EEG。除了EEG是无损的&#xff0c;其他都是有损的。 脑电信号采集系统 下面是完整的…

泰迪智能科技生成式人工智能(AIGC)实验室解决方案

AIGC&#xff08;Artificial Intelligence Generated Content&#xff0c;生成式人工智能&#xff09;是一种新的人工智能技术&#xff0c;指的是利用人工智能技术来生成内容。这种技术可以自动生成文本、图像、音频和视频等多种类型的内容&#xff0c;而且内容的质量较高&…

elasticsearch在ubuntu下的配置以及简单使用

参考资料 官方下载地址 ELK学习实验002&#xff1a;Elasticsearch介绍及单机安装 ElasticSearch (ES从入门到精通一篇就够了) 前言 警告&#xff1a;elasticsearch默认不允许使用root账号来运行的&#xff0c;所以&#xff0c;强烈建议一开始就创建一个账号例如&#xff1a;…

Java关于Excel文件的导入导出

人生如梦 荣华富贵 如木槿之花 朝荣夕逝 需求 导出&#xff1a; 能够将库表内的数据导出多个Excel表&#xff0c;并且生成一个压缩包&#xff0c;提供用户下载导入&#xff1a; 能够将一个压缩包内的多个Excel表解压&#xff0c;并获取表内的所有数据 FileUtils 工具类 publi…

【开发】长期项目与代码质量,对抗软件工程复杂度(设计、重构、规范)

【开发】长期项目与代码质量&#xff0c;对抗软件工程复杂度&#xff08;设计、重构、规范&#xff09; 文章目录 一、设计模式与设计原则二、历史债务与代码重构1、技术债务的来源2、重构—无奈之举3、工程一致性&#xff1a;有效控制技术债务积累的主要手段 一、设计模式与设…

基于ssm和微信小程序的健身房私教预约管理系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…

Postman-接口测试教程

接口是软件开发中常用的概念&#xff0c;是软件生产过程中比较核心的任务。对于接口开发者&#xff0c;调试接口是一件较为繁琐的事情&#xff0c;很多时候需要线上线下来回切换。在这里&#xff0c;我就跟大家介绍一个只需要在本地就可以调试接口的方法&#xff0c;即使用post…

java大文件分片上传

1.效果图 2.前端html <!DOCTYPE html> <html> <head></head> <body> <form><input type"file" id"fileInput" multiple><button type"button" onclick"upload()" >大文件分片上传&l…

计算机网络_1.3电路交换、分组交换和报文交换

1.3电路交换、分组交换和报文交换 一、电路交换1、“电路交换”例子引入2、电路交换的三个阶段3、计算机之间的数据传送不适合采用电路交换 二、分组交换1、发送方&#xff08;1&#xff09;报文&#xff08;2&#xff09;分组&#xff08;3&#xff09;首部 2、交换节点3、接收…

LeetCode 使循环数组所有元素相等的最少秒数

地址&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 难度&#xff1a;中等 题目描述&#xff1a;给你一个下标从 0 开始长度为 n 的数组 nums 。 每一秒&#xff0c;你可以对数组执行以下操作&#xff1a; 对于范围在 [0, n - 1] 内的每…

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

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

深入理解二叉树:遍历、构建与性质探索的代码实现

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构冒险记 ✅C语言进阶之路 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 文章目录 前言一、二叉树的存储结构二、二叉树链式结构的实现三、二叉树的前、中、后续遍历&…

【数据结构 07】AVL树

目录 一、二叉搜索树 二、AVL树 2.1 左单旋 2.2 右单旋 2.3 左右双旋 2.4 右左双旋 三、AVL.h 四、test.cpp 一、二叉搜索树 二叉搜索树&#xff0c;又称二叉排序树&#xff08;Binary Search Tree&#xff09;&#xff0c;相比于普通二叉树&#xff0c;BST的特性有&a…

UE5 C++ 读取本地图片并赋值到UI上

目录 结果图 节点样式 主要代码 调试代码 结果图 节点样式 主要代码 &#xff08;注释纯属个人理解&#xff0c;可能存在错误&#xff09; // Fill out your copyright notice in the Description page of Project Settings.#pragma once#include "CoreMinimal.h&q…

Java面向对象详解

面向对象和面向过程的区别&#xff1a; 面向对象和面向过程都是对软件分析、设计和开发的一种思想&#xff0c;它指导着人们以不同的方式去分析、设计和开发软件。C语言是一种典型的面向过程语言&#xff0c;Java是一种典型的面向对象语言。 面向过程适合简单、不需要协作的事务…

Optimism的挑战期

1. 引言 前序博客&#xff1a; Optimism的Fault proof 用户将资产从OP主网转移到以太坊主网时需要等待一周的时间。这段时间称为挑战期&#xff0c;有助于保护 OP 主网上存储的资产。 而OP测试网的挑战期仅为60秒&#xff0c;以简化开发过程。 2. OP与L1数据交互 L1&#xf…

探索智能巡检机器人深度学习的奥秘

机器人深度学习&#xff08;Robot Deep Learning&#xff09;是指利用深度学习技术&#xff0c;使机器人能够从大量数据中学习和提取特征&#xff0c;进而实现自主感知、决策和行动的能力。通过深度学习算法&#xff0c;机器人可以从传感器获取的数据中自动学习模式和规律&…

微信开放平台第三方开发,实现代小程序认证申请

大家好&#xff0c;我是小悟 微信小程序认证整体流程总共分为五个环节&#xff1a;认证信息填写、平台初审、管理员验证、供应商审核和认证成功。 服务商可以代小程序发起认证申请。平台将对认证基础信息进行初步校验。通过后&#xff0c;平台将向管理员微信下发模板消息&…

Redis(十)SpringBoot集成Redis

文章目录 连接单机mvnYMLController.javaRedisConfig.java 连接集群YML问题复现 RedisTemplate方式 连接单机 mvn <!--Redis--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</art…

SRC实战 | 信息泄露挖掘

本文由掌控安全学院 - 叴龙 投稿 1. 信息搜集 首先老语法先搜集一波&#xff0c;毕竟没有钓鱼和sg的能力&#xff0c;只能找注册站去挖挖了。 web.title”XX大学”&&web.body”忘记密码”&&web.body”注册” 2. 漏洞挖掘 这里找到一个可以注册网站接口&…