STM32F4X RTC

news2024/12/24 21:17:04

STM32F4X RTC

  • 什么是RTC
  • STM32F4X RTC
    • STM32F4X RTC框图
    • STM32F4X RTC计数频率
    • STM32F4X RTC日历
    • STM32F4X RTC闹钟
  • STM32F4X RTC例程

什么是RTC

RTC全程叫Real-Time Clock实时时钟,是MCU中一个用来计时的模块。RTC的一个主要作用是用来显示实时时间,就像日常生活中的时钟一样,RTC除了可以显示时间之外,还有闹钟功能,唤醒功能等。很多的MCU里面都会有RTC模块,当然也可以外接RTC芯片使用。

STM32F4X RTC

STM32F4X RTC框图

在这里插入图片描述

  1. RTC时钟源:RTC的时钟源有3个,分别是外部低频晶振(LSE)、内部低频晶振(LSI)和外部高频晶振(HSE)。一般来说我们都会选择32768Hz的LSE作为RTC的时钟源。
  2. RTC分频器:时钟源选择好之后,就需要对时钟源进行分频。STM32F4X的RTC分频器有两个,分别是异步分频器7位的PREDIV_A和15位的同步分频器 PREDIV_A。RTC的分频由这两个分频器共同决定。
  3. RTC闹钟:STM32F4X的RTC有两个闹钟,用户可以通过设置闹钟的触发条件,当闹钟设置的触发条件跟当前RTC的计数时间一致时就会产生一个信号,如果使能了闹钟中断,就会触发闹钟中断
  4. RTC唤醒:当系统进入低功耗模式时,可以通过RTC唤醒系统。RTC有一个唤醒预分频器,可以设置2/4/6/8分频,还有一个16位的唤醒自动重装载寄存器,用来设置唤醒时间。
  5. RTC影子寄存器:影子寄存器的作用是提供给用户读取日历使用,用户不能直接访问影子寄存器,由STM32F4X每隔两个TRCCLK周期进行复制。

STM32F4X RTC计数频率

对于RTC来说,我们需要得到一个1秒的计数频率,这样才符合日常生活的习惯。下面就以RTC的时钟源为32768Hz来计算,看如何得到1Hz的频率。
STM32F4X给出了RTC时钟频率的计算公式
在这里插入图片描述
STM32F4X的RTC分频需要PREDIV_A和PREDIV_S两个分频器共同决定。其中PREDIV_A为7位,PREDIV_S为15位。我们可以设置PREDIV_A为0x7F,PREDIV_S为0xFF。

F = 32768 / (0x7F + 1) * (0xFF + 1) = 32768 / 32768 = 1Hz
刚好可以得到1Hz的频率,这样就可以让RTC以1秒的频率进行计数。

STM32F4X RTC日历

用户可以设置RTC的日历功能,通过RTC_TR和RTC_DR寄存器可以设置日历。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

STM32F4X RTC闹钟

STM32F4X的RTC有两个闹钟,分别是ALARM A和ALARM B。可以通过RTC_ALRMAR和RTC_ALRMBR进行设置。可以设置闹钟的触发条件和触发时间。
在这里插入图片描述
在这里插入图片描述

STM32F4X RTC例程

#include "rtc.h"
#define ALARM_HOUR_MIN_SEC  1 // 闹钟匹配 时分秒
#define ALARM_HOUR_MIN      2 // 闹钟匹配 时分
#define ALARM_MIN_SEC       3 // 闹钟匹配 分秒
#define ALARM_HOUR          4 // 闹钟匹配 时
#define ALARM_MIN           5 // 闹钟匹配 分
#define ALARM_SEC           6 // 闹钟匹配 秒
ErrorStatus rtc_set_time(u8 hour,u8 min,u8 sec,u8 ampm)
{
	RTC_TimeTypeDef RTC_TimeStruct;
	RTC_TimeStruct.RTC_H12 = ampm;
	RTC_TimeStruct.RTC_Hours = hour; // 设置小时
	RTC_TimeStruct.RTC_Minutes = min; // 设置分钟
	RTC_TimeStruct.RTC_Seconds = sec;// 设置秒
	return RTC_SetTime(RTC_Format_BIN,&RTC_TimeStruct);
}
ErrorStatus rtc_set_date(u8 year,u8 mon,u8 day,u8 week)
{
	RTC_DateTypeDef RTC_DateStruct;
	
	RTC_DateStruct.RTC_Date = day; // 设置日
	RTC_DateStruct.RTC_Month = mon; // 设置月
	RTC_DateStruct.RTC_WeekDay = week;// 设置周
	RTC_DateStruct.RTC_Year = year;//设置年
	return RTC_SetDate(RTC_Format_BIN,&RTC_DateStruct);
}

