单片机入门学习十二 STM32单片机学习九 看门狗

看到 ‘看门狗’ 这个词对于刚入门的人来说是个很新鲜的词,那么什么是看门狗呢?
看门狗的作用就是监控程序运行是否异常,在程序出现异常进入死循环的时候,可以自动系统复位,保证程序正常运行。
出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测单片机程序运行状态的模块或者芯片,俗称“看门狗”(watchdog) 。

STM32内置了两个看门狗,1个是独立看门狗、1个是窗口看门狗,现我们先列举一下这两个看门狗的异同,再分别做详细的介绍。

1、概述

1)独立看门狗

独立看门狗(IWDG)由内部专门的40Khz低速时钟(LSI)驱动,即使主时钟发生故障它仍有效。
独立看门狗适合应用于需要看门狗作为一个在主程序之外 能够完全独立工作,并且对时间精度要求低的场合。

2)窗口看门狗

窗口看门狗由从APB1时钟分频后得到时钟驱动。通过可配置的时间窗口来检测应用程序非正常的过迟或过早操作。
窗口看门狗最适合那些要求看门狗在精确计时窗口起作用的程序,通常被用来监测由外部干扰或不可预见的逻辑条件造成的应用程序背离正常的运行序列而产生的软件故障。

2、二者区别

窗口看门狗最适合那些要求看门狗在精确计时窗口起作用的程序。
1)独立看门狗没有中断,窗口看门狗有中断
2)独立看门狗有硬件软件之分,窗口看门狗只能软件控制
3)独立看门狗只有下限,窗口看门狗有下限和上限
4)独立看门狗是12位递减的。窗口看门狗是7位递减的
5)独立看门狗是用的内部的大约40KHZ RC振荡器,窗口看门狗是用的系统时钟APB1ENR

3、详细介绍

1)独立看门狗

独立看门狗

上图是独立看门狗的框图,我们看一下独立看门狗如何工作
①往键寄存器(IWDG_KR)中写入0xCCCC,开启独立看门狗,开启独立看门狗后,计数器开始从其复位值0xFFF递减
②当计数器值计数到尾值0x000时会产生一个复位信号(IWDG_RESET)
③无论什么时候,在键寄存器(IWDG_KR)中写入0xAAAA(通常说的喂狗),自动重装寄存器(IWDG_RLR)的值就会重新加载到计数器,从而避免看门狗复位。
④如果程序异常,就无法正常喂狗,从而系统复位。

独立看门狗寄存器介绍
①IWDG_KR键寄存器
IWDG_KR
②IWDG_RLR重装载寄存器
IWDG_RLR
③IWDG_PR预分频寄存器
IWDG_PR

预分频值如何确定?说到该值我们应该知道独立看门狗的超时时间如何计算?
看门狗超时时间公式如下:
Tout=42prerrlr40ms
该公式中
prer:预分频系数0、1、2…6,下图中的PR[2:0]位
rlr:IWDG_RLR中的重装载值

prer与rlr确定示例:
如果要求独立看门狗IWDG 超时复位时间是1s,则Tout=1s,若prer=0,则rlr=10000;若prer=2,则rlr=625(十进制),其16进制是0x271

预分频系数

上图的输入时钟频率LSI=40Khz,公式的分子才是40。实际上,MCU内部的RC频率会在30KHz到60Khz之间变化。
最长超时时间=IWDG_RLR寄存器最大值0xFFF 算出的

④IWDG_SR状态寄存器
IWDG_SR

从上可以看出:
键值寄存器IWDG_KR: 0~15位有效,用于启动看门狗、喂狗
预分频寄存器IWDG_PR:0~2位有效,用于设置预分频,具有写保护功能,要操作先取消写保护。
重装载寄存器IWDG_RLR:0~11位有效,用于设置计数初值,具有写保护功能,要操作先取消写保护。
状态寄存器IWDG_SR:0~1位有效

独立看门狗编程步骤
① 取消寄存器写保护:
IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess););//取消写保护:0x5555使能
② 设置独立看门狗的预分频系数,确定时钟:
IWDG_SetPrescaler(uint8_t IWDG_Prescaler);//设置预分频系数:写PR
③ 设置看门狗重装载值,确定溢出时间:
IWDG_SetReload(uint16_t Reload);//设置重装载值:写RLR
④ 使能看门狗
IWDG_ReloadCounter(void);//喂狗:写0xAAAA到KR
⑤ 应用程序喂狗:
IWDG_Enable(void);//使能看门狗:写0xCCCC到KR

