16-看门狗和RTC

#新星杯·14天创作挑战营·第11期#

一、独立看门狗

1、独立看门狗概述

      在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成程序的跑飞(不按照正常程序进行运行,如程序重启,但是如果我们填加看门狗的技术,就可以防止这个种情况的发生),而陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续工作,会造成整个系统的陷入停滞状态,发生不可预料的后果,所以出于对单片机运行状态进行实时监测的考虑,便产生了一种专门用于监测单片机程序运行状态的模块或者芯片,俗称“看门狗”(watchdog) 。

    看门狗( watchdog timer),是一个定时器(12位)电路, 一般有一个输入,叫喂狗(kicking the dog or service the dog),一个输出到MCU的RST(复位)端,MCU正常工作的时候,每隔一段时间输出一个信号到喂狗端,如果超过规定的时间不喂狗,(一般在程序跑飞时,不在程序正常的状态),WDT 定时超过,就会给出一个复位信号到MCU,使MCU复位. 防止MCU死机. 看门狗的作用就是防止程序发生死循环,或者说程序跑飞。

2、STM32独立看门狗

   独立看门狗适合应用于需要看门狗作为一个在主程序之外 能够完全独立工作,并且对时间精度要求低的场合。

        STM32F4 的独立看门狗由内部专门的 LSIRC32Khz 低速时钟 (LSI) 驱动,即使主时钟发生故障,它也仍然有效。这里需要注意独立看门狗的时钟是一个内部RC时钟,所以并不是准确的32Khz,而是在15~47Khz 之间的一个可变化的时钟,只是我们在估算的时候,以 32Khz 的频率来计算,独立看门狗对时间的要求不是很精确,所以,时钟有些偏差都是接受的范围。

3、独立看门狗操作步骤

独立看门狗操作步骤需要添加的库函数文件:stm32f4xx_iwdg.c

1、 取消寄存器写保护:

      IWDG_WriteAccessCmd();

2、设置独立看门狗的预分频系数,确定时钟:

     IWDG_SetPrescaler();

3、设置看门狗重装载值,确定溢出时间:

    IWDG_SetReload();

4、使能看门狗

    IWDG_Enable();

5、应用程序喂狗:就是重新将重装载寄存器值装载到计数器中,就相当于你每个月的伙食费,没钱了会向父母要差不多意思。

   IWDG_ReloadCounter();

如下例子是防止程序重启的代码,应用到看门狗的作用

看门狗例子源码:

https://download.csdn.net/download/m0_63622771/90841876

4、效果分析

没有喂狗,系统重启

int main(void)
{
    int ret;
    u8 data[5];
    
    //中断的优先级分组,一个项目只能设置一次
    //中断优先级分为第二组,抢占级范围:0~3  响应:0~3
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    Delay_Init();
    

    //初始化后GPIOF_ODR默认为低电平,所以灯亮
    Led_Init();
    
    Usart1_Init(115200);
    Tim3_NoISR_Init(50000-1);
    Dht11_Init();
    //下面我们设置了一条狗,使其每两秒内要喂狗,不然会让程序重启。
    Iwdg_Init();
    
    //如果打印这一句话,说明系统重启。
    printf("iwdg test\r\n");
    
    while(1)
    {    
        ret = Dht11_Data(data);
        if(ret == 0)
        {
            //让CPU打印数据
            printf("湿度:%d.%d\r\n", data[0], data[1]);
            printf("温度:%d.%d\r\n", data[2], data[3]);
            
        }
        
        delay_s(1);
        delay_ms(500);
        delay_ms(400);
        
    }
    
    return 0;
}

下面是添加喂狗的情况,系统会正常运行

