GD 32 UNIX时间戳

news2024/11/17 12:23:56

前言


 ...


UINX时间戳定义

UNIX时间戳是一种表示时间的方法,广泛用于计算机系统和网络协议中。它定义的时间起点是1970年1月1日午夜(协调世界时UTC),也就是所谓的“UNIX纪元”开始的时刻。

Unix 时间戳(Unix Timestamp)定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数不考虑闰秒,时间戳是一个计数器数值,从1970年1月1日0时0分0秒开始,到现在总共所经过的秒数,时间戳存储在一个秒计数器中,秒计数器为32位/64位的整型变量,世界上所有时区的秒计数器相同,不同时区通过添加偏移来得到当地时间。


UTC与GMT

GMT(Greenwich Mean Time)格林尼治标准时间是一种以地球自转为基础的时间计量系统。它将地球自转一周的时间间隔等分为24小时,以此确定计时标准。

UTC(Universal Time Coordinated)协调世界时是一种以原子钟为基础的时间计量系统。它规定铯133原子基态的两个超精细能级间在零磁场下跃迁辐射9,192,631,770周所持续的时间为1秒。当原子钟计时一天的时间与地球自转一周的时间相差超过0.9秒时,UTC会执行闰秒来保证其计时与地球自转的协调一致。


时间戳与日历时间转换

在C语言提供的标准库中,time时间模块(time.h),提供了日历时间和时间戳转换的相关函数,在不使用操作系统的逻辑程序中常使用UNIX时间戳实现系统的计时,时间校准等功能,其中需要对获取到的时间做时区和格式的转换。

C语言提供有关时间戳转换的相关函数:

C语言库函数文件中定义好的有关时间戳的格式

部分转换示例函数:


RTC实时时钟

实时时钟 RTC 通常用于日历时钟。 RTC 电路分属于两个电源域。 一部分位于备份域中,该部分包括一个 32 位的累加计数器、一个闹钟、一个预分频器、一个分频器以及 RTC 时钟配置寄存器。这表明系统复位或者从待机模式唤醒时, RTC 的设置和时间都保持不变。另一部分位于VDD 电源域中,该部分只包括 APB 接口以及一组控制寄存器。


RTC 基本硬件结构:

以上包含三个外部时钟,一个是外部高速时钟,一个是外部低速时钟,一个是内部低速时钟,经过RTCCLK实时时钟时候,选择是否对时钟的频率进行分频,包含一个预分频器,分频器对频率进行分频,提供三个中断,分别是秒中断,溢出中断(溢出中断由CNT计数器计数溢出后产生,CNT最大的计数范围是65535个),提供32位闹钟ALRM为系统提供闹钟中断,最后经中断输出控制,进入NVIC(嵌套中断向量控制器,配置通道通道中断优先级,开启中断)。


RTC 基本硬件结构

以上是STM32RTC硬件结构程序框图与GD32大致相同。


RTC 主要特征

 32位可编程计数器,用于计数运行时间

可编程的预分频器: 分频系数最高可达 220

 独立时钟域:

A) PCLK1 时钟域

B) RTC 时钟域(该时钟必须比 PCLK1 时钟至少慢 4 倍)

 RTC 时钟源:

A) HXTAL 时钟除以 128

B) LXTAL 振荡电路时钟

C) IRC40K 振荡电路时钟

 可屏蔽的中断源:

A) 闹钟中断

B) 秒中断

C) 溢出中断


RTC 时钟源

在GD32这款MCU中RTC(实时时钟)一共有三个时钟源分别如下所示:

(A) HXTAL  时钟除以 128

(B) LXTAL   振荡电路时钟

(C) IRC40K 振荡电路时钟


BKP 备份寄存器

备份寄存器可在 VDD 电源关闭时由 VBAT 供电,备份寄存器有 42 个16 位(84字节)寄存器可用来存储并保护用户应用数据,从待机模式唤醒或系统复位也不会对这些寄存器造成影响。

此外,BKP 寄存器也可实现侵入检测和 RTC 校准功能。


在复位之后,任何对备份域寄存器的写操作都将被禁止,也就是说,备份寄存器和 RTC 不允许写访问。为使能对备份寄存器和 RTC的写访问,首先通过设置 RCU APB1EN 寄存器的PMUEN 和 BKPIEN 位来打开电源和备份接口时钟,然后再通过设置 PMU CTL 寄存器的BKPWEN 位来使能对备份域中寄存器的写访问。


