STM32--RTC实时时钟

文章目录

  • Unix时间戳
  • 时间戳转换
  • BKP
  • RTC简介
  • RTC框图
  • 硬件电路
  • RTC的注意事项
  • RTC时钟实验工程

Unix时间戳

Unix 时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒

时间戳存储在一个秒计数器中,秒计数器为32位/64位的整型变量。

世界上所有时区的秒计数器相同,不同时区通过添加偏移来得到当地时间。

在这里插入图片描述

GMT : GMT(Greenwich Mean Time), 格林威治平时(也称格林威治时间)。
它规定太阳每天经过位于英国伦敦郊区的皇家格林威治天文台的时间为中午12点。它将地球自转一周的时间间隔等分为24小时,以此确定计时标准。

UTC:UTC(Coodinated Universal Time),协调世界时,又称世界统一时间、世界标准时间、国际协调时间。
UTC 是现在全球通用的时间标准,全球各地都同意将各自的时间进行同步协调。UTC 时间是经过平均太阳时(以格林威治时间GMT为准)、地轴运动修正后的新时标以及以秒为单位的国际原子时所综合精算而成。

时间戳转换

对于我们目前使用的电子设备,都是通过联网来确认时间戳的。所以我们看到的时间都是由时间戳转换成日期的。

C语言的time.h模块提供了时间获取和时间戳转换的相关函数,可以方便地进行秒计数器、日期时间和字符串之间的转换。

在这里插入图片描述
这里讲几个会用到的。

第一个,time_t time(time_t*),获取系统时钟。
通过使用设备当前时间,获取一个时间戳。
在这里插入图片描述

第二个,struct tm* gmtime(const time_t*);秒计数器转换为日期时间(格林尼治时间)
在这里插入图片描述
这里需要注意的是struct tm 结构体类型成员year和mon
在这里插入图片描述
年是从1900年算起的,所以实际时间要加上1900;
月是从0开始的,所以要加上1;
时是由于计算是标准时间,所以要加上8才是东八区的标准时间。

第三个,time_t mktime(struct tm*);日期时间转换为秒计数器(当地时间)
在这里插入图片描述

由于STM32无法计算系统时钟,需要软件输入设置当前时间,所以也没有当地时间与标准时间的概念。

在这里插入图片描述

BKP

备份寄存器是42个16位的寄存器,可用来存储84个字节的用户应用程序数据。(对于中小容量的产品,只能存储20个字节)他们处在备份域里,当VDD电源被切断,他们仍然由VBAT维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位。
也就是说,只要有一方供电,保存的数据就不会丢失;

BKP控制寄存器用来管理侵入检测和RTC校准功能

在这里插入图片描述

侵入检测:当TAMPER引脚上的信号从’0’变成’1’或者从’1’变成’0’(取决于备份控制寄存器BKP_CR的TPAL位),会产生一个侵入检测事件。侵入检测事件将所有数据备份寄存器内容清除
RTC校准:为方便测量, RTC时钟可以经64分频输出到侵入检测引脚TAMPER上。
这里只是简单介绍这两种功能而已。
在这里插入图片描述

RTC简介

实时时钟是一个独立的定时器RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。
RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后, RTC的设置和时间维持不变。
在这里插入图片描述
操作访问方法与BKP相同。

相关特性
在这里插入图片描述

RTC框图

在这里插入图片描述
RTC时钟部分就是在后备区域内,上面连接着APB1总线进行读写的操作,
左边连接着RTC时钟源。
RTC核心部分是完全独立于APB接口的,需要通过软件,经过APB1接口访问RTC的预分频值,计数器值和闹钟值。
RTC预分频器会先预装重装载器,然后给到DIV,在RTCCLK时钟源进来的每一次,DIV以递减的方式,直到DIV为0时才将输出时钟传到CNT上;
CNT是一个计数器,用来存储时间戳;下面的ALR是闹钟寄存器,当CNT与ALR相等时,可以通过闹钟来产生中断;
这些产生的时钟信号经过控制寄存器进入NVIC中断控制器。
在这里插入图片描述

硬件电路

在这里插入图片描述
这部分是备用电池供电的电路,对于简单连接的就是直接连上一个3.3V供电的即可。
右边的是纽扣电池的连接方式。

在这里插入图片描述
外部低速晶振图,外部时钟的产生;
在这里插入图片描述

RTC的注意事项