int main(void)
{
    int ret;
    u8 data[5];
    
    //中断的优先级分组,一个项目只能设置一次
    //中断优先级分为第二组,抢占级范围:0~3  响应:0~3
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    Delay_Init();
    

    //初始化后GPIOF_ODR默认为低电平,所以灯亮
    Led_Init();
    
    Usart1_Init(115200);
    Tim3_NoISR_Init(50000-1);
    Dht11_Init();
    
    Iwdg_Init();
    
    //如果打印这一句话,说明系统重启。
    printf("iwdg test\r\n");
    
 
    while(1)
    {    
        ret = Dht11_Data(data);
        if(ret == 0)
        {
            //让CPU打印数据
            printf("湿度:%d.%d\r\n", data[0], data[1]);
            printf("温度:%d.%d\r\n", data[2], data[3]);
            
        }
        
        delay_s(1);
        delay_ms(500);
        delay_ms(400);
        
        //保证上面程序运行的时间少于2S
        
        //应用程序喂狗:
        IWDG_ReloadCounter();
        
    }
    
    return 0;
}

注意:真正看门狗喂程序不应该放主函数当中,因为主函数运行的时间不可控制,而是应该将喂狗程序放在一个基本定时器当中,每隔固定时间进行喂狗。

例如下面使用定时器7,每隔1.8s喂狗源码:

https://download.csdn.net/download/m0_63622771/90842063

二、RTC(时钟)

1、RTC概述

RTC(Real Time Clock,实时时钟)是一种专门用于记录时间的设备或模块,通常作为计算机系统中的一部分存在。其本质是一个计数器,以秒为单位进行计数,可以提供精确的时间信息,并且具有以下特性:

提供时间信息: RTC能够提供当前的时间,通常以秒钟数的形式表示,但也可以提供更精细的时间分辨率,如毫秒或微秒级别。

持久性: RTC具有持久性,即在MCU(Microcontroller Unit,微控制器单元)掉电后(主电源)仍然能够继续运行(依靠纽扣电池,也就说纽扣电池给RTC进行供电),因此能够确保时间信息的连续性和准确性。

低功耗: RTC通常具有低功耗特性,以确保在长时间内使用时消耗的能量较少,这对于依靠电池供电的应用尤为重要,因为它可以延长电池的使用寿命。

总的来说,RTC在许多应用中扮演着关键的角色,特别是在需要准确记录时间并且需要在掉电后继续运行的场景下,如数据记录、日志记录、定时任务等。

    STM32 的 RTC 外设,实质是一个掉电后还继续运行的定时器。RTC是个独立的BCD定时器/计数器。提供一个日历时钟,两个可编程闹钟中断,以及一个具有中断功能的周期性可编程唤醒标志。RTC还包含用于管理低功耗模式的自动唤醒单元。

两个32位寄存器包含二进码十进制格式(BCD)的秒,分钟,小时(12或24小时制),星期几,日期,月份和年份。此外,还可以提供二进制的亚秒值。系统可以自动将月份的天数补偿为28,29(闰年),30,31天。并且还可以进行夏令时补偿。

STM32F4 的 RTC 时钟源( RTCCLK )通过时 钟控制器,可以从 LSE 时钟、 LSI 时钟以及 HSE 时钟三者中选择(通过 RCC_BDCR 寄存器选择)。一般我们选择 LSE ,即外部 32.768Khz 晶振作为时钟源 (RTCCLK) ,而 RTC 时钟核心,要求提供 1Hz 的时钟 ,所以,我们要设置 RTC 的可编程预分配器。STM32F4 的可编程预分配器(RTC_PRER)分为 2 个部分:

1, 一个通过 RTC_PRER 寄存器的 PREDIV_A 位配置的 7 位异步预分频器。

异步预分频需要设置为:0x7f (127则是128分频)

2, 一个通过 RTC_PRER 寄存器的 PREDIV_S 位配置的 15 位同步预分频器。

同步预分频需要设置为:0xFF (255则是256分频)
BCD码
BCD码(Binary-Coded Decimal)是一种用二进制编码表示十进制数的编码方式

1.BCD码的分类:
有权码‌:如8421码、2421码、5421码,每个二进制位有固定的权值。
‌无权码‌:如余3码、余3循环码、格雷码,每个编码中的1和0没有确切的权值。

最常见的是8421码

选择外部时钟源,当主时钟发生故障时,RTC还能正常运行;且当主电源发生故障,RTC由钮扣电池进行独立供电

纽扣电池供电电路,纽扣电池供电由PWR外设进行管理