独立看门狗常用库函数
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)窗口看门狗

使用窗口看门口的优势:对于一般的看门狗,程序可以在它产生复位前的任意时刻刷新看门狗,但这有一个隐患,有可能程序跑乱了又跑回到正常的地方,或跑乱的程序正好执行了刷新看门狗操作,这样的情况下一般的看门狗就检测不出来了;
  如果使用窗口看门狗,程序员可以根据程序正常执行的时间设置刷新看门狗的一个时间窗口,保证不会提前刷新看门狗也不会滞后刷新看门狗,这样可以检测出程序没有按照正常的路径运行非正常地跳过了某些程序段的情况。

窗口看门狗如何工作,请看下面:
窗口看门狗
看门狗时序图

应用程序在正常运行过程中必须定期地写入WWDG_CR寄存器以防止MCU发生复位。只有当计数器值小于窗口寄存器的值时,才能进行写操作。储存在WWDG_CR寄存器中的数值必须在0xFF和0xC0之间:

  • 启动看门狗WWDG_CR
    在系统复位后,看门狗总是处于关闭状态,设置WWDG_CR寄存器的WDGA位能够开启看门狗,随后它不能再被关闭,除非发生复位。
  • 控制递减计数器 WWDG_CNT
    递减计数器处于自由运行状态,即使看门狗被禁止,递减计数器仍继续递减计数。当看门狗被启用时,T6位必须被设置,以防止立即产生一个复位。 T[5:0]位包含了看门狗产生复位之前的计时数目;复位前的延时时间在一个最小值和一个最大值之间变化,这是因为写入WWDG_CR寄存器时,预分频值是未知的。 配置寄存器(WWDG_CFR) 中包含窗口的上限值:要避免产生复位,递减计数器必须在其值小于窗口寄存器的数值并且大于0x3F时被重新装载,0描述了窗口寄存器的工作过程。 另一个重装载计数器的方法是利用早期唤醒中断(EWI)。设置WWDG_CFR寄存器中的WEI位开启该中断。当递减计数器到达0x40时,则产生此中断,相应的中断服务程序(ISR)可以用来加载计数器以防止WWDG复位。在状态寄存器(WWDG_SR)中写’0’可以清除该中断。 注: 可以用T6位产生一个软件复位(设置WDGA位为’1’,T6位为’0’)。

看门狗框图举例说明
1)若WWDG_CR=0x60(0x01100000),递减计数器值为 0x60,即T6=1、T5=1、T4到T0为0,当递减计数器递减到0x3F,即T6=0时,看图知 会产生复位信号
解释
2)若WWDG_CFR=0x250(0x001001010000),即W6:0值为0x50,即在递减计数器值(T6:0)> W6:0 时,让WWDG_CR的第7位WDGA为1,则 也会产复位信号
复位信号

总结:
STM32F的窗口看门狗中有一个7位的递减计数器T[6:0],它会在出现下述2种情况之一时产生看门狗复位:

  • 当喂狗的时候如果计数器的值大于某一设定数值W[6:0]时,此设定数值在WWDG_CFR寄存器定义。
  • 当计数器的数值从0x40减到0x3F时【T6位跳变到0】 。

如果启动了看门狗并且允许中断,当递减计数器等于0x40时产生早期唤醒中断(EWI),它可以用于喂狗以避免WWDG复位。

窗口看门狗超时公式解释
Twwdg=40962WDGTB(T[5:0]+1)Fpclk1ms
其中:
Twwdg:WWDG超时时间(单位为ms)
Fpclk:APB1的时钟频率(单位为Khz)
WDGTB:WWDG的预分频系数
T[5:0]:窗口看门狗的计数器低6位

窗口看门狗寄存器
①WWDG_CR控制寄存器
WWDG_CR

该寄存器相关的库函数:
void WWDG_Enable(uint8_t Counter);//启动并设置初始值
void WWDG_SetCounter(uint8_t Counter);//喂狗

②WWDG_CRF配置寄存器
WWDG_CRF

该寄存器相关的库函数:
void WWDG_EnableIT(void);//使能提前唤醒中断
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler);//设置预分频系数
void WWDG_SetWindowValue(uint8_t WindowValue);//设置窗口上限

③ WWDG_SR状态寄存器
WWDG_SR

该寄存器相关的库函数:
FlagStatus WWDG_GetFlagStatus(void);
void WWDG_ClearFlag(void);

