当前位置: 首页 > news >正文

16-看门狗和RTC

一、独立看门狗

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~3NVIC_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~3NVIC_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喂狗源码:

二、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日期时间例子源码:

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:闹钟BRTC_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; 

http://www.dtcms.com/a/192023.html

相关文章:

  • 西门子 Teamcenter13 Eclipse RCP 开发 1 工具栏
  • PyTorch循环神经网络(Pytotch)
  • 基于Rust语言的Rocket框架和Sqlx库开发WebAPi项目记录(一)
  • 青少年编程与数学 02-019 Rust 编程基础 14课题、并发编程
  • 系统集成项目管理工程师学习笔记
  • 深度学习框架对比---Pytorch和TensorFlow
  • C++23 新增的查找算法详解:ranges::find_last 系列函数
  • AWS CloudHSM:金融级密钥安全管理实战,如何通过FIPS 140-2认证守护数据生命线?
  • aws 实践创建policy + Role
  • W1R3S: 1.0.1靶场
  • 从卡顿到丝滑:JavaScript性能优化实战秘籍
  • (C语言)超市管理系统 (正式版)(指针)(数据结构)(清屏操作)(文件读写)
  • 【数据挖掘笔记】兴趣度度量Interest of an association rule
  • FastAPI使用@app.get/@app.post等装饰器注册路由无效404 Not Found
  • Kotlin并发请求的一些知识记录
  • 掌握Multi-Agent实践(七):基于AgentScope分布式模式实现多智能体高效协作[并行加速大模型辅助搜索、分布式多用户协同辩论赛]
  • 详细分析python 中的deque 以及和list 的用法区别
  • 【深度剖析】安踏体育的数字化转型(上篇1)
  • 嵌入式学习的第二十一天-数据结构-双向链表
  • js关于number类型的计算问题
  • RabbitMQ工作流程及使用方法
  • c/c++消息队列库RabbitMQ的使用
  • 动态库和静态库的区别
  • 以项目的方式学QT开发(二)
  • 哲学物理:太极图和莫比乌斯环有什么关系?
  • OkHttp用法-Java调用http服务
  • 【Linux系列】Linux 系统下 SSD 磁盘识别
  • 【油藏地球物理正演软件ColchisFM】基于数据驱动的油藏参数叠前地震反演研究进展
  • 操作系统学习笔记第3章 内存管理(灰灰题库)
  • javaSE.QueueDeque