void set_alarm_time(u32 alarmx,u8 hour,u8 min,u8 sec,u8 week,u8 alarm_type)
{
	RTC_AlarmTypeDef RTC_AlarmStruct;
	RTC_TimeTypeDef RTC_AlarmTime; 
	NVIC_InitTypeDef NVIC_InitStruct;
	EXTI_InitTypeDef   EXTI_InitStructure;
	
	
	RTC_AlarmCmd(alarmx,DISABLE); // 关闭闹钟
	
	RTC_AlarmTime.RTC_H12 = RTC_H12_AM;
	RTC_AlarmTime.RTC_Hours = hour; // 闹钟小时
	RTC_AlarmTime.RTC_Minutes = min; // 闹钟分
	RTC_AlarmTime.RTC_Seconds = sec;// 闹钟秒
	
	
	RTC_AlarmStruct.RTC_AlarmDateWeekDay = week; // 闹钟周
	RTC_AlarmStruct.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_Date;
	
	// 闹钟类型选择
	if(alarm_type == ALARM_HOUR_MIN_SEC)
		RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay ;
	else if(alarm_type == ALARM_HOUR_MIN)
		RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay | RTC_AlarmMask_Seconds;
	else if(alarm_type == ALARM_MIN_SEC)
		RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay | RTC_AlarmMask_Hours;
	else if(alarm_type == ALARM_HOUR)
		RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay | RTC_AlarmMask_Minutes | RTC_AlarmMask_Seconds;
	else if(alarm_type == ALARM_MIN)
		RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay | RTC_AlarmMask_Hours | RTC_AlarmMask_Seconds;
	else if(alarm_type == ALARM_SEC)
		RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay | RTC_AlarmMask_Hours | RTC_AlarmMask_Minutes;
	else
		RTC_AlarmStruct.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay | RTC_AlarmMask_Hours | RTC_AlarmMask_Minutes;
		
	RTC_AlarmStruct.RTC_AlarmTime = RTC_AlarmTime;
	RTC_SetAlarm(RTC_Format_BIN,alarmx,&RTC_AlarmStruct);
	
	NVIC_InitStruct.NVIC_IRQChannel = RTC_Alarm_IRQn; // RTC 闹钟中断号
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority  = 2;
	NVIC_Init(&NVIC_InitStruct);
	
	EXTI_InitStructure.EXTI_Line = EXTI_Line17;//LINE17
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发 
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能LINE17
	EXTI_Init(&EXTI_InitStructure);//配置
	
	if (alarmx == RTC_Alarm_A)
	{
		RTC_ClearITPendingBit(RTC_IT_ALRA);
		RTC_ITConfig( RTC_IT_ALRA,ENABLE);
	}
	else if(alarmx == RTC_Alarm_B)
	{
		RTC_ClearITPendingBit(RTC_IT_ALRB);
		RTC_ITConfig( RTC_IT_ALRB,ENABLE);
	}
		
	RTC_AlarmCmd(alarmx,ENABLE);
}
	
u8 bsp_rtc_init(void)
{
	u32 lse_rdy_count = 0xFFFF;
	RTC_InitTypeDef RTC_InitStruct;
	
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//使能PWR时钟
	PWR_BackupAccessCmd(ENABLE);	//使能后备寄存器访问 
	RCC_LSEConfig(RCC_LSE_ON); // 使能LSE时钟
	
	if(RTC_ReadBackupRegister(RTC_BKP_DR0) != 0x525443)  // 判断是不是第一次配置
	{
		while(1)
		{
			if(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == SET) // 等待LSE时钟稳定
				break;
			
			lse_rdy_count--;
			delay_ms(10);
			if(lse_rdy_count == 0)
				return 1;
		}
		RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); // RTC时钟源选择LSE时钟
		RCC_RTCCLKCmd(ENABLE);                  // RTC使能
		
		
		// RTC最终的计数频率 = 32768 / (0x7F + 1) * (0xFF + 1) 
		RTC_InitStruct.RTC_AsynchPrediv = 0x7F; // 设置异步分频器
		RTC_InitStruct.RTC_HourFormat = RTC_HourFormat_24; // 24小时制
		RTC_InitStruct.RTC_SynchPrediv = 0xFF;  // 设置同步分频器
		RTC_Init(&RTC_InitStruct);

		
		rtc_set_time(4,7,4,RTC_H12_AM); // 设置时间 4:7:4
		rtc_set_date(23,9,8,5);         // 设置日期 2023-9-8 
		
		RTC_WriteBackupRegister(RTC_BKP_DR0,0x525443); // 如果是第一次就往备份寄存器写一个值
	}
	
	return 0;
	
}