窗口看门狗编程步骤
① 使能看门狗时钟:
RCC_APB1PeriphClockCmd();
② 设置分频系数:
WWDG_SetPrescaler();
③ 设置上窗口值:
WWDG_SetWindowValue();
④ 开启提前唤醒中断并分组(可选):
WWDG_EnableIT();
NVIC_Init();
⑤ 使能看门狗:
WWDG_Enable();
⑥ 喂狗:
WWDG_SetCounter();
⑦编写中断服务函数
WWDG_IRQHandler();

3、示例程序

1)独立看门狗
//初始化独立看门狗
//prer:分频数:0~7(只有低3位有效!)
//分频因子=4*2^prer.但最大值只能是256!
//rlr:重装载寄存器值:低11位有效.
//时间计算(大概):Tout=((4*2^prer)*rlr)/40 (ms).
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
}
//喂独立看门狗
void IWDG_Feed(void)
{   
    IWDG_ReloadCounter();//reload                                          
}
//该程序思路是 按WKU_PRES按键进行喂狗,则程序不会复位,LED一直亮,否则程序会自动复位,看到的现象是LED灯在闪烁
int main(void)
{       
    delay_init();            //延时函数初始化    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);      //设置NVIC中断分组2:2位抢占优先级,2位响应优先级

    LED_Init();          //初始化与LED连接的硬件接口
    KEY_Init();          //按键初始化     

    IWDG_Init(4,625);    //与分频数为64,重载值为625,溢出时间为1s

    delay_ms(500);       //让人看得到灭
    LED0=0;              //点亮LED0

    while(1)
    {
        if(KEY_Scan(0)==WKUP_PRES)
        {
            IWDG_Feed();//如果WK_UP按下,则喂狗
        }
        delay_ms(10);
    };   
}
2)窗口看门狗
//保存WWDG计数器的设置值,默认为最大. 
u8 WWDG_CNT=0x7f; 
//初始化窗口看门狗  
//tr   :T[6:0],计数器值 
//wr   :W[6:0],窗口值 
//fprer:分频系数(WDGTB),仅最低2位有效 
//Fwwdg=PCLK1/(4096*2^fprer). 

void WWDG_Init(u8 tr,u8 wr,u32 fprer)
{ 
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);  //   WWDG时钟使能

    WWDG_CNT=tr&WWDG_CNT;   //初始化WWDG_CNT.   
    WWDG_SetPrescaler(fprer);设置IWDG预分频值

    WWDG_SetWindowValue(wr);//设置窗口值

    WWDG_Enable(WWDG_CNT);   //使能看门狗 ,  设置 counter .                  

    WWDG_ClearFlag();//清除提前唤醒中断标志位 

    WWDG_NVIC_Init();//初始化窗口看门狗 NVIC

    WWDG_EnableIT(); //开启窗口看门狗中断
} 
//重设置WWDG计数器的值
void WWDG_Set_Counter(u8 cnt)
{
    WWDG_Enable(cnt);//使能看门狗 ,  设置 counter .     
}
//窗口看门狗中断服务程序
void WWDG_NVIC_Init()
{
    NVIC_InitTypeDef NVIC_InitStructure;
    NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQn;    //WWDG中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   //抢占2,子优先级3,组2  
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;   //抢占2,子优先级3,组2 
  NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; 
    NVIC_Init(&NVIC_InitStructure);//NVIC初始化
}

void WWDG_IRQHandler(void)
{
    WWDG_SetCounter(WWDG_CNT);    //当禁掉此句后,窗口看门狗将产生复位
    WWDG_ClearFlag();     //清除提前唤醒中断标志位
    LED1=!LED1;      //LED状态翻转
}

