【STM32学习】实时时钟 —— RTC

2023-05-16

【STM32学习】实时时钟 —— RTC

  • 零、参考
  • 一、工作原理
    • 1、RTC介绍
    • 2、工作过程
  • 二、相关寄存器
  • 三、代码说明
    • 1、rtc初始化
    • 2、关于中断
    • 3、中断配置代码(仅供参考)
      • 3.1 秒中断+普通闹钟功能
      • 3.2 待机模式唤醒
      • 3.3 停机模式唤醒

零、参考

STM32RTC实时时钟实验讲解,从入门到放弃
【STM32】RTC休眠唤醒(停机模式)、独立看门狗开启状态下
关于STM32使用RTC唤醒停止模式的设置

一、工作原理

1、RTC介绍

RTC(Real Time Clock):实时时钟,是指可以像时钟一样输出实际时间的电子设备,一般会是集成电路,因此也称为时钟芯片。总之,RTC只是个能靠电池维持运行的32位定时器,并不像实时时钟芯片,读出来就是年月日。
RTC就只一个定时器而已,掉电之后所有信息都会丢失,因此我们需要找一个地方来存储这些信息,于是就找到了备份寄存器(BKP)。因为它掉电后仍然可以通过纽扣电池供电,继续工作,所以能时刻保存这些数据。
stm32F103使用外部晶体的32.768kHz的振荡器,产生一个1秒长的时间基准。
RTC 模块和时钟配置系统(RCC_BDCR 寄存器)是在后备区域,即在系统复位或从待机模式唤醒后 RTC 的设置和时间维持不变。但是在系统复位后,会自动禁止访问后备寄存器和 RTC,以防止对后备区域(BKP)的意外写操作。所以在要设置时间之前, 先要取消备份区域(BKP)写保护

2、工作过程

在这里插入图片描述

RTC只是一个时钟,但与RTC相连的有两个系统时钟:一个是APB1接口的PCLK1,另一个是RTC时钟。这样,RTC功能也就分为两个部分:第一部分,APB1接口部分,与APB1总线相连,MCU也就是通过这条总线对其进行读写操作。另一部分,RTC核心,其整个核心部分位于后备区域,所以只要有VBAT引脚供电,就能一直工作,由一系列可编程计数器组成,这部分又再细分为两个组件:20位的预分频模块与32位可编程计数器。预分频模块用来产生最长为1秒的RTC时间基准,而32位的可编程的计数器可被初始化为当前的系统时间。

RTC_PRL:预分频装载寄存器
RTC_DIV:预分频器余数寄存器
RTC_CNT:计数器寄存器
RTC_ALR:闹钟寄存器

首先,在初始化时候,DIV和PRL都会装载同样的数。RTCCLK频率为32.768kHz,来驱动DIV工作,DIV为自减寄存器。当DIV减少到0时,会产生一个TR_CLK信号,该信号会触发三件事情:①将PRL的数重装在到DIV中;②触发CNT计数器+1;③触发SECF,进而产生秒中断。我们会设置一个合理的预分频数,使得TR_CLK触发时间刚好是1s。ALR中存储的是我们设置的闹钟秒数,当CNT和ALR中的数据相同时,就会触发闹钟中断或者闹钟唤醒。(关于CNT和ALR中存放的数据,为时间戳。)

1s的时间如何计算?
fTR_CLK = fRTCCLK/(PRL[19:0]+1)
我们的RTC_CLK为32.768kHz,所以只要PRL中写入32767即可,即为2的15次方。
我们只需要在PRL的低16位寄存器中写入0x7FFF即可。

DIV寄存器存在的意义?
从上述能知道TR_CLK输出必须为1s。那么我们想要的到0.15s,应该怎么实现呢?
道理很简单,因为DIV是自减的,并且从32768一直减少到0,所需要的时间为1s。所以减少一个数,所用的时间为1/32768s,那么减少多少个数,就计时了0.15s呢?
1/32768s * n = 0.15
n = 0.15 * 32768
又因为DIV寄存器是可读的,所以我们就能实现0.15s的计时。

从框图中,还可以看到,只有秒中断和闹钟中断能触发中断,溢出是没有中断的

二、相关寄存器

具体的寄存器讲解与设置,就不做讲解了,不是很复杂。
只说几处需要注意的:

1、RTC的寄存器都是分了高16位和低16位使用的
2、在这里插入图片描述
需要注意的是RTOFF位,该位为只读位,表示最后一次寄存器的写状态。当我们需要对PRL、CNT、ALR寄存器写入数据时,需要先判断该位是否为1。只有上一次写完了,我们才能继续写。
3、关于备份数据寄存器
在这里插入图片描述
可以把它看作是一个EEPROM,掉电不丢失的存储器。
DRx的x(x=1…10)什么意思呢?就是有10个这样的16位寄存器。
例如,RTC程序中,我们向DR1写入0x5050,开机检测是否已经配置过RTC。