执行以下操作将使能对BKP和RTC的访问:
设置RCC_APB1ENR的PWREN和BKPEN,使能PWR和BKP时钟
设置PWR_CR的DBP,使能对BKP和RTC的访问(开启RTC)

若在读取RTC寄存器时,RTC的APB1接口曾经处于禁止状态,则软件首先必须等待RTC_CRL寄存器中的RSF位(寄存器同步标志)被硬件置1(时钟同步)

必须设置RTC_CRL寄存器中的CNF位,使RTC进入配置模式后,才能写入RTC_PRL、RTC_CNT、RTC_ALR寄存器

对RTC任何寄存器的写操作,都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的RTOFF状态位,判断RTC寄存器是否处于更新中。仅当RTOFF状态位是1时,才可以写入RTC寄存器

RTC时钟实验工程

OLED代码链接入口

连接方式:
在这里插入图片描述
在OLED屏幕显示一个实时时钟;

MyRTC.h

#ifndef __MYRTC_H__
#define __MYRTC_H__

#include "stm32f10x.h"                  // Device header
#include <time.h>

typedef struct Time
{
    int sec;
    int min;
    int hour;
    int mday;
    int mon;
    int year;
    
}Time;



void MyRTC_Init(Time* t);
void MyRTC_SetTime(Time* t);
void MyRTC_ReadTime(Time* t);

#endif
 

MyRTC.c

#include "MyRTC.h"

//时间设置
void MyRTC_SetTime(Time* t)
{
    time_t time_cnt;//计数器
    struct tm time_date;//时钟日期
    
    time_date.tm_year=  t->year-1900;
    time_date.tm_mon= t->mon-1;
    time_date.tm_mday= t->mday;
    time_date.tm_hour= t->hour;
    time_date.tm_min= t->min;
    time_date.tm_sec= t->sec;
    //设置计数器
    //日期转换为时间戳
    time_cnt=mktime(&time_date)-8*60*60;
    RTC_SetCounter(time_cnt);
    RTC_WaitForLastTask();   
}

void MyRTC_Init(Time* t)
{
   //打开电源和后备接口的时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);
    //开启RTC的使用
    PWR_BackupAccessCmd(ENABLE);
    
   // if(BKP_ReadBackupRegister(BKP_DR1)!=0x1111)
   // {
        //配置LSE
        RCC_LSICmd(ENABLE);
        while(!RCC_GetFlagStatus(RCC_FLAG_LSIRDY));
        //RCCLK选择LSE
        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
        //开启RTC的时钟源
        RCC_RTCCLKCmd(ENABLE);
        
        //时钟同步  
        RTC_WaitForSynchro();
        RTC_WaitForLastTask();
        
        //设置分频器,写操作等待完成
        RTC_SetPrescaler(32767);
        RTC_WaitForLastTask();
        
        //时间初始化设置
        MyRTC_SetTime(t);
        //非首次和完全断电给一个值
   //     BKP_WriteBackupRegister(BKP_DR1,0x1111);
  //  }
  // else
  // {
  //     RTC_WaitForSynchro();
  //     RTC_WaitForLastTask();
  // }
    
    
     
}



//读取时间
void MyRTC_ReadTime(Time* t)
{
    time_t time_cnt;//计数器
    struct tm time_date;//时钟日期
    //时间戳转换为日期
    time_cnt=RTC_GetCounter()+8*60*60;
    time_date=*localtime(&time_cnt);
    
    
    t->year=time_date.tm_year+1900;
    t->mon=time_date.tm_mon+1;
    t->mday=time_date.tm_mday;
    t->hour=time_date.tm_hour;
    t->min=time_date.tm_min;
    t->sec=time_date.tm_sec;
}

对于时钟的选择内部时钟LSI无法在断开电源和复位时进入后备区域;LSE外部时钟可以,我们可以设置一个值,只要是这个值说明就进入了后备区域。由于我的外部时钟晶振无法震荡,所以只能使用内部时钟,读者可以
修改为在这里插入图片描述
并将那些注释解开即可。
这里进行写操作时,函数中就已经进入了配置模式了
在这里插入图片描述
这里输入的时钟是东八区的时间,而设置计数器为标准时间的时间戳,所以要进行减去8* 60* 60
等到读取时间时再加回来

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MyRTC.h"