//该程序的现象是 在中断中自动喂狗,程序不会复位,LED0先亮后灭,LED1闪烁
int main(void)
 {      
    delay_init();            //延时函数初始化    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级

    LED_Init(); 
    WWDG_Init(0X7F,0X5F,WWDG_Prescaler_8);//计数器值为7f,窗口寄存器为5f,分频数为8

    LED0=0;
    delay_ms(300);  

    while(1)
    {
        LED0=1;                
    }   
}
优秀的处理器配合好的开发工具和工具链成就了单片机的辉煌,这是单片机开发者辛勤劳动的结果。也正因为此,ARM的工具链工程师和CPU工程师强强联手,日日夜夜不停耕耘为ARM7TDMI设计出了精练、优化和到位的内部结构,终于成就了ARM7TDMI的风光无限的辉煌。新的ARMCortex-MB处理器在破茧而出之后,就处处闪耀着ARM体系结构激动人心的新突破。它是基于最新最好的32为ARMv7架构,支持高度成功的Thumb-2指令集,并带来了很多前卫崭新的特性。在它优秀,强大的同时,编程模型也更清爽,因而无论你是新手还是骨灰级玩家都会对这样秀外慧中的小尤物爱不释手。根据ARM的统计,2010年全部Cortex-MMCU出货量为1.44亿片,2008年~2011年第一季度,STM32累计出货量占Cortex-MMCU出货量的45%。也就是说,两个Cortex-M微控制器中有一个就来自ST。”很多市场分析机构也ARM的强劲增长表示认可。2007年在3264bitMCU及MPU架构中,ARM所占市场份额为13.6%,而2010年已经占了23.5%击败了PowerArchitecture,成为市场占有率最多的架构。Cortex-n3内核是ARM公司整个Cortex内核系列中的微控制器系列(M)内核还是其他两个系列分别是应用处理器系列(A)与实时控制处理系列(R),这三个系列又分别简称为A、R、M系列。当然,这三个系列的内核分别有各自不同的应用场合。Cortex-MB内核是为满足存储器和处理器的尺寸对产品成本影响很大的广泛市场和应用领域的低成本需求而专门开发设计的。主要是应用于低成本、小管脚数和低功耗的场合,并且具有极高的运算能力和极强的中断响应能力。Cortex-M3处理器采用纯Thumb2指令的执行方式,这使得这个具有32位高性能的ARM内核能够实现8位和16位的代码存储密度。核心门数只有3K,在包含了必要的外设之后的门数也只有60K,使得封装更为小型,成本更加低廉。Cortex-n3采用了ARMV7哈佛架构,具有带分支预测的3级流水线,中断延退最大只有12个时钟周期,在末尾连锁的时候只需要6个时钟周期。同时具有1.25DMIPS/MHZ的性能和0.19MW/MHZ的功耗。     社会对基于ARM的嵌入式系统开发人员的高需求及给予的高回报,催生了很多的培训机构,这也说明嵌入式系统的门槛较高,其主要原因有以下几点。ARM本身复杂的体系结构和编程模型,使得我们必须了解详细的汇编指令,熟悉ARM与Thumb状态的合理切换,才能理解Bootloader并对操作系统进行移植,而理解Bootloader本身就比较困难,因而对于初学者来说Bootloader的编写与操作系统的移植成了入门的第一道难以逾越的门槛2、ARM芯片,开发板及仿真器的高成本,这样就直接影响了嵌入式开发的普及,使得这方面人才增长缓慢;3、高校及社会上高水平嵌入式开发人员的短缺,现实问题使得我们的大学生和公司职工在入门的道路上困难重重,很多人也因此放弃;培训机构的高费用,虽然有高水平的老师指导,但是高费用就是一道关口,进去的人也只是在短短的几天时间里匆匆了解了一下开发过程,消除了一些畏惧心理而己,修行还是得依靠自己;5、好的开发环境需要资金的支持,也直接影响了入门的进度。基于Cortex-m3内核的ARM处理器的出现,在优秀的Kei开发工具的支持下,可以自动生成启动代码,省去了复杂的Bootloader的编写。Thumb-2指令集的使用,使得开发人员不用再考虑ARM状态与Thumb状态的切换,节省了执行时间和指令空间,大大减轻了软件开发的管理工作。处理器与内存尺寸的减少,大大降低了成本,使得芯片及开发板的价格得以在很大程度降低。Cortex-M3内核通过把中断控制器、MPU及各种调试组件等基础设施的地址固定很大程度上方便了程序的移植。源代码是公开的库函数,使得我们可以摒弃晦涩难懂的汇编语言,在不需要了解底层寄存器的操作细节的情况下,用C语言就可以完成我们需要的功能。所有这些特点使得我们学习ARM处理器的门槛得以降低。同时建议大家尽量去用固件库。而不是避开固件库自己写代码。因为在实际的项目中,代码成百上千个,不可能都自己来写,调用固件库中的函数来完成,才是可行的方案。当然我们在深入的情况下,透彻理解寄存器的操作是必要的,也是值得的,高效编程也必须在这方面努力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风水月

从心底相信自己是成功的第一步

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值