纽扣电池实物图

纽扣电池电路图

2、RTC时间与日期配置流程

1、使能PWR时钟:RCC_APB1PeriphClockCmd();

2、使能后备寄存器访问:   PWR_BackupAccessCmd();

3、配置RTC时钟源,使能RTC时钟:

      RCC_RTCCLKConfig();

      RCC_RTCCLKCmd();

      如果使用LSE,要打开LSE:RCC_LSEConfig(RCC_LSE_ON);

4、 初始化RTC(同步/异步分频系数和时钟格式):RTC_Init ();

5、 设置时间:RTC_SetTime ();

6、设置日期:RTC_SetDate();

后备寄存器是一种掉电后可保存数据的寄存器。
uint32_t RTC_ReadBackupRegister(uint32_t RTC_BKP_DR)//读后备寄存器
void RTC_WriteBackupRegister(uint32_t RTC_BKP_DR, uint32_t Data)//写入后备寄存器

RTC日期时间例子源码:

https://download.csdn.net/download/m0_63622771/90842069

3、RTC闹钟

STM32有两个闹钟,分别闹钟A与闹钟B.

RTC 中断:所有 RTC 中断均与 EXTI(外部中断控制) 控制器相连。

要使能 RTC 闹钟中断,需按照以下顺序操作:

1. 将 EXTI 线 17 配置为中断模式并将其使能,然后选择上升沿有效。

2. 配置 NVIC 中的 RTC_Alarm IRQ 通道并将其使能。

3. 配置 RTC 以生成 RTC 闹钟(闹钟 A 或闹钟 B)。 

闹钟A配置流程

1、RTC时间已经初始化好相关参数。

2、关闭闹钟:RTC_AlarmCmd(RTC_Alarm_A,DISABLE);

3、配置闹钟参数:RTC_SetAlarm();

4、开启配置闹钟中断:

    

     EXTI_Init();

     NVIC_Init();

RTC_ITConfig();

5、开启闹钟:RTC_AlarmCmd(RTC_Alarm_A,ENABLE);

6、编写中断服务函数:RTC_Alarm_IRQHandler();

可通过下面函数判断是哪个闹钟发生响应

FlagStatus RTC_GetFlagStatus(uint32_t RTC_FLAG)//获取标志位

RTC闹钟例子:

https://download.csdn.net/download/m0_63622771/90842074

4、实验效果

时间设置

        RTC_TimeStruct.RTC_H12        = RTC_H12_PM; //下午,在24小时制时,这个参数是无用
        RTC_TimeStruct.RTC_Hours    = 9; //时
        RTC_TimeStruct.RTC_Minutes    = 16; //分
        RTC_TimeStruct.RTC_Seconds    = 10; //秒
        //RTC_Format_BIN,写10进制,硬件自动转换为2进制进行存储
        RTC_SetTime (RTC_Format_BIN, &RTC_TimeStruct);

闹钟A的设置时间1后

    //闹钟时间设置
    RTC_AlarmTime.RTC_H12        = RTC_H12_AM; //上午,在24小时制时,这个参数是无用
    RTC_AlarmTime.RTC_Hours        = 9; //时
    RTC_AlarmTime.RTC_Minutes    = 17; //分
    RTC_AlarmTime.RTC_Seconds    = 10; //秒

5、掩码位理解

掩码位:对某个位屏蔽,可以理解为忽略这个操作
在代码中:RTC_AlarmStruct.RTC_AlarmMask            = RTC_AlarmMask_Hours;  //表示闹钟A有小时掩码位
如设置的时间:9:55:10,接下来,忽略了小时,也就每隔小时的55分10秒都会响应响应,一天有24个闹钟。

三、函数说明

//1
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess);
函数功能:是否使能 IWDG_PR and IWDG_RLR寄存器
返回值:无
uint16_t IWDG_WriteAccess:是否使能
IWDG_WriteAccess_Enable 
IWDG_WriteAccess_Disable