int main()
{
    Time time;
    time.year=2023;
    time.mon=1;
    time.mday=1;
    time.hour=23;
    time.min=59;
    time.sec=55;
    
	OLED_Init();
	MyRTC_Init(&time);
    
    
	
    MyRTC_SetTime(&time);
	OLED_ShowString(1, 1, "Date:XXXX-XX-XX");
	OLED_ShowString(2, 1, "Time:XX:XX:XX");
	OLED_ShowString(3, 1, "CNT :");
	OLED_ShowString(4, 1, "DIV :");
	
    
	while (1)
	{
		MyRTC_ReadTime(&time);
		
		OLED_ShowNum(1, 6, time.year, 4);
		OLED_ShowNum(1, 11,time.mon, 2);
		OLED_ShowNum(1, 14, time.mday, 2);
		OLED_ShowNum(2, 6, time.hour, 2);
		OLED_ShowNum(2, 9, time.min, 2);
		OLED_ShowNum(2, 12, time.sec, 2);
		
		OLED_ShowNum(3, 6, RTC_GetCounter(), 10);
		OLED_ShowNum(4, 6, RTC_GetDivider(), 10);
	}
    
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

部署问题集合(二十二)Linux设置定时任务,并设置系统时间

前言 因为项目中经常用到定时任务&#xff0c;特此总结记录一下 步骤 大部分虚拟机创建后就自带定时服务&#xff0c;直接用命令就好编辑定时任务&#xff1a;crontab -e&#xff0c;在该文件下添加如下内容开机自启&#xff1a;reboot /home/autoRun.sh定时执行&#xff1a…

走进低代码平台| iVX-困境之中如何突破传统

前言&#xff1a; “工欲善其事,必先利其器”&#xff0c;找到和使用一个优质的工具平台&#xff0c;往往会事半功倍。 文章目录 1️⃣认识走近低代码2️⃣传统的低代码开发3️⃣无代码编辑平台一个代码生成式低代码产品iVX受面性广支持代码复用如何使用&#xff1f; 4️⃣总结…

极氪汽车的云资源治理细探

作者&#xff1a;极氪汽车吴超 前言 2021 年&#xff0c;极氪 001 迅速崭露头角&#xff0c;仅用 110 天便创下了首款车型交付量“最快破万”的纪录。2022 年 11 月&#xff0c;极氪 009 在短短 76 天内便率先完成了首批交付&#xff0c;刷新了中国豪华纯电品牌交付速度的纪录…

分布式集群——jdk配置与zookeeper环境搭建

系列文章目录 分布式集群——jdk配置与zookeeper环境搭建 分布式集群——搭建Hadoop环境以及相关的Hadoop介绍 文章目录 系列文章目录 前言 一 zookeeper介绍与环境配置 1.1 zookeeper的学习 1.2 Zookeeper的主要功能 1.2.1 znode的节点类型 1.2.2 zookeeper的实现 …

SQL Server 2019导入txt数据

1、选择导入数据 2、选择Flat file Source 选择文件&#xff0c;如果第一行不是列名&#xff0c;就不勾选。 3、下一步 可以看看数据是否是对的 4、下一步 选择SQL server Native Client 11&#xff0c;数据库选择导入进的库 输入连接数据库的名字和要导入的数据库 下一…

渲染如何做到超强渲染?MAX插件CG MAGIC中的渲染功能!

渲染工作应该算是设计师的日常工作流程中最重要的环节之一了。如果渲染速度加快&#xff0c;可能是要看渲染技巧掌握的有多少了。 大家熟悉的3d Max本地渲染通道&#xff0c;对于CG MAGIC渲染功能你也一定不能错过&#xff0c;要知道操作简单易使用&#xff0c;就完全拿捏了效率…

22.3D等距社交媒体菜单的悬停特效

效果 源码 <!doctype html> <html><head><meta charset="utf-8"><title>CSS Isometric Social Media Menu</title><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.…

成集云 | 钉钉财务费用单同步至畅捷通 | 解决方案

源系统成集云目标系统 方案介绍 财务管理作为企业管理中重要的组成部分&#xff0c;在企业的发展和成长中扮演着重要角色&#xff0c;成集云以钉钉费用单OA审批与畅捷通TCloud系统为例&#xff0c;与钉钉连接器深度融合&#xff0c;通过数据处理和字段匹配实现了费用…

Hugging Face--Transformers

pipeline 在这里插入图片描述 AutoClass AutoClass 是一个能够通过预训练模型的名称或路径自动查找其架构的快捷方式. 你只需要为你的任务选择合适的 AutoClass 和它关联的预处理类。 AutoTokenizer AutoModel 保存模型 自定义模型构建 Trainer - PyTorch优化训练循环 参考资…

Mysql-InnoDB记录结构

一、InnoDB简介 InnoDB 采取的方式是&#xff1a;将数据划分为若干个页&#xff0c;以页作为磁盘和内存之间交互的基本单位&#xff0c;InnoDB中页的大小一般为 16 KB。也就是在一般情况下&#xff0c;一次最少从磁盘中读取16KB的内容到内存中&#xff0c;一次最少把内存中的1…

数据结构:八种数据结构大全

数据结构 1.1 数据结构概述 数据结构是计算机存储、组织数据的方式&#xff1b;通常情况下&#xff0c;精心选择的数据结构可以带来更高的运行或者存储效率。数据结构的优良将直接影响着我们程序的性能&#xff1b;常用的数据结构有&#xff1a;数组&#xff08;Array&#xff…

前端三剑客中简单的两个:HTMLCSS

HTML&CSS 1&#xff0c;HTML1.1 介绍1.2 快速入门1.3 基础标签1.3.1 标题标签1.3.2 hr标签1.3.3 字体标签 1.4 图片、音频、视频标签1.5 超链接标签1.6 列表标签1.7 表格标签1.8 布局标签1.9 表单标签1.9.1 表单标签概述1.9.2 form标签属性1.9.3 代码演示 1.10 表单项标签 …

postgis数据库从一张表中过滤出一部分数据到新表中

你可以使用以下步骤在PostGIS数据库中过滤objectid<100的数据&#xff0c;并将其创建为新表&#xff1a;打开PostGIS数据库的终端或客户端工具&#xff08;如Psql&#xff09;。 选择你要过滤数据的表。假设表名为"original_table"&#xff0c;该表包含一个名为&q…

Leetcode Top 100 Liked Questions(序号75~104)

75. Sort Colors 题意&#xff1a;红白蓝的颜色排序&#xff0c;使得相同的颜色放在一起&#xff0c;不要用排序 我的思路 哈希 代码 Runtime 4 ms Beats 28.23% Memory 8.3 MB Beats 9.95% class Solution { public:void sortColors(vector<int>& nums) {vector…

无涯教程-Android - Services

服务是在后台运行以执行长时间运行的操作而无需与用户交互的组件&#xff0c;并且即使应用程序被破坏&#xff0c;它也可以工作。服务实际上可以采取两种状态- Sr.No.State & Remark1 Started 当应用程序组件(如Activity)通过调用 startService()启动服务&#xff0c;启动后…

[Linux]进程程序替换

[Linux]进程程序替换 文章目录 [Linux]进程程序替换进程程序替换的意义见一见进程程序替换进程程序替换的原理进程程序替换中的写时拷贝介绍进程程序替换接口 进程程序替换的意义 Linux系统下使用fork系统函数创建子进程后&#xff0c;子进程只能执行继承的部分父进程代码&…

常用的css样式

1&#xff1a;flex布局 .flex-between {display: flex;justify-content: space-between; }.flex-evenly {display: flex;justify-content: space-evenly; }.flex-end {display: flex;justify-content: flex-end; }.flex {display: flex; }.flex-center {display: flex;justify…

JavaScript(函数,作用域和闭包)

目录 一&#xff0c;什么是函数1.1&#xff0c;常用系统函数1.2&#xff0c;函数声明 1.3&#xff0c;函数表达式二&#xff0c;预解析2.1&#xff0c;函数自调用 2.2&#xff0c;回调函数三&#xff0c;变量的作用域3.1&#xff0c;隐式全局变量 四&#xff0c;作用域与块级作…

关于sd卡根目录在哪里

你说的对,一切都会过去,哪怕是回忆。 sd卡根目录在哪里 1、手机要有SD卡才会存在SD卡根目录。 2、打开文件管理并在此页面下点击所有文件。 3、点击SD卡选项进入的页面就是SD卡根目录。 4、SD存储卡是一种基于半导体快闪记忆器的新一代记忆设备&#xff0c;由于它体积小、数…

[Pandas] pandas.melt

melt是溶解 / 分解的意思&#xff0c;即拆分数据 melt()函数可以将一些列的内容进行合并&#xff0c;把宽表整合成长表 语法格式 pandas.melt(frame, id_varsNone, value_varsNone, var_nameNone, value_namevalue)参数说明 frame&#xff1a;要处理的数据集 id_vars&#…