RTC 复位

APB 接口和 RTC_INTEN 寄存器会随着系统复位进行复位。 RTC 内核(预分频器、分频器、计数器以及闹钟)只会随备份域复位进行复位。通过下面的步骤,可以在复位后访问备份域寄存器以及 RTC 寄存器:

1.通过对 RCU_APB1EN 寄存器中的 PMUEN 和 BKPEN 位进行置位,使能电源以及备份接口时钟。

2.通过对 PMU_CTL 中的 BKPWEN 位进行置位,使能对备份域寄存器和 RTC 的访问。


RTC 读取

APB 接口和 RTC 内核分属于两个不同电源域。

在 RTC 内核中,只有计数器和分频器寄存器为可读寄存器。这两个寄存器的值以及 RTC 标志会在每个 RTC 时钟的上升沿进行内部更新,并与 APB1 时钟进行重新同步。

当 APB 接口从禁用状态使能后,建议不要立即进行读操作,因为这些寄存器的首次内部更新可能尚未完成。这表明,在系统复位、电源复位、从待机/深度睡眠模式下唤醒时, APB 接口是被禁用的,但是 RTC 内核仍然保持运行。在这类情况下,正确的读操作应该先将 RTC_CTL寄存器的 RSYNF 清零并等待其被硬件置位。 WFI 和 WFE 指令对于 RTC 的 APB 接口没有影响


栈,堆,静态区存储

栈存储、静态区存储和堆存储是程序中不同类型的内存分配方式。它们各自有不同的特点和生命周期。下面是这三种存储方式的概述:

1. 栈存储 (Stack Storage)

  • 用途: 用于存储局部变量和函数调用时的临时数据。
  • 特点:
    • 栈上的数据由编译器自动管理。
    • 分配速度快,因为栈空间是预先分配好的。
    • 栈空间有限,不适合存储大量数据。
    • 栈上的数据具有固定的生存期,当函数退出时,这些数据会被自动销毁。
  • 生命周期: 栈上的数据在其作用域内存在,当作用域结束时,数据被销毁。

2. 静态区存储 (Static Storage)

  • 用途: 用于存储全局变量、静态局部变量以及常量。
  • 特点:
    • 静态区的数据在整个程序运行期间存在。
    • 编译器会在程序启动前分配静态存储空间。
    • 静态局部变量仅在其声明的函数内部可见,但其生命周期贯穿整个程序运行过程。
    • 全局变量在整个程序中可见。
    • 常量通常存储在只读的静态存储区域。
  • 生命周期: 静态区的数据在程序启动时创建,在程序结束时销毁。

3. 堆存储 (Heap Storage)

  • 用途: 用于动态分配的大块内存。
  • 特点:
    • 堆空间是在程序运行时动态分配的。
    • 分配速度较慢,因为需要搜索合适的内存块。
    • 堆空间相对较大,适合存储大量数据。
    • 堆上的数据由程序员手动管理,需要显式地分配和释放。
    • 堆空间可能会产生内存碎片。
  • 生命周期: 堆上的数据由程序员控制,一般通过 malloc, calloc, realloc, free (C) 或 new, delete (C++) 进行分配和释放。

代码案例:

#include <stdio.h>
#include <stdlib.h>

void func() {
    int stack_var = 1; // 栈存储
    static int static_var = 2; // 静态区存储
    int *heap_var = malloc(sizeof(int)); // 堆存储
    *heap_var = 3;

    printf("Stack var: %d\n", stack_var);
    printf("Static var: %d\n", static_var);
    printf("Heap var: %d\n", *heap_var);

    free(heap_var); // 释放堆上的内存
}

int main() {
    func();
    func(); // 注意静态变量的值不会重置
    return 0;
}

:在这个示例中,stack_var 存储在栈上,每个函数调用时都会重新分配;static_var 存储在静态区,它在两次函数调用间保持相同的值;heap_var 存储在堆上需要手动分配和释放


UNIX 时间戳验证

验证采用调用C语言提供的库函数time.h文件的方式,通过时间戳的获取显示验证程序的执行结果为后续的学习做好铺垫。

引入库函数文件:

#include <time.h>
#include <stdlib.h>

main 函数程序:

1.0 版:

int main(void)
{	
	DrvInit();
	AppInit();
		
	// 定义一个时间戳的变量
	time_t timeStamp = 100000000;
	// 定义一个结构体变量
	struct tm* timeInfo = NULL;
	// 将时间戳的秒数转换为时间
	timeInfo = gmtime(&timeStamp);
	printf
	(
		"gmtime, %d-%d-%d %d:%d:%d\n",
		 timeInfo->tm_year + 1900,
		 timeInfo->tm_mon + 1,
		 timeInfo->tm_mday,
		 timeInfo->tm_hour,
		 timeInfo->tm_min,
		 timeInfo->tm_sec
	);
	
	timeInfo = localtime(&timeStamp);
	printf
	(
		"localtime, %d-%d-%d %d:%d:%d\n",
		 timeInfo->tm_year + 1900,
		 timeInfo->tm_mon + 1,
		 timeInfo->tm_mday,
		 timeInfo->tm_hour,
		 timeInfo->tm_min,
		 timeInfo->tm_sec
	);

	while (1)
	{
		TaskHandler();
	}
}

将获取到的UNIX时间戳转换为指定的格式


 2.0 版:

int main(void)
{	
	DrvInit();
	AppInit();
		
	// 定义一个时间戳的变量
	time_t timeStamp = 1000000000;
	// 定义一个结构体变量
	struct tm* timeInfo = NULL;
	// 将时间戳的秒数转换为时间
//	timeInfo = gmtime(&timeStamp);
//	printf
//	(
//		"gmtime, %d-%d-%d %d:%d:%d\n",
//		 timeInfo->tm_year + 1900,
//		 timeInfo->tm_mon + 1,
//		 timeInfo->tm_mday,
//		 timeInfo->tm_hour,
//		 timeInfo->tm_min,
//		 timeInfo->tm_sec
//	);
	
	timeInfo = localtime(&timeStamp);
	printf
	(
		"localtime, %d-%d-%d %d:%d:%d\n",
		 timeInfo->tm_year + 1900,
		 timeInfo->tm_mon + 1,
		 timeInfo->tm_mday,
		 timeInfo->tm_hour,
		 timeInfo->tm_min,
		 timeInfo->tm_sec
	);
	
	printf("%s\n",asctime(timeInfo));


	//另外一个接口函数
	char timeArr[80];
	// 根据我们传入的格式解析结构体里面的成员
	strftime(timeArr,80,"%Y-%m-%d %H:%M:%S",timeInfo);
	printf("%s\n",timeArr);
	
		
	while (1)
	{
		TaskHandler();
	}
}

获取本地戳转换为对应格式


 3.0 版:

int main(void)
{	
	DrvInit();
	AppInit();
		
	// 定义一个时间戳的变量
	time_t timeStamp = 1000000000;
	// 定义一个结构体变量
	struct tm* timeInfo = NULL;
	
	
//	timeInfo = Test();
//	printf("address of timeInfo is 0x%p\n",timeInfo);
//	timeInfo = Test();
//	printf("address of timeInfo is 0x%p\n",timeInfo);
	
	
	// 将时间戳的秒数转换为时间
//	timeInfo = gmtime(&timeStamp);
//	printf
//	(
//		"gmtime, %d-%d-%d %d:%d:%d\n",
//		 timeInfo->tm_year + 1900,
//		 timeInfo->tm_mon + 1,
//		 timeInfo->tm_mday,
//		 timeInfo->tm_hour,
//		 timeInfo->tm_min,
//		 timeInfo->tm_sec
//	);

	timeInfo = localtime(&timeStamp);
	printf("address of timeInfo is 0x%p\n",timeInfo);
	timeInfo = localtime(&timeStamp);
	printf("address of timeInfo is 0x%p\n",timeInfo);
	
	printf
	(
		"localtime, %d-%d-%d %d:%d:%d\n",
		 timeInfo->tm_year + 1900,
		 timeInfo->tm_mon + 1,
		 timeInfo->tm_mday,
		 timeInfo->tm_hour,
		 timeInfo->tm_min,
		 timeInfo->tm_sec
	);
	
	printf("%s\n",asctime(timeInfo));


	//另外一个接口函数
	char timeArr[80];
	// 根据我们传入的格式解析结构体里面的成员
	strftime(timeArr,80,"%Y-%m-%d %H:%M:%S",timeInfo);
	printf("%s\n",timeArr);
	
		
	while (1)
	{
		TaskHandler();
	}
}

 程序的执行结果:

两次打印输出程序的打印输出的地址是一致的,在malloc等函数开辟栈堆空间中的地址存储的位置是一致的,使用堆进行存储需要手动的分配和释放,而使用栈存储的地址,存储数据的地址空间是不一致的。

简单来讲就是静态局部变量指针函数内存管理的区别


 RTC 初始化


RTC 软件架构


RTC API接口及数据结构定义

RTC 驱动程序

...


后记


...

time - > 2024-7-29


...

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

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

相关文章

DjangoRF实战-2-apps-users

1、用户模块 创建一个用户模块子应用&#xff0c;用来管理用户&#xff0c;和认证和授权。 1.1根目录创建apps&#xff0c; 为了使用方便&#xff0c;还需要再pycharm中设置一下资源路径&#xff0c;就可以自动提示 1.2注册子应用 1.3添加应用根目录到环境变量path python导…

搭建cool-admin-java(前端vue)项目

为什么选择 Cool Admin&#xff1f;​ 随着技术不断地发展&#xff0c;特别是最近 Ai 相关的技术发展&#xff0c;以往的框架已经越来越不能满足现代化的开发需求。 Cool Admin 做为后来者有后发优势&#xff0c;主要特点&#xff1a; Ai 编码&#xff0c;从页面到后端代码&…

成为git砖家(5): 理解 HEAD

文章目录 1. git rev-parse 命令2. 什么是 HEAD2.1 创建分支当并未切换&#xff0c; HEAD 不变2.2 切换分支&#xff0c;HEAD 改变2.3 再次切换分支&#xff0c; HEAD 再次改变 3. detached HEAD4. HEAD 表示分支、表示 detached HEAD 有什么区别&#xff1f;区别相同点 5. HEA…

【大模型学习】1:基于通用大语言模型的构建方法

基于通用大语言模型的构建 目录 前言 一、大模型是什么&#xff1f; 二、如何构建大语言模型&#xff1f; 1.基本介绍 2.数据 3.模型构建 总结 前言 本人之前没接触过大模型&#xff0c;研究生的研究方向也不是这一块的&#xff0c;所以是以工程的心态快速上手做到工科领域的不…

数据库实验:SQL Server创建数据库及基本表

一、实验目的&#xff1a; 1、掌握使用SQL SERVER Management Studio工具连接数据库引擎&#xff1b; 2、掌握使用CREATE TABLE 创建基本表的用法&#xff1b; 3、掌握使用ALTER TABLE 修改基本表的用法&#xff1b; 4、掌握使用DROP TABLE删除基本表的用法&#xff1b; 二…

【C++指南】类和对象(中)

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法》 期待您的关注

Python的输入规则

Python的输入特别有意思&#xff0c;它和C的输入不一样&#xff0c;它的输入的原型是类似于C的string类型&#xff0c;但是对于一些有意思的算法题来说&#xff0c;光是读入string型的内容并不容易解题&#xff0c;于是我们可以从两个方面来将输入给转化。 1. 先使用函数input…

【Node.js基础05】包的理解与使用

一&#xff1a;包的理解与简介 1 什么是包 包是一个将模块、代码、以及其他资料聚合成的文件夹 2 包的分类 项目包&#xff1a;编写项目代码的文件夹 软件包&#xff1a;封装工具和方法供开发者使用 3 为什么要在软件包中编写package.json文件 记录包的清单信息 二&…

用 node 搭建基于 gotenberg、LibreOffice 或者 onlyoffice 文档转换服务

1. 使用 gotenberg 和 LibreOffice a. 开启 docker&#xff0c;运行以下指令 docker run --rm -p 3000:3000 gotenberg/gotenberg:8 gotenbderg 默认运行在本地 3000 端口 b. 项目中添加如下依赖 npm install chromiumly dotenv -D chromiumly 是用来连接 gotenberg 服务的包…

深入理解计算机系统 CSAPP 练习题12.4

我们每次都用read_set初始化ready_set是因为我们每次都处理read_set里的描述符,这是我们希望服务器做的事情.每次一有描述符3或描述符0,select函数会更新ready_set ,我们判断更新后ready_set的情况.然后干对应的事. 由此可以看到select函数的神奇之处,它把一个复杂的事情简单化…