三、代码说明

1、rtc初始化

在这里插入图片描述

2、关于中断

rtc中断服务函数有两个:RTC_IRQHandler(全局中断)和RTCAlarm_IRQHandler(闹钟中断)
给我们的印象,好像是全局中断就是用来处理秒中断的;闹钟中断就是用来处理闹钟中断的。
但是,这样的说法并不是全面的。

先说结论:
① 如果只需要闹钟作为一个定时的功能,而不是用于低功耗的唤醒,那么只需要在NVIC设置秒中断(如果不用可以不设置)和闹钟中断,秒中断和闹钟中断任何一个都能触发RTC_IRQHandler,我们只需要根据读取相应标志位,判断是秒还是闹钟中断即可。
在这里插入图片描述
在这里插入图片描述
② 如果该闹钟中断用于低功耗唤醒——待机模式。那么闹钟中断会触发RTCAlarm_IRQHandler函数。我们需要在中断函数中,清除调闹钟中断标志位。
③ 如果该闹钟中断用于低功耗唤醒——停机模式。单纯的闹钟中断是无法唤醒停机模式的,我们需要将RTC闹钟中断链接到外部中断EXIT_17(也不用链接,默认的,就是使能一下子),用来唤醒停机模式。
在这里插入图片描述

3、中断配置代码(仅供参考)

3.1 秒中断+普通闹钟功能

记得开启闹钟中断以及设置闹钟时间

u8 RTC_Init(void)
{
	//检查是不是第一次配置时钟
	u8 temp=0;
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);	//使能PWR和BKP外设时钟   
	PWR_BackupAccessCmd(ENABLE);	//使能RTC和后备寄存器访问  
	if (BKP_ReadBackupRegister(BKP_DR1) != 0x5555)		//从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
		{	 			
		BKP_DeInit();	//复位备份区域 	
		RCC_LSEConfig(RCC_LSE_ON);	//设置外部低速晶振(LSE),使用外设低速晶振
		while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)	//检查指定的RCC标志位设置与否,等待低速晶振就绪
			{
			temp++;
			delay_ms(10);
			}
		if(temp>=250)return 1;//初始化时钟失败,晶振有问题	 
			
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);		//设置RTC时钟(RTCCLK),选择LSE作为RTC时钟    
		RCC_RTCCLKCmd(ENABLE);	//使能RTC时钟  
		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
		RTC_WaitForSynchro();		//等待RTC寄存器同步  
			
		RTC_ITConfig(RTC_IT_SEC, ENABLE);		//使能RTC秒中断
		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
		RTC_WaitForSynchro();		//等待RTC寄存器同步  

		RTC_ITConfig(RTC_IT_ALR, ENABLE);		//使能RTC闹钟中断
		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
		RTC_WaitForSynchro();		//等待RTC寄存器同步 	
			
		RTC_EnterConfigMode();/// 允许配置	
		RTC_SetPrescaler(32767); //设置RTC预分频的值
		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
			
		RTC_Set(2023,4,4,19,10,10);  //设置时间	
		RTC_WaitForLastTask(); 
			
    RTC_SetAlarm(10+RTC_GetCounter());    //闹钟值设定为当前时间的10秒后
    RTC_WaitForLastTask(); 			
		
		RTC_ExitConfigMode(); //退出配置模式  
			
		BKP_WriteBackupRegister(BKP_DR1, 0X5555);	//向指定的后备寄存器中写入用户程序数据
		}
	else//系统继续计时
		{

		RTC_WaitForSynchro();	//等待最近一次对RTC寄存器的写操作完成
		RTC_ITConfig(RTC_IT_SEC, ENABLE);	//使能RTC秒中断
		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
		RTC_ITConfig(RTC_IT_ALR, ENABLE);		//使能RTC闹钟中断
		RTC_WaitForLastTask();	//等待最近一次对RTC寄存器的写操作完成
		RTC_WaitForSynchro();		//等待RTC寄存器同步 
		}
	RTC_NVIC_Config();//RCT中断分组设置		    				     
	RTC_Get();//更新时间	
	return 0; //ok

}		
static void RTC_NVIC_Config(void)
{	
  NVIC_InitTypeDef NVIC_InitStructure;
  NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;		//RTC全局中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	//先占优先级1位,从优先级3位
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;	//先占优先级0位,从优先级4位
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;		//使能该通道中断
  NVIC_Init(&NVIC_InitStructure);		//根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
void RTC_IRQHandler(void)
{		 
	if (RTC_GetITStatus(RTC_IT_SEC) != RESET)//秒钟中断
	 {							
		 RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW);		//清秒中断
		 RTC_Get();   //更新时间   
		 RTC_WaitForLastTask();  //等待写入完成
	 }
	 
	if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)//闹钟中断
	 {
	    RTC_ClearITPendingBit(RTC_IT_ALR);		//清闹钟中断	  	
	    RTC_Get();		//更新时间  
	    RTC_WaitForLastTask();		 
     } 				  								 
	  	  	    						 	   	 
}

