stm32f10x独立看门狗
Posted 旭日初扬
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了stm32f10x独立看门狗相关的知识,希望对你有一定的参考价值。
目录
独立看门有自己的时钟LSI(内部低速时钟),不存在使能问题,但固件库还是提供LSI的使能函数
(1)IWDG相关库函数在stm32f10x_iwdg.c和stm32f10x_iwdg.h文件中
(3)重载计数器值(喂狗)给IWDG_KR寄存器写入0xAAAA
(4)开启IWDG(给IWDG_KR寄存器写入0xCCCC)
一、IWDG介绍
1.1、独立看门狗简介
- STM21F1芯片内部含有两个看门狗外设,独立看门狗(IWDG)与窗口看门狗(WWDG)。
- 两个看门狗都可以用于检测并解决由软件错误导致的故障。
- 独立看门狗可以简单的理解为一个12位的递减计数器,当计数器从某个值递减到0时(如果看门狗已激活),那么系统会产生一次复位。
- 如果在计数器递减到0之前刷新了计数器值,那么系统就不会产生复位。
- 这个刷新计数器值得过程称为“喂狗”。
- 独立看门狗功能由VDD电压域供电,在停止模式和待机模式下仍能工作。
1.2、IWDG结构框图
- LSI:内部低速时钟,频率约在30~60KHz之间 仅适用于时间精度较低的场合,即便在主时钟发生 故障时仍然保持工作状态。
- 8 位预分频寄存器 IWDG_PR :LSI 时钟并不是直接提供给计数器时钟,而是通过一个 8 位预分频寄存器 IWDG_PR 分频后输入给计数器时钟。操作 IWDG_PR 寄存器来设置分频因子。8位预处理器(寄存器):分频因子有2,4,8,16,32,64,128,256。分频后的计数器时钟为:CK_CNT= 40/ 4*2^PRE,PRE 为预分频系数(0-6),4*2^PRE 大小就是 4、8、16、32、64、128、256 值。每经过一个计数器时钟, 计数器就减 1。
- 12位递减计数器:独立看门狗的计数器是一个 12 位的递减计数器,计数最大值为 0XFFF,当递减到 0 时,会产生一个复位信号,让系统重新启动运行,如果在计数器减到 0
之前刷新了计数器值的话,就不会产生复位信号,这个刷新计数器值过程称 之为“喂狗”。
- 12位 重加载数值:重装载寄存器是一个 12 位的寄存器,里面装着要刷新到计数器的值,这个值的大小决定着独立看门狗的溢出时间。溢出时间 Tout = (4*2^pre) / 40 * rlr
(ms), pre 是预分频器系数(0-6),rlr 是重装载寄存器的值,公式内的 40 是 独立看门狗的时钟。 比如设置 pre=4,rlr=800,那么独立看门狗溢出时间是 1280ms,也就是说如果在 1280ms 内没有进行喂狗,那么系统将进行重启,即程序重新开始运行
- 键寄存器(IWDG_KR)又称关键字寄存器或密钥寄存器(IWDG_KR)。此寄存器可以说 是 IWDG 的一个控制寄存器。往该寄存器写入三种值会有三种控制效果:
- ①写入 0X5555,由于 IWDG_PR 和 IWDG_RLR 寄存器具有写访问保护。若要 修改寄存器,必须首先对 IWDG_KR 寄存器写入代码 0x5555。若写入其他值将重 启写保护。
- ②写入 0XAAAA,把 IWDG_RLR 寄存器内值重装载到计数器中。
- ③写入 0XCCCC,启动 IWDG 功能。此方式属于软件启动,一旦开启独立看门 狗,它就关不掉,只有复位才能关掉IWDG的控制寄存器
- 状态寄存器 IWDG_SR 只有位 0: PVU 和位 1: RVU 有效,这两位只能由硬件操作。RVU:看门狗计数器重装载值更新,硬件置 1 表示重装载值的更新正在进行中,更新完毕之后由硬件清 0。 PVU: 看门狗预分频值更新,硬件置 1 表示预分频值的更新正在进行中,当更新完成后,由硬件清 0。所以只有当 RVU/PVU 等于 0 的时候才可以更新重装载寄存器/预分频寄存器
二、IWDG配置
独立看门有自己的时钟LSI(内部低速时钟),不存在使能问题,但固件库还是提供LSI的使能函数
RCC_LSICmd(ENABLE); //
while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY)==0){} // 复位LSE振荡器时钟
/**
* @brief Enables or disables the Internal Low Speed oscillator 振荡器(LSI). 使能或失能内部低速时钟
* @note LSI can not be disabled if the IWDG is running. 注意:当IWDG处于运行状态时,无法禁用LSI。
* @param NewState: new state of the LSI. This parameter can be: ENABLE or DISABLE.
* @retval None
*/
void RCC_LSICmd(FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_FUNCTIONAL_STATE(NewState));
*(__IO uint32_t *) CSR_LSION_BB = (uint32_t)NewState;
}
内部低速时钟开启为的别名地址
#define CSR_LSION_BB (PERIPH_BB_BASE + (CSR_OFFSET * 32) + (LSION_BitNumber * 4))
#define PERIPH_BB_BASE ((uint32_t)0x42000000) /*!< Peripheral base address in the bit-band region */ 位带区域内的外围基地地址
#define CSR_OFFSET (RCC_OFFSET + 0x24)
/* ------------ RCC registers bit address in the alias region ----------- */ RCC在别名区域寄存器位地址
#define RCC_OFFSET (RCC_BASE - PERIPH_BASE)#define LSION_BitNumber 0x00
(1)IWDG相关库函数在stm32f10x_iwdg.c和stm32f10x_iwdg.h文件中
开启寄存器访问(给IWDG_KP寄存器写入0x5555)
IWDG_WriteAccesscmd(IWDG_WriteAccess_Enable); // 取消寄存器写保护
/**
* @brief Enables or disables write access to IWDG_PR and IWDG_RLR registers. 失能或使能独立看门狗的预分频寄存器和独立看门狗重装载寄存器的写访问
* @param IWDG_WriteAccess: new state of write access to IWDG_PR and IWDG_RLR registers. 独立看门狗的预分频寄存器与独立看门狗重装载寄存器 写访问的新状态
* This parameter can be one of the following values:
* @arg IWDG_WriteAccess_Enable: Enable write access to IWDG_PR and IWDG_RLR registers
* @arg IWDG_WriteAccess_Disable: Disable write access to IWDG_PR and IWDG_RLR registers
* @retval None
*/
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess)
{
/* Check the parameters */
assert_param(IS_IWDG_WRITE_ACCESS(IWDG_WriteAccess)); assert_param宏 拥有检测函数的参数
IWDG->KR = IWDG_WriteAccess; IWDG的KR(健存寄存器) 的0~15位写入0x5555 (0101 0101 0101 0101) 表示允许操作IWDG_PR与IWDG_RLR 即取消寄存器写保护
}
#define IWDG_WriteAccess_Enable ((uint16_t)0x5555) // 取消写保护
#define IWDG_WriteAccess_Disable ((uint16_t)0x0000) // 写保护
#define IS_IWDG_WRITE_ACCESS(ACCESS) (((ACCESS) == IWDG_WriteAccess_Enable) || \\
((ACCESS) == IWDG_WriteAccess_Disable))
(2)设置IWDG预分频系数和重装载值
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler ) // 设置预分频的值
void IWDG_SetReload(uint16_t Reload); // 设置重装载的值
Tout =(4*2^pre)/40*rlr
Tout独立看门狗的溢出时间,单位:ms。pre是预分频系数(0-6),rlr是重装载寄存器的值,
公式内的40是独立看门狗的时钟。
比如设置 pre=4,rlr=800,那么独立看门狗溢出时间是 1280ms,
只要在 1280ms 之内,有一次写入 0XAAAA 到 IWDG_KR,就不会导致看门狗复位
看门狗的时钟不是准确的40Khz,所以在喂狗的时候,最好不要太晚了,否则,有可能发生看门狗复位
/**
* @brief Sets IWDG Prescaler value. 设置预分频寄存器的值
* @param IWDG_Prescaler: specifies the IWDG Prescaler value.
* This parameter can be one of the following values: 4 8 16 32 64 128 256
* @arg IWDG_Prescaler_4: IWDG prescaler set to 4
* @arg IWDG_Prescaler_8: IWDG prescaler set to 8
* @arg IWDG_Prescaler_16: IWDG prescaler set to 16
* @arg IWDG_Prescaler_32: IWDG prescaler set to 32
* @arg IWDG_Prescaler_64: IWDG prescaler set to 64
* @arg IWDG_Prescaler_128: IWDG prescaler set to 128
* @arg IWDG_Prescaler_256: IWDG prescaler set to 256
* @retval None
*/
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler)
{
/* Check the parameters */
assert_param(IS_IWDG_PRESCALER(IWDG_Prescaler));
IWDG->PR = IWDG_Prescaler; 预分频寄存器
}
/**
* @brief Sets IWDG Reload value. 独立看门狗重装载的值
* @param Reload: specifies the IWDG Reload value. 设置独立看门狗重装载的值
* This parameter must be a number between 0 and 0x0FFF. 参数的取值范围0 ~ 0x0FFF
* @retval None
*/
void IWDG_SetReload(uint16_t Reload)
{
/* Check the parameters */
assert_param(IS_IWDG_RELOAD(Reload));
IWDG->RLR = Reload;
}
(3)重载计数器值(喂狗)给IWDG_KR寄存器写入0xAAAA
IWDG_ReloadCounter();
/**
* @brief Reloads IWDG counter with value defined in the reload register
* (write access to IWDG_PR and IWDG_RLR registers disabled).
* @param None
* @retval None
*/
void IWDG_ReloadCounter(void)
{
IWDG->KR = KR_KEY_Reload;
}
/* KR register bit mask */
#define KR_KEY_Reload ((uint16_t)0xAAAA)
#define KR_KEY_Enable ((uint16_t)0xCCCC)
(4)开启IWDG(给IWDG_KR寄存器写入0xCCCC)
IWDG_Enable();
/**
* @brief Enables IWDG (write access to IWDG_PR and IWDG_RLR registers disabled).
* @param None
* @retval None
*/
void IWDG_Enable(void)
{
IWDG->KR = KR_KEY_Enable;
}
四、编写独立看门狗
#include "iwdg.h"
/*******************************************************************************
* 函 数 名 : IWDG_Init
* 函数功能 : IWDG初始化
* 输 入 : pre:预分频系数(0-6)
rlr:重装载值(12位范围0xfff)
独立看门狗复位时间计算公式:t=(4*2^pre*rlr)/40
* 输 出 : 无
*******************************************************************************/
void IWDG_Init(u8 pre,u16 rlr)
{
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //取消寄存器写保护
IWDG_SetPrescaler(pre);//设置预分频系数 0-6
IWDG_SetReload(rlr);//设置重装载值
IWDG_ReloadCounter(); //重装载初值
IWDG_Enable(); //打开独立看门狗
}
/*******************************************************************************
* 函 数 名 : IWDG_FeedDog
* 函数功能 : 喂狗
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void IWDG_FeedDog(void) //喂狗
{
IWDG_ReloadCounter(); //重装载初值
}
头文件
#ifndef _iwdg_H
#define _iwdg_H
#include "system.h"
void IWDG_Init(u8 pre,u16 rlr);
void IWDG_FeedDog(void); //喂狗
#endif
主函数
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h"
#include "key.h"
#include "iwdg.h"
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
int main()
{
u8 i=0;
SysTick_Init(72); // 9M
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组 分2组
LED_Init();
USART1_Init(115200); // 串口通信波特率
KEY_Init();
IWDG_Init(4,800); //只要在1280ms内进行喂狗就不会复位系统
LED2=1;
printf("复位系统\\r\\n");
while(1)
{
if(KEY_Scan(0)==KEY_UP_PRESS)
{
IWDG_FeedDog();//喂狗
LED2=0;
printf("喂狗\\r\\n");
}
i++;
if(i%20==0)
{
LED1=!LED1;
}
delay_ms(10); // 200ms
}
}
以上是关于stm32f10x独立看门狗的主要内容,如果未能解决你的问题,请参考以下文章