void RTC_Alarm_IRQHandler(void)
{
	if(RTC_GetITStatus(RTC_IT_ALRA) == SET)
	{
		printf("Alarm A\r\n");
		RTC_ClearITPendingBit(RTC_IT_ALRA);
	}
	if(RTC_GetITStatus(RTC_IT_ALRB) == SET)
	{
		printf("Alarm B\r\n");
		RTC_ClearITPendingBit(RTC_IT_ALRB);
	}
	EXTI_ClearITPendingBit(EXTI_Line17);	//清除中断线17的中断标志 	
}
int main(void)
{
	RTC_TimeTypeDef RTC_TimeStruct;
	RTC_DateTypeDef RTC_DateStruct;
	uint32_t crc_value = 0;
	NVIC_PriorityGroupConfig(2);
	system_tick_init();
	
	bsp_usart_init(115200);
	bsp_rtc_init();
	set_alarm_time(RTC_Alarm_A,10,0,55,2,ALARM_SEC); // 设置闹钟A 按秒闹 
	set_alarm_time(RTC_Alarm_B,10,1,45,2,ALARM_SEC); // 设置闹钟B 按秒闹
	
  while(1){

	  delay_ms(1000);
	  RTC_GetTime(RTC_Format_BIN,&RTC_TimeStruct);	// 获取时间
	  RTC_GetDate(RTC_Format_BIN, &RTC_DateStruct); // 获取日期
	  printf("20%02d-%02d-%02d %02d:%02d:%02d\r\n",RTC_DateStruct.RTC_Year,RTC_DateStruct.RTC_Month,RTC_DateStruct.RTC_Date,RTC_TimeStruct.RTC_Hours,RTC_TimeStruct.RTC_Minutes,RTC_TimeStruct.RTC_Seconds); 
		
	}
  
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/989660.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Visual Studio 2019下使用C++与Python进行混合编程——环境配置与C++调用Python API接口

前言 在vs2019下使用C与Python进行混合编程,在根源上讲,Python 本身就是一个C库,那么这里使用其中最简单的一种方法是把Python的C API来嵌入C项目中,来实现混合编程。当前的环境是,win10,IDE是vs2019,python版本是3.9&#xff0c…

一个帮各位填秋招表格省一点事的浏览器插件

最近应该很多和我一样的双非鼠鼠在秋招等面试,而且处于海投阶段,为了不忘记投了哪些公司,可以用这样一个表格来记录: 其中有些字段,比如状态、投递时间、查看进度的网址其实可以不手动输入,所以搞个插件来…

2023数模国赛C 题 蔬菜类商品的自动定价与补货决策-完整版创新多思路详解(含代码)

题目简评:看下来C题是三道题目里简单一些的,考察的点比较综合,偏数据分析。涉及预测模型和运筹优化(线性规划),还设了一问开放型问题,适合新手入门,发挥空间大。 题目分析与思路: 背景&#x…

部署zookeeper集群

zookeeper和jdk下载地址 jdk 链接:https://pan.baidu.com/s/13GpNaAiHM5HSDJ66ebBtEg 提取码:90se zookeeper 链接:https://pan.baidu.com/s/1nSFKEhSGNiwgSPZWdb7hkw 提取码:u5l2 在所有的机器上面执行下面步骤: 1.上…

C++的纯虚函数和抽象类

在C++中,可以将虚函数声明为纯虚函数,语法格式为: virtual 返回值类型 函数名 (函数参数) = 0; 纯虚函数没有函数体,只有函数声明,在虚函数声明的结尾加上=0,表明此函数为纯虚函数。 最后的=0并不表示函数返回值为0,它只起形式上的作用,告诉编译系统“这是纯虚函数”。…

继承的偏移量问题

下面是实际测试: p1 p3 ! p2 Base1* p1 &d; Derive* p3 &d;! Base2* p2 &d; 图解:

斯坦福小镇升级版——AI-Town搭建指南

导语: 8月份斯坦福AI小镇开源之后,引起了 AIGC 领域的强烈反响,但8月份还有另一个同样非常有意义的 AI-Agent 的项目开源,a16z主导的 AI-Town 本篇文章主要讲解如何搭建该项目,如有英文基础或者对这套技术栈熟悉&#…

监控系统prometheus部署

wget -c https://github.com/prometheus/prometheus/releases/downloa d/v2.37.1/prometheus-2.37.1.linux-amd64.tar.gz下载必要的组件。 mkdir -p /opt/prometheus创建目录。 此文章为9月Day 8学习笔记,内容来源于极客时间《运维监控系统实战笔记》。

docker安装开发常用软件MySQL,Redis,rabbitMQ

Docker安装 docker官网:Docker: Accelerated Container Application Development docker镜像仓库:https://hub.docker.com/search?qnginx 官网的安装教程:Install Docker Engine on CentOS | Docker Docs 安装步骤 1、卸载以前安装的doc…

Reqable项目技术栈全方面总结

大家好,最近有知乎网友问我Reqable技术选型的问题,恰好Reqable也刚刚发布了非常重要的1.3版本更新,所以此次写一篇关于Reqable项目技术栈的全方面总结。 本篇文章的目的,是向大家分享我关于Reqable项目的一些技术思考、细节和填坑…

鸿蒙应用程序入口UIAbility详解

一、UIAbility概述 UIAbility是一种包含用户界面的应用组件,主要用于和用户进行交互。UIAbility也是系统调度的单元,为应用提供窗口在其中绘制界面。每一个UIAbility实例,都对应于一个最近任务列表中的任务。一个应用可以有一个UIAbility&am…

Kafka生产与消费示例

Kafka生产与消费流程 Kafka是一款消息中间件,消息中间件本质就是收消息与发消息,所以这节课我们会从一条消息开始生产出发,去了解生产端的运行流程,然后简单的了解一下broker的存储流程,最后这条消息是如何被消费者消…

GNU Linux 的退出码规定

参考:https://tldp.org/LDP/abs/html/exitcodes.html 从这张表里来看,小于 128 的是被程序员捕捉的错误,大于等于 128 的是真正的 bugs ?

MySQL卸载干净再重新安装【Windows】

家人们,谁懂啊? 上学期学的数据库,由于上学期不知道为什么抽风,过得十分的迷,上课跟老师步骤安装好了Mysql,但后面在使用的过程中出现了问题,而且还出现了忘记密码这么蠢的操作,后半…

linux设置登录超时自动退出

问题背景 最近登录某台linux服务器,经常遇到超时自动退出现象,如下图: 是因为服务器设置了超时时间,如果某个超时时间段内服务器没有任何操作,则会自动注销 解决方法 查看服务器设置的超时时间(TMOUT 变量的值)&am…

非科班菜鸡算法学习记录 | 代码随想录算法训练营第59天||503.下一个更大元素II 42. 接雨水

503. 下一个更大元素 II 知识点&#xff1a;单调栈 状态&#xff1a;不会&#xff0c;全靠卡哥 思路&#xff1a; 用i%nums.size()来代替i&#xff0c; 用for遍历时遍历两次 // 版本二 class Solution { public:vector<int> nextGreaterElements(vector<int>&am…

TLA+学习记录1——hello world

0x01 TLA是个好工具 编程人员一个好习惯是凡事都想偷懒&#xff0c;当然是指要科学地偷懒&#xff0c;而不是真的偷懒。一直想找到一种能检验写出的代码&#xff0c;做出的设计是否真的完全正确&#xff0c;而不是靠经验检视、代码Review、反复测试去检验。因为上述方法不管怎…

MATLAB中M文件编写

简介 所谓M文件就是将处理问题的各种命令融合到一个文件中&#xff0c;该文件以.m为扩展名。然后&#xff0c;由MATLAB系统编译M文件&#xff0c;得出相应的运行结果。M文件具有相当大的可开发性和扩展性。M文件有脚本文件和函数文件两种。脚本文件不需要输入参数&#xff0c;…

【美团3.18校招真题1】

大厂笔试真题网址&#xff1a;https://codefun2000.com/ 塔子哥刷题网站博客&#xff1a;https://blog.codefun2000.com/ 小美剪彩带 提交网址&#xff1a;https://codefun2000.com/p/P1088 题意&#xff1a;找出区间内不超过k种数字子数组的最大长度 使用双指针的方式&…

js使用crypto-js做加密解密

首先安装 crypto-js npm install crypto-js下面是完整代码&#xff0c;首先引入 crypto-js 里的 AES 和 enc&#xff0c;声明加密方法和解密方法进行测试 let { AES, enc } require("crypto-js");// 加密方法 function encryptString(str, key) {// 使用 AES 加密…