烯牛数据JS逆向:MD5数据加密?不存在的!

&#x1f50d; 步骤与思路详解 &#x1f575;️ 抓包数据接口 使用抓包工具捕获烯牛数据的接口请求&#xff0c;仔细观察请求体和响应体&#xff0c;发现数据均进行了加密处理。 &#x1f510; 定位到加密位置 分析抓取到的JS文件&#xff0c;找到负责加密的代码块。 &am…

研发管理革命:探索顶尖的工时系统选择

国内外主流的10款研发工时管理系统对比&#xff1a;PingCode、Worktile、无鱼项目工时系统、Toggl Track、泽众ALM、Asana、Jira、GitHub、Trello、TrackingTime。 在研发团队中&#xff0c;工时管理常常成为效率瓶颈&#xff0c;尤其是在资源分配和项目进度跟踪方面。选择合适…

面试 SQL整理 常见的SQL面试题:大厂经典60题(一)

目录 SQL基础知识整理: 数据库基础知识 为什么要使用数据库 数据保存在内存 数据保存在文件 数据保存在数据库 什么是SQL&#xff1f; 什么是MySQL? 数据库三大范式是什么 mysql有关权限的表都有哪几个 MySQL的binlog有有几种录入格式&#xff1f;分别有什么区别&…

【数学建模】——matplotlib简单应用

目录 1.绘制带有中文标签和图例的正弦和余弦曲线 2. 绘制散点图 1.修改散点符号与大小 2.修改颜色 3.绘制饼状图 4.在图例中显示公式 5.多个图形单独显示 6.绘制有描边和填充效果的柱状图 7.使用雷达图展示学生成绩 8.绘制三维曲面 9.绘制三维曲线 10.设置…

在 Postman 中设置全局 token

目录 问题描述解决方案 问题描述 在使用 Postman 进行接口测试时&#xff0c;经常会遇到在 Header 中添加 token 的情况。当接口数量较多时&#xff0c;需要为每个接口进行设置&#xff0c;而且当 token 失效时需要重新获取并设置&#xff0c;这样一来效率较低。 解决方案 下…

idea-springboot后端所有@注释含义汇总-持续更新!

&#xff08;1&#xff09;启动类 ①SpringBootApplication 出现这个代表这个就是整个程序的入口&#xff0c;是运行的开始位置 &#xff08;2&#xff09;Dao层 ①Repository 作用就是声明自己这个为bean文件&#xff08;每一个controller都是一个bean文件&#xff09;&am…

搭建自己的金融数据源和量化分析平台(四):自动化更新上市公司所属一级、二级行业以及股票上市状态

前面做了更新沪深交易所的上市股票列表的读取和更新&#xff0c;但一旦股票退市则需要在数据库里将该股票状态更新为退市&#xff0c;同时附上退市日期&#xff0c;将股票名更改为XX退。 此外深交所下载的xls解析出来是没有上市公司所属的二级行业的&#xff0c;因此还需要建立…

永磁同步电机无速度算法--非线性磁链观测器

非线性磁链观测器顾名思义观测器的状态变量为磁链值&#xff0c;观测的磁链值收敛于电机实际磁链值&#xff0c;观测器收敛。非线性是由于观测器存在sin和cos项&#xff0c;所以是非线性观测器 一、原理介绍 表贴式永磁同步电机αβ轴电压方程: 将公式变换 定义状态变量X: 定…

网络安全 DVWA通关指南 DVWA Command Injection(命令注入)

DVWA Command Injection&#xff08;命令注入&#xff09; 文章目录 DVWA Command Injection&#xff08;命令注入&#xff09;LowMediumHighImpossible Low 1、分析网页源代码 <?php// 当表单提交按钮&#xff08;Submit&#xff09;被触发时执行以下代码 if (isset($_P…

用Python编写用于IAR内存上传和下载的motorola格式转换工具

需求背景 IAR导出和载入内存支持 motorola 格式和 intel-extended 格式&#xff1a; 其中 motorola 格式以16进制表示&#xff0c;在输出文件中可以直接看到内存地址信息&#xff0c;并且文本长度比 intel-extended 格式更短。 所以我这里以 motorola 格式为基础&#xff0c;…