3.2 待机模式唤醒

void RTC_NVIC_Config(void)
{	
  NVIC_InitTypeDef NVIC_InitStructure;
  NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn;		//RTC闹钟中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	//先占优先级1位
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;	//先占优先级0位
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;		//使能该通道中断
  NVIC_Init(&NVIC_InitStructure);		//根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
}
void RTCAlarm_IRQHandler(void)
{
  if(RTC_GetITStatus(RTC_IT_ALR) != RESET)
   {
      RTC_ClearITPendingBit(RTC_IT_ALR);
      RTC_WaitForLastTask();
      if(PWR_GetFlagStatus(PWR_FLAG_WU) != RESET)
       {
         PWR_ClearFlag(PWR_FLAG_WU);
         RTC_WaitForLastTask();
         //处理业务
       }
    }
   RTC_ITConfig(RTC_IT_ALR, DISABLE);  //关闭闹钟中断,用的时候在开启
}

3.3 停机模式唤醒

void RTC_NVIC_Config(void)
{	
  EXTI_InitTypeDef EXTI_InitStructure;  
  NVIC_InitTypeDef NVIC_InitStructure;
  NVIC_InitStructure.NVIC_IRQChannel = RTCAlarm_IRQn;		//RTC闹钟中断
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	//先占优先级1位
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;	//先占优先级0位
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;		//使能该通道中断
  NVIC_Init(&NVIC_InitStructure);		//根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
  
  //闹钟中断接到第17线外部中断
  EXTI_ClearITPendingBit(EXTI_Line17);
  EXTI_InitStructure.EXTI_Line = EXTI_Line17;
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  EXTI_Init(&EXTI_InitStructure); 

}
void RTCAlarm_IRQHandler(void)
{
  EXTI_ClearITPendingBit(EXTI_Line17);
  RTC_ClearFlag(RTC_FLAG_ALR);
  RTC_WaitForLastTask();
  SystemInit();//重要,由于停机下对所有时钟关闭,所以唤醒需要重新配置时钟!!
  if(PWR_GetFlagStatus(PWR_FLAG_WU) != RESET)
  {
    PWR_ClearFlag(PWR_FLAG_WU);// 清除唤醒标志
    //处理业务
  }
  RTC_ITConfig(RTC_IT_ALR, DISABLE);            //失能RTC闹钟中断,用的时候在开启
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【STM32学习】实时时钟 —— RTC 的相关文章

随机推荐

  • Docker世界 -- 进阶篇(入门)

    一 Docker Compose 1 1 Docker Compose 介绍 1 1 1 简介 xff1a 传统的 docker 服务 xff0c 我们一般通过编写 Dockerfile 文件 xff0c 通过 build 命令创建一个镜像
  • 树莓派pico CMake工程 直接添加 .c .h文件

    假设工程名test1 xff0c 带main 的源代码文件 main c xff0c 要往工程里添加oled c oled h之类的源代码 直接添加为可执行文件 xff1a 编辑工程根目录的 CmakeLists txt add execu
  • 张量的通俗理解

    1 关于张量的四种定义 张量 在不同的运用场景下有不同的定义 xff08 1 xff09 张量是多维数组 xff0c 这个定义常见于各种人工智能软件 听起来还好理解 xff08 2 xff09 张量是某种几何对象 xff0c 不会随着坐标系
  • 如何搭建node_exporter

    如何搭建node exporter 1 观看条件 1 假设你已经看过上一篇文章 如何搭建普罗米修斯 Prometheus 2 假设你已经会搭建普罗米修斯 xff08 promethus xff09 3 上面两个假设 xff0c 只要满足一个
  • python类中初始化形式:def __init__(self)和def __init__(self, 参数1,参数2,···,参数n)区别

    前言 这两种初始化形式 xff0c 就类似于C 43 43 类中的构造函数 形式1 def init self span class token keyword class span span class token class name
  • Go语言操作grpc详细使用

    Go语言操作grpc详细使用 零 参考链接一 protobuf的详细使用二 grpc与protobuf的go文件的生成1 安装两个插件2 写proto文件3 编译proto文件 xff0c 生成go文件 三 grpc的详细使用1 一元RPC
  • Steghide使用教程及其密码爆破

    Steghide使用教程及其密码爆破 工具介绍 Steghide是一款开源的隐写术软件 xff0c 它可以让你在一张图片或者音频文件中隐藏你的秘密信息 xff0c 而且你不会注意到图片或音频文件发生了任何的改变 而且 xff0c 你的秘密文
  • 一道Gloang并发、锁的面试题,你会吗?

    Gloang并发 锁的面试题 1 题目描述2 问题分析2 1问题一2 2问题二2 3问题三2 4问题四2 5问题五 3 问题解决方法4 代码实现4 1 map前后加锁的方式4 2 sync map解决方式 1 题目描述 源地址 xff1a
  • 阿里云、腾讯云centos7安装mysql

    阿里云 腾讯云centos7安装mysql 1 下载2 解压与准备3 安装4 配置4 1配置数据库4 2查看默认密码4 3启动mysql4 4设置密码 5 开启远程登录5 1开放3306端口5 2开启远程登录6 参考链接 1 下载 镜像网站
  • go语言gin、net/http的优雅关机

    gin net http的优雅关机 什么是优雅关机 xff1f 优雅关机的实现参考链接 什么是优雅关机 xff1f http server运行过程中 xff0c 若进程被关闭 xff0c 那么正在处理的请求可能只被处理了一半就停止了 xff
  • C语言不详细记录

    C记录 1 内存管理2 结构体内存对其规则3 字符串函数4 二维数组5 const 指针6 字符串7 图片记录8 函数指针 1 内存管理 C语言内存讲解 详说内存分布和heap空间 2 结构体内存对其规则 C语言结构体对齐规则 C语言 结构
  • 【web压测】压测常用工具、压测指标到底是什么?

    压测常用工具 压测指标到底是什么 xff1f 一 压测指标 I1 QPS xff0c 每秒查询2 TPS xff0c 每秒事务3 RT xff0c 响应时间 二 压测指标 II三 压测工具1 ab2 go wrk 在window上压测 一
  • C语言结构体字节对其规则简述

    C语言结构体字节对其规则简述 规则描述示例示例一示例二 字节对齐规则 xff0c 一直不是很理解 xff0c 网上的答案也是参差不齐 规则描述 首先 xff0c 预处理指令 pragma pack n 可以改变默认对齐数进行字节对齐 n 取
  • 【STM32学习】SysTick定时器(嘀嗒定时器)

    SysTick定时器 一 参考资料二 时钟源选择与定时时间计算1 时钟源选择2 定时时间计算 三 SysTick Handler中断服务函数 一 参考资料 嘀嗒定时器 xff1a 时钟源 寄存器 二 时钟源选择与定时时间计算 结合正点原子的
  • 【STM32学习】GPIO口的八种工作模式

    GPIO口的八种工作模式 一 参考资料二 GPIO八种模式1 输入模式2 输出模式 三 施密特触发器1 电路2 电路计算 一 参考资料 GPIO原理图详解 强烈建议观看 xff1a GPIO为什么这样设计 xff1f 施密特触发器 原理 施
  • 【STM32学习】WWDG窗口看门狗

    STM32学习 WWDG窗口看门狗 x1f415 1 图展示WWDG原理2 复位 中断条件3 溢出时间计算4 与独立看门狗 x1f415 的对比 1 图展示WWDG原理 2 复位 中断条件 产生复位的情况 xff1a 当递减计数器数值递减到
  • 【STM32学习】时钟配置详解

    STM32学习 时钟配置详解 看懂时钟图结合代码外部高速时钟修改 看懂时钟图 在刚开始学习32的时候 xff0c 并不会在意这些 xff0c 或者即使看了也看的不是很明白 随着学习的深入 xff0c 我们发现看门狗 定时器 ADC很多外设都
  • vnc远程访问ubuntu18.04桌面系统 vncserver开机自启动

    文章目录 一 windows端准备二 ubuntu端准备三 远程连接桌面四 配置vncserver开机自启动 一 windows端准备 下载TightVNC xff1a https www tightvnc com 二 ubuntu端准备
  • 【STM32学习】定时器寄存器配置、功能工作过程详解

    STM32学习 定时器寄存器配置 功能工作过程详解 零 参考一 引言二 功能以及寄存器说明1 最基本的定时功能 xff08 时基单元 xff09 1 1 框图1 2 工作流程1 3 寄存器介绍1 3 1 CR1寄存器1 3 2 CNT PS
  • 【STM32学习】实时时钟 —— RTC

    STM32学习 实时时钟 RTC 零 参考一 工作原理1 RTC介绍2 工作过程 二 相关寄存器三 代码说明1 rtc初始化2 关于中断3 中断配置代码 xff08 仅供参考 xff09 3 1 秒中断 43 普通闹钟功能3 2 待机模式唤