MSP430F5529 DriverLib 库函数学习笔记(十四)看门狗定时器 (WDT)

平台:Code Composer Studio 10.3.1
MSP430F5529 LaunchPad™ Development Kit
(MSP‑EXP430F5529LP)


硬知识

       在工业控制现场,往往会由于供电电源、空间电磁干扰或其他的原因引起强烈的干扰噪声。这些干扰作用于数字器件,极易使其产生误动作,引起单片机程序跑飞,若不进行有效的处理,程序就不能回到正常的运行状态。为了保证系统的正常工作,一方面要尽量减少干扰源对系统的影响;另一方面,在系统受到影响之后要能尽快地恢复,看门狗就起到了这个作用。看门狗的用法:在正常工作期间,一次看门狗定时时间将产生一次系统复位。如果通过编程使看门狗定时时间稍大于程序中主循环执行一遍所用的时间,并且程序执行过程中都有对看门狗定时器清零的指令,使计数值重新计数,程序正常运行时,就会在看门狗定时时间到达之前对看门狗清零,不会产生看门狗溢出。如果由于干扰使程序跑飞,则不会在看门狗定时时间到达之前执行看门狗清零指令,看门狗就会产生溢出,从而产生系统复位,使CPU重新运行用户程序,这样程序就又可以恢复正常运行。
       看门狗定时器具有如下特点:
 软件可编程的8种时间间隔选择;
 看门狗模式;
 定时计数模式;
 对看门狗控制寄存器更改受口令的保护,若口令输入错误,则控制寄存器无法更改;
 多种时钟源供选择;
 可选择关闭看门狗以减少功耗;
 时钟故障保护功能。
       MSP430单片机的看门狗定时器逻辑结构框图如图所示。由该图可知,MSP430单片机看门狗定时器由中断产生逻辑单元、看门狗定时计数器、口令比较单元、看门狗控制寄存器、参考时钟选择逻辑单元等构成。
在这里插入图片描述

看门狗定时计数器 (WDTCNT)

       看门狗定时计数器是一个32位增计数器,不能通过软件程序直接访问其计数值。软件可通过看门狗控制寄存器(WDTCTL)控制看门狗定时计数器及配置其产生的时间间隔。看门狗定时计数器的参考时钟源可通过WDTSSEL控制位配置为SMCLK、ACLK、VLOCLK或X_CLK,产生的时间间隔可通过WDTIS控制位选择,具体请参考相应寄存器配置。

看门狗模式

       在一个上电复位清除(PUC)后,看门狗定时器被默认配置为采用SMCLK作为参考时钟源,复位时间间隔约为32ms并工作在看门狗模式。用户必须在看门狗复位时间间隔期满或另一个复位信号产生之前,配置、停止或清除看门狗定时器。当看门狗定时器被配置工作在看门狗模式时,利用一个错误的口令密码操作看门狗控制寄存器(WDTCTL)或选择的时间间隔期满都将产生一个PUC复位信号,一个PUC复位信号可将看门狗定时器复位到默认状态。

定时计数模式

       将WDTTMSEL控制位选择为1,看门狗定时器被配置为定时计数模式。这个模式可以被用来产生周期性中断,在定时计数模式下,当选定的时间间隔到来时,将置位看门狗定时计数中断标志位(WDTIFG),但并不产生PUC复位信号。当看门狗定时计数中断允许控制位(WDTIE)和全局中断允许控制位(GIE)置位时,CPU将响应WDTIFG中断请求。中断请求被响应后,单片机将自动清除看门狗定时计数中断标志位,当然也可通过软件手动清除看门狗定时计数中断标志位。在定时计数模式下的中断向量地址不同于在看门狗模式下的中断向量地址,具体请参考MSP430单片机中断向量表。

看门狗定时器中断

       看门狗定时器利用以下两个寄存器控制看门狗定时器中断:
 看门狗中断标志位WDTIFG:位于SFRIFG1.0内;
 看门狗中断允许控制位WDTIE:位于SFRIE1.0内。
       当看门狗定时器工作在看门狗模式时,看门狗中断标志位WDTIFG来源于一个复位向量中断。复位中断服务程序可利用看门狗中断标志位WDTIFG来判定看门狗定时器是否产生了一个系统复位信号。若WDTIFG标志位置位,看门狗定时器产生一个复位条件,要么复位定时时间到,要么口令密码错误。
当看门狗定时器工作在定时计数模式时,当定时时间到,将置位看门狗中断标志位WDTIFG,若WTDIE和GIE都置位,则可响应看门狗定时计数中断。

时钟故障保护功能

       看门狗定时器提供了一个时钟故障保护功能,确保在看门狗模式下,参考时钟不失效,这就意味着低功耗模式将有可能影响看门狗定时器参考时钟的选择。如果SMCLK或ACLK作为定时器参考时钟源时失效,看门狗定时器将自动选择VLOCLK作为其参考时钟源。当看门狗定时器工作于定时计数模式时,看门狗定时器没有时钟故障保护功能。