//2
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler)
函数功能:设置看门预分频器
返回值:无
uint8_t IWDG_Prescaler:分频系数
IWDG_Prescaler_4   
IWDG_Prescaler_8   
IWDG_Prescaler_16  
IWDG_Prescaler_32  
IWDG_Prescaler_64  
IWDG_Prescaler_128 
IWDG_Prescaler_256 

//3
void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource)
void IWDG_SetReload(uint16_t Reload)
函数功能:设置重载值
返回值:无
uint16_t Reload:重载值寄存器的值,范围:0~0xFFF

//4
void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource)
函数功能:RTC时钟源配置
返回值:无
uint32_t RCC_RTCCLKSource:时钟源选择
RCC_RTCCLKSource_LSE      
RCC_RTCCLKSource_LSI      
RCC_RTCCLKSource_HSE_Div2 
RCC_RTCCLKSource_HSE_Div3 
.
.
.
RCC_RTCCLKSource_HSE_Div30
RCC_RTCCLKSource_HSE_Div31

//5
ErrorStatus RTC_Init(RTC_InitTypeDef* RTC_InitStruct);
函数功能:RTC设置
返回值
成功:SUCCESS
失败:ERROR
RTC_InitTypeDef* RTC_InitStruct:RTC结构体
typedef struct
{
  uint32_t RTC_HourFormat;   //小时制选择
  
  uint32_t RTC_AsynchPrediv; //异步通道分频器
  
  uint32_t RTC_SynchPrediv;  //同步通道分频器
}RTC_InitTypeDef;

//6
ErrorStatus RTC_SetTime(uint32_t RTC_Format, RTC_TimeTypeDef* RTC_TimeStruct);
函数功能:RTC时间设置
返回值
成功:SUCCESS
失败:ERROR
uint32_t RTC_Format:存储格式
RTC_Format_BIN:二进制存储
RTC_Format_BCD:BCD编码存储
RTC_TimeTypeDef* RTC_TimeStruct:时间结构体
typedef struct
{
  uint8_t RTC_Hours;    //时

  uint8_t RTC_Minutes;  //分
  
  uint8_t RTC_Seconds;  //秒

  uint8_t RTC_H12;      //上/下午
}RTC_TimeTypeDef; 


//7
ErrorStatus RTC_SetDate(uint32_t RTC_Format, RTC_DateTypeDef* RTC_DateStruct);
函数功能:RTC日期设置
返回值
成功:SUCCESS
失败:ERROR
uint32_t RTC_Format:存储格式
RTC_Format_BIN:二进制存储
RTC_Format_BCD:BCD编码存储

RTC_DateTypeDef* RTC_DateStruct:日期结构体
typedef struct
{
  uint8_t RTC_WeekDay; //星期
  
  uint8_t RTC_Month;   //月

  uint8_t RTC_Date;     //日
  
  uint8_t RTC_Year;     //年
}RTC_DateTypeDef;

//8
void RTC_SetAlarm(uint32_t RTC_Format, uint32_t RTC_Alarm, RTC_AlarmTypeDef* RTC_AlarmStruct)
函数说明:闹钟设置
返回值:无
uint32_t RTC_Format:存储格式
RTC_Format_BIN:二进制存储
RTC_Format_BCD:BCD编码存储
uint32_t RTC_Alarm:选择闹钟
RTC_Alarm_A:闹钟A
RTC_Alarm_B:闹钟B

RTC_AlarmTypeDef* RTC_AlarmStruct:闹钟结构体

typedef struct
{
  RTC_TimeTypeDef RTC_AlarmTime;     //时间设置

  uint32_t RTC_AlarmMask;            //掩码位

  uint32_t RTC_AlarmDateWeekDaySel;  //选择日期还是星期设置闹钟
  
  uint8_t RTC_AlarmDateWeekDay;      //日期还是星期
}RTC_AlarmTypeDef;

//时间设置的结构体
typedef struct
{
  uint8_t RTC_Hours;    //时
  uint8_t RTC_Minutes;  //分
  
  uint8_t RTC_Seconds;  //秒

  uint8_t RTC_H12;      //上/下午
}RTC_TimeTypeDef; 


















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Bardb

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

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

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

打赏作者

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

抵扣说明:

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

余额充值