低功耗模式下的看门狗操作

       MSP430单片机具有多种低功耗模式,在不同的低功耗模式下,启用不同的时钟信号。应用程序的需要及所选时钟的类型决定了看门狗定时器的配置,例如如果用户想用低功耗模式3(LPM3),就要避免看门狗定时器的参考时钟选择以DCO、高频模式下的XT1或XT2作为时钟源的SMCLK或ACLK。当不需要看门狗定时器时,可利用WDTHOLD控制位关闭看门狗计数器(WDTCNT),以减少单片机功耗。

看门狗定时器控制寄存器

看门狗定时器控制寄存器(WDTCTL)列表如表所示。
在这里插入图片描述

WDT_A API (机翻)

       看门狗定时器(WDT_A) API提供了一组使用MSP430Ware WDT_A模块的函数。提供了初始化看门狗定时器为定时计数模式或看门狗模式的函数,具有可选择的时钟源和分频器来设置定时器周期。
WDT_A模块在定时器定时计数模式下只能产生一种中断。在看门狗模式时,一旦定时器计数完成,WDT_A模块将产生一次复位。

WDT_A_hold(uint16_t baseAddress)
//暂停看门狗定时器
WDT_A_start(uint16_t baseAddress)
//启动看门狗定时器
WDT_A_resetTimer(uint16_t baseAddress)
//重置看门狗定时器的计数值
WDT_A_initWatchdogTimer(uint16_t baseAddress, uint8_t clockSelect, uint8_t clockDivider)
//以看门狗模式设置看门狗定时器的时钟源
WDT_A_initIntervalTimer(uint16_t baseAddress, uint8_t clockSelect, uint8_t clockDivider)
//以定时计数模式设置看门狗定时器的时钟源

参数

baseAddress

WDT_A_BASE

clockSelect

/*is the clock source that the watchdog timer will use. Valid values are:*/
WDT_A_CLOCKSOURCE_SMCLK /*[Default]*/
WDT_A_CLOCKSOURCE_ACLK
WDT_A_CLOCKSOURCE_VLOCLK
WDT_A_CLOCKSOURCE_XCLK
/*Modified bits are WDTSSEL of WDTCTL register.*/

clockDivider

/*is the divider of the clock source, in turn setting the watchdog timer interval.
Valid values are:*/
WDT_A_CLOCKDIVIDER_2G
WDT_A_CLOCKDIVIDER_128M
WDT_A_CLOCKDIVIDER_8192K
WDT_A_CLOCKDIVIDER_512K
WDT_A_CLOCKDIVIDER_32K /*[Default]*/
WDT_A_CLOCKDIVIDER_8192
WDT_A_CLOCKDIVIDER_512
WDT_A_CLOCKDIVIDER_64
/*Modified bits are WDTIS and WDTHOLD of WDTCTL register.*/

上机实战

定时计数模式

配置

配置为定时计数模式,时钟源选为ACLK = 32768HZ ,分频系数设为32768,得到1s的定时周期

    WDT_A_hold(WDT_A_BASE);		//暂停计数

    SystemClock_Init();

    WDT_A_initIntervalTimer(WDT_A_BASE, WDT_A_CLOCKSOURCE_ACLK, WDT_A_CLOCKDIVIDER_32K);	//初始化看门狗定时计数模式
    SFR_enableInterrupt(SFR_WATCHDOG_INTERVAL_TIMER_INTERRUPT);	//启用看门狗定时计数模式中断

    GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);


    WDT_A_start(WDT_A_BASE);	//开始计数

    __bis_SR_register(GIE);

中断服务函数

// 看门狗中断服务程序
#pragma vector = WDT_VECTOR
__interrupt void WDT_ISR(void)
{
    GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);    // 反转P1.0端口状态
}

整体代码

#include "driverlib.h"

#define MCLK_IN_HZ      25000000

#define delay_us(x)     __delay_cycles((MCLK_IN_HZ/1000000*(x)))
#define delay_ms(x)     __delay_cycles((MCLK_IN_HZ/1000*(x)))

void SystemClock_Init(void)
{
    PMM_setVCore(PMM_CORE_LEVEL_3);     //高主频工作需要较高的核心电压

    //XT1引脚复用
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN4);
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN5);

    //起振XT1
    UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,UCS_XCAP_3);

    //XT2引脚复用
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN2);
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN3);

    //起振XT2
    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);

    //XT2作为FLL参考时钟,先8分频,再50倍频 4MHz / 8 * 50 = 25MHz
    UCS_initClockSignal(UCS_FLLREF, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_8);
    UCS_initFLLSettle(25000, 50);

    //XT1作为ACLK时钟源 = 32768Hz
    UCS_initClockSignal(UCS_ACLK, UCS_XT1CLK_SELECT, UCS_CLOCK_DIVIDER_1);

    //DCOCLK作为MCLK时钟源 = 25MHz
    UCS_initClockSignal(UCS_MCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);

    //DCOCLK作为SMCLK时钟源 = 25MHz
    UCS_initClockSignal(UCS_SMCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);

    //设置外部时钟源的频率,使得在调用UCS_getMCLK, UCS_getSMCLK 或 UCS_getACLK时可得到正确值
    UCS_setExternalClockSource(32768, 4000000);
}

int main(void)
{

    WDT_A_hold(WDT_A_BASE);
    SystemClock_Init();


    WDT_A_initIntervalTimer(WDT_A_BASE, WDT_A_CLOCKSOURCE_ACLK, WDT_A_CLOCKDIVIDER_32K);

    SFR_enableInterrupt(SFR_WATCHDOG_INTERVAL_TIMER_INTERRUPT);

    GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);

    WDT_A_start(WDT_A_BASE);

    __bis_SR_register(GIE);

    while(1)
    {

    }
}

// 看门狗中断服务程序
#pragma vector = WDT_VECTOR
__interrupt void WDT_ISR(void)
{
    GPIO_toggleOutputOnPin(GPIO_PORT_P1, GPIO_PIN0);    // 反转P1.0端口状态
}

实验结果

在这里插入图片描述

看门狗模式

配置

初始化P2.1为上拉输入,P1.0为LED输出,按下P2.1 按钮喂狗,当得不到及时的喂狗,系统将会复位。

    WDT_A_hold(WDT_A_BASE);
    SystemClock_Init();


    WDT_A_initWatchdogTimer(WDT_A_BASE, WDT_A_CLOCKSOURCE_ACLK, WDT_A_CLOCKDIVIDER_32K);

    GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);
    GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0);

    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, GPIO_PIN1);

    WDT_A_start(WDT_A_BASE);

    __bis_SR_register(GIE);

    while(1)
    {
        if(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN1))
        {
            delay_ms(20);
            if(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN1))
            {
                WDT_A_resetTimer(WDT_A_BASE);
                while(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN1));
            }
        }
    }

整体代码

#include "driverlib.h"

#define MCLK_IN_HZ      25000000

#define delay_us(x)     __delay_cycles((MCLK_IN_HZ/1000000*(x)))
#define delay_ms(x)     __delay_cycles((MCLK_IN_HZ/1000*(x)))

void SystemClock_Init(void)
{
    PMM_setVCore(PMM_CORE_LEVEL_3);     //高主频工作需要较高的核心电压

    //XT1引脚复用
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN4);
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN5);

    //起振XT1
    UCS_turnOnLFXT1(UCS_XT1_DRIVE_3,UCS_XCAP_3);

    //XT2引脚复用
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P5, GPIO_PIN2);
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P5, GPIO_PIN3);

    //起振XT2
    UCS_turnOnXT2(UCS_XT2_DRIVE_4MHZ_8MHZ);

    //XT2作为FLL参考时钟,先8分频,再50倍频 4MHz / 8 * 50 = 25MHz
    UCS_initClockSignal(UCS_FLLREF, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_8);
    UCS_initFLLSettle(25000, 50);

    //XT1作为ACLK时钟源 = 32768Hz
    UCS_initClockSignal(UCS_ACLK, UCS_XT1CLK_SELECT, UCS_CLOCK_DIVIDER_1);

    //DCOCLK作为MCLK时钟源 = 25MHz
    UCS_initClockSignal(UCS_MCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);

    //DCOCLK作为SMCLK时钟源 = 25MHz
    UCS_initClockSignal(UCS_SMCLK, UCS_DCOCLK_SELECT, UCS_CLOCK_DIVIDER_1);

    //设置外部时钟源的频率,使得在调用UCS_getMCLK, UCS_getSMCLK 或 UCS_getACLK时可得到正确值
    UCS_setExternalClockSource(32768, 4000000);
}

int main(void)
{

    WDT_A_hold(WDT_A_BASE);
    SystemClock_Init();


    WDT_A_initWatchdogTimer(WDT_A_BASE, WDT_A_CLOCKSOURCE_ACLK, WDT_A_CLOCKDIVIDER_32K);

    GPIO_setAsOutputPin(GPIO_PORT_P1, GPIO_PIN0);
    GPIO_setOutputHighOnPin(GPIO_PORT_P1, GPIO_PIN0);

    GPIO_setAsInputPinWithPullUpResistor(GPIO_PORT_P2, GPIO_PIN1);

    WDT_A_start(WDT_A_BASE);

    __bis_SR_register(GIE);

    while(1)
    {
        if(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN1))
        {
            delay_ms(20);
            if(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN1))
            {
                WDT_A_resetTimer(WDT_A_BASE);
                while(!GPIO_getInputPinValue(GPIO_PORT_P2, GPIO_PIN1));
            }
        }
    }
}

  • 4
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

乙酸氧铍

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值