stm32f103c8t6学习笔记(学习B站up江科大自化协)-UNIX时间戳

news2024/12/23 13:13:31

UNIX时间戳 

        ·UNIX时间戳最早是在UNIX系统使用的,所以叫做UNIX时间戳,之后很多由UNIX演变而来的系统也继承了UNIX时间戳的规定,目前linux,windows,安卓这些操作系统的底层计时系统都是用UNIX时间戳

        ·时间戳这个计时系统和我们常用的年月日时分秒的计时系统具有较大的差别。

        年月日时分秒计时系统是每60秒进位1次,记为一分钟,每60分钟进位1次记为1小时,之后便是日月年        

        时间戳计时系统定义1970年1月1日0点整为0秒,之后只用最基本的秒计时,永不进位,无论数有多大都不进位。        

        这样有很多好处:

        第一,简化了硬件电路,在设计RTC硬件电路的时候直接用一个很大的寄存器即可,无需考虑其他的寄存器

        第二,在进行一些时间间隔的计算时非常方便,秒数相见换成时间很方便

        第三,存储方便,存储秒数一个很大的变量即可,存储年月日时分秒则需要很多变量

        坏处:比较占用软件资源,每次进行转换的时候软件需要进行复杂的计算

        ·时间戳存储在一个秒计数器中,计算机为了存储这一个永不进位的秒数,定义的变量类型通常会较大。变量类型在不同的系统中是不一样的。在早起的UNIX系统中,这个秒数大多是用32位有符号的整形变量进行存储,32位有符号数所能表示的最大数是2^{32} / 2 - 1,这个数是21亿多,有溢出的风险,根据计算,32位的有符号时间戳会在2038年的1月19号溢出,到时候采用32位有符号数存储时间戳的设备,计时系统会因数据溢出而出错,会导致很多不健全的计算机程序崩溃。

        随着操作系统和设备的更新换代,目前基本使用64位的数据存储时间戳。

        stm32核心的计时部分是一个32位的可编程计数器,说明这款stm32的时间戳是32位的数据类型,但是是无符号的32位,最大是2^{32} - 1,大概到2106年才会溢出

        ·地球上不一样的经度时间是不一样的,穿过英国伦敦的经线是本初子午线,这个位置的时间是一个时间标准,时间戳的1970年1月1日0时0分0秒也是指伦敦时间的0时0分0秒,其他地方分为24个时区,每偏差一个时区时间需要加或减一个小时

        对于不同地区是共用同一个时间戳的秒计数器,在伦敦是0,北京也是0,根据不同时区添加小时的偏移即可,伦敦是0点的时候,北京处于东八区就是8点

        图中的箭头代表的是一个时间轴,在时间轴上定义一个起点,时间戳从起点开始计时,起点是人为规定的,对于起点之前的时间,时间戳是无法表示的

UTC/GMT

        ·格林尼治是一个地名,位于英国伦敦,也就是伦敦的标准时间。在格林尼治有个天文台,可以观察天上太阳和星星以确定太阳的自转和公转,将地球自转一周的时间间隔分为24小时。

        GMT是以前的计时时间,因为存在一个棘手的问题,因为地球自转一周的时间是不固定的,由于潮汐力等因素导致地球处于越转越慢的状态,根据这个时间基准定义新的时间,那么这个时间基准是不断变化的,地球越转越慢,那么定义的1秒的时间也就越来越长

        ·为了时间的定义更标准,提出了新的计时系统,叫做UTC协调世界时。在原子钟计时系统的基础上加入了润秒的机制,来消除计时一天和自转一周的误差。所谓润秒就是计时标准是恒定不变的,但是地球越转越慢,当误差超过0.9秒的时候,计时系统就多走一秒等一下地球的自转。

        润秒的机制可能会造成一些程序的bug,可能会出现一分钟61秒的情况。平时不追求严谨的话使用GMT或UTC都可以

时间戳转换

·time_t time(time_t*):

        作用是获取系统时钟,返回值是time_t,表示当前系统时钟的秒计数期值,参数time_t*,是一个输出参数,输出的内容和返回值是一样的。这个函数可以通过返回值获取系统时钟,也可以通过输出参数获取。

        这个函数在电脑中可以直接读取电脑的时间,在STM32中无法使用,因为STM32是一个离线的裸机系统,无法获取目前的时间状态,

代码(使用DEV C++进行编写)
#include <stdio.h>
#include <time.h>

time_t time_cnt;//秒计数器	time_t是一个typedef重命名的类型  如果不是特别声明要用32位的秒计数器类型 
//那么默认状况下就是__time64_t  然后__time_t实际上是int64 是一个有符号的整型数据 无需担心溢出问题 可以用于存储时间戳中一直自增的秒数 
struct tm time_date;//tm是结构体类型名,time_date是结构体变量名 
char *time_str; 

int main()
{
	time_cnt = time(NULL);//参数不需要的话给null即可 
	printf("%d\n",time_cnt);
	return 0;
}

编译烧录后在中断可以看到这样的输出

         将终端的数值复制到网络上的时间戳在线转换工具中,进行转换,验证了数据是准确的

     将代码

time_cnt = time(NULL);

进行注释,替换成

time(&time_cnt);

也可以进行正常的显示当前的时间值

·struct tm* gmtime(const time_t):

        将秒计数器的值转换为格林尼治,也就是伦敦时间。

        参数是const time_t*,秒计数器指针类型,是输入参数,返回值struct tm*是日期时间结构体指针类型

        gmtime()的参数是time_t*,需要将地址传进去,返回值是struct tm*

        如果直接time_date = gmtime(&time_cnt)是指针跨级赋值,等号左边是一个变量,右边是一个地址,解决方法有两个:
        第一:time_date = *gmtime(&time_cnt),在函数的右边返回值加上*取内容,等号左右两边都是变量,结构体变量互相赋值是ok的 
        第二:定义变量的时候struct tm *time_date定义为指针类型,那么time_date = gmtime(&time_cnt)的等号左右都是指针,结构体指针之间相互赋值

代码(使用DEV C++进行编写)
#include <stdio.h>
#include <time.h>

time_t time_cnt;//秒计数器	time_t是一个typedef重命名的类型  如果不是特别声明要用32位的秒计数器类型 
//那么默认状况下就是__time64_t  然后__time_t实际上是int64 是一个有符号的整型数据 无需担心溢出问题 可以用于存储时间戳中一直自增的秒数 
struct tm time_date;//tm是结构体类型名,time_date是结构体变量名 
char *time_str; 

int main()
{
	//time_cnt = time(NULL);//参数不需要的话给null即可 
	//time(&time_cnt);
	time_cnt = 1713960225;
	printf("%d\n",time_cnt);
	
	time_date = *gmtime(&time_cnt);
	printf("%d\n",time_date.tm_year + 1900);//年份偏移	
	printf("%d\n",time_date.tm_mon+1);//月份偏移
	printf("%d\n",time_date.tm_mday);
	printf("%d\n",time_date.tm_hour+8);//北京时间东八区
	printf("%d\n",time_date.tm_min);
	printf("%d\n",time_date.tm_sec);
	printf("%d\n",time_date.tm_wday);

	return 0;
}

·struct tm* localtime(const time_t*):       

        转换当地时间,函数的使用方法和gmtime是一样的,作用也是一样的,不过localtime会根据时区自动添加小时的偏移,程序只需将gmtime的名字替换成localtime即可,这个函数会自动根据当前电脑的设置判断所处的时区,将时间添加时区偏移之后输出

·time_t mktime(struct tm*):

        将日期时间转换为秒计数器,mktime传入的日期时间需要是当地的,maketime就是前边两个转换的逆过程。

代码(使用DEV C++进行编写)

        编译烧录后,第一行是给定的时间秒数,中间是转换成当地的时间,最后一行是根据日期时间转换回的秒数,最终的秒数和最初的秒数是一样的。

        将localtime改成gmtime,最终的秒数就和最初的秒数不一样,说明mktime不是根据伦敦时间进行的  

        mktime的参数前边是没有const,这个参数既是输入参数也是输出参数。内部的工作过程是这样的:日期时间结构体,里面有年月日时分秒星期等数据,但是仅通过年月日时分秒就足以计算出秒计数器,里边的星期参数实际上是不作为输入参数的;但是相反的是,函数在算出秒数的同时还会顺便计算当前年月日是星期几,回填到结构体中的星期之中。使用这个函数可以很方便的计算对应的是星期几

#include <stdio.h>
#include <time.h>

time_t time_cnt;//秒计数器	time_t是一个typedef重命名的类型  如果不是特别声明要用32位的秒计数器类型 
//那么默认状况下就是__time64_t  然后__time_t实际上是int64 是一个有符号的整型数据 无需担心溢出问题 可以用于存储时间戳中一直自增的秒数 
struct tm time_date;//tm是结构体类型名,time_date是结构体变量名 
char *time_str; 

int main()
{
	//time_cnt = time(NULL);//参数不需要的话给null即可 
	//time(&time_cnt);
	time_cnt = 1713960225;
	printf("%d\n",time_cnt);
	
	time_date = *localtime(&time_cnt);
	printf("%d\n",time_date.tm_year + 1900);	
	printf("%d\n",time_date.tm_mon+1);
	printf("%d\n",time_date.tm_mday);
	printf("%d\n",time_date.tm_hour);
	printf("%d\n",time_date.tm_min);
	printf("%d\n",time_date.tm_sec);
	printf("%d\n",time_date.tm_wday);

	time_cnt = mktime(&time_date); //参数是日期时间结构体指针 可以传入日期时间结构体的地址 返回秒计数器的值 
	printf("%d\n",time_cnt);
	return 0;
}

char* ctime(const time_t*):

        将秒计时器转换成字符串表示,使用默认的格式,相当于转换成char* 格式的字符串

char* asctime(const struct tm*):

        将日期转换为字符串,使用默认格式。相当于转换成char* 格式的字符串

代码:两个函数卸载一块进行展示
#include <stdio.h>
#include <time.h>

time_t time_cnt;//秒计数器	time_t是一个typedef重命名的类型  如果不是特别声明要用32位的秒计数器类型 
//那么默认状况下就是__time64_t  然后__time_t实际上是int64 是一个有符号的整型数据 无需担心溢出问题 可以用于存储时间戳中一直自增的秒数 
struct tm time_date;//tm是结构体类型名,time_date是结构体变量名 
char *time_str; 

int main()
{
	//time_cnt = time(NULL);//参数不需要的话给null即可 
	//time(&time_cnt);
	time_cnt = 1713960225;
	printf("%d\n",time_cnt);
	
	time_date = *localtime(&time_cnt);
	printf("%d\n",time_date.tm_year + 1900);	
	printf("%d\n",time_date.tm_mon+1);
	printf("%d\n",time_date.tm_mday);
	printf("%d\n",time_date.tm_hour+8);
	printf("%d\n",time_date.tm_min);
	printf("%d\n",time_date.tm_sec);
	printf("%d\n",time_date.tm_wday);

	time_cnt = mktime(&time_date); //参数是日期时间结构体指针 可以传入日期时间结构体的地址 返回秒计数器的值 
	printf("%d\n",time_cnt);
		
	time_str = ctime (&time_cnt);
	printf(time_str);
	
	time_str = asctime (&time_date);
	printf(time_str);
	
	return 0;
}

 编译运行后显示的为下图所示(最后两行)

size_t strftime(char*,size_t,const char*,const struct tm*):

        这个函数作用同上边两个函数一样,但是区别是可以自定义格式。输入下列代码接在前边的代码后边,

char t[50]; 
strftime(t,50,"%H-%M-%S",&time_date);//前两个参数需要传入一个字符数组和数组长度 第三个参数需要给定指定的格式字符串 第四个参数把time_date传进去即可 
printf(t);

         其中关于第三个参数的格式,可以参考菜鸟教程中的文件,

       编译烧录后得到结果在最后一行

菜鸟教程

        clock_t clock(void)函数可以用于计算程序执行的时长,

        double difftime(time_t time1,time_t2 time2)可以计算两个时间之间的差值

        最重要且最复杂的是其中的localtime 和mktime函数,在STM32的RTC程序会使用到,需要重点掌握

各个函数的关系和作用

秒计数器数据类型time_t:

        秒计数器,time_t是一个typedef重命名的类型  如果不是特别声明要用32位的秒计数器类型,那么默认状况下就是__time64_t ,__time_t实际上是int64,是一个有符号的整型数据,无需担心溢出问题,可以用于存储时间戳中一直自增的秒数 

日期时间数据类型struct tm:

        struct tm time_date;//tm是结构体类型名,time_date是结构体变量名.

        关于struct tm里边的变量定义如下

  struct tm {
    int tm_sec;	//表示秒 取值范围0-59 
    int tm_min;	//表示分钟 取值范围0-59 
    int tm_hour; //表示午夜开始的小时 取值范围0-23 
    int tm_mday; //表示一个月的几号 取值范围0-31 
    int tm_mon;  //表示1月开始的第几个月 取值范围0-11 1月是0 12月是11 参数值需要加1才是所需月份 
    int tm_year; //表示从1900年的第几年 所以参数需要加上1900才是年份 时间戳起点是1970 参数最小值是70 
    int tm_wday; //表示周末开始的星期几  0表示周日  1表示周一  直到6表示周六 
    int tm_yday; //表示从1月1号开始的第几天 取值范围0-365 
    int tm_isdst; //是否使用夏令时 +1表示使用 0表示不用 -1表示不知道 
  };
字符串数据类型char*

        char型数据的指针,用于表示一个指向时间的字符串

        需要在ST_Link上引出一个3.3V电源接到stm32的VBAT引脚上,用于模拟电池的电源,一般情况下VBAT是电池供电口,需要接备用电池

        BKP寄存器和Flash存储器类似,都是用于存储数据,不过Flash的数据是掉电不丢失,而BKP的数据是需要通过VBAT引脚上的备用电池来维持的。只要VBAT有电池供电,即使STM32主电源断电,BKP的值仍然可以维持原状,并且在按下系统复位键之后,BKP的数据并不会产生复位

        如果把VBAT的电池断电,再次拔掉主电源上电,BKP的数据被清零,因为BKP的本质并不完全掉电不丢失,数据需要VBAT引脚提供备用电源维持。如果stm32接了备用电池,那么BKP可以完成主电源掉电时保存少量数据的任务。



实时时钟

        第一行显示日期,给的是一个测试时间;第二行是时间;第三行是时间戳的秒计数器;第四行是RTC预分频器的计数值

        作为实时时钟,按下复位键的时候不能复位,时间会继续运行。实时时钟在系统主电源断电之后需要继续运行,就像手机关机后时钟需继续运行,否则造成时间错误。在VBAT接上了电源再断开系统主电源,可以看到时间数据不会丢失,并且在断电期间RTC会继续走时不会暂停,是借助BKP实现的,RTC与BKP关联度较高

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

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

相关文章

C++ Qt QMainWindow实现无边框窗口自定义标题栏可拖拽移动拉伸改变窗口大小

本篇博客介绍C Qt QMainWindow实现无边框窗口&#xff0c;适用于win10/win11系统。 QMainWindow相对于QWidget多了dockedwidget功能&#xff0c;跟多人可能更喜欢用QMainWindow做主窗口&#xff0c;如果不需要dockedwidget功能&#xff0c;QMainWindow与QWidget做主窗口基本无…

Spring - 4 ( 11000 字 Spring 入门级教程 )

一&#xff1a;Spring IoC&DI 在前⾯的章节中, 我们学习了 Spring Boot 和 Spring MVC 的开发, 可以完成⼀些基本功能的开发了, 但是什么是 Spring 呢? Spring, Spring Boot 和 SpringMVC 又有什么关系呢? 咱们还是带着问题去学习.我们先看什么是Spring 1.1 Spring 是什…

万兆以太网MAC设计(7)ARP协议报文格式详解以及ARP层模块设计

文章目录 前言&#xff1a;1、ARP协议详解2、ARP工作机制 二、ARP_RX模块设计三、ARP_TX模块设计四、ARP_table模块5、仿真5.1、发送端5.2、接收端5.3、缓存表 总结 前言&#xff1a; 1、ARP协议详解 ARP数据格式&#xff1a; 硬件类型:表示硬件地址的类型。它的值为1表示以太…

微信小程序使用echarts组件实现饼状统计图功能

微信小程序使用echarts组件实现饼状统计图功能 使用echarts实现在微信小程序中统计图的功能&#xff0c;具体的实现步骤思路可进我主页查看我的另一篇博文https://blog.csdn.net/weixin_45465881/article/details/138171153进行查看&#xff0c;本篇文章主要使用echarts组件实…

javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 小比特 大梦想 此篇文章与大家分享多线程专题的最后一篇文章:关于JUC常见的类以及线程安全的集合类 如果有不足的或者错误的请您指出! 目录 3.JUC(java.util.concurrent)常见的类3.1Callable接口3.2 RentrantLoc…

Yolov5 v7.0目标检测——详细记录环境配置、自定义数据处理、模型训练与常用错误解决方法(数据集为河道漂浮物)

1. Yolov5 YOLOv5是是YOLO系列的一个延伸&#xff0c;其网络结构共分为&#xff1a;input、backbone、neck和head四个模块&#xff0c;yolov5对yolov4网络的四个部分都进行了修改&#xff0c;并取得了较大的提升&#xff0c;在input端使用了Mosaic数据增强、自适应锚框计算、自…

鸿蒙云函数调试坑点

如果你要本地调试请使用 const {payload, action} event.body/** 本地调试不需要序列化远程需要序列化 */ // const {payload, action} JSON.parse(event.body) const {payload, action} event.body 注意: 只要修改云函数&#xff0c;必须上传云函数 如果使用 const {pay…

牛客NC98 判断t1树中是否有与t2树完全相同的子树【simple 深度优先dfs C++/Java/Go/PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/4eaccec5ee8f4fe8a4309463b807a542 思路 深度优先搜索暴力匹配 思路和算法这是一种最朴素的方法——深度优先搜索枚举 s 中的每一个节点&#xff0c;判断这个点的子树是否和 t 相等。如何判断一个节点的子树是否…

HTTP/1.1,HTTP/2.0和HTTP/3.0 各版本协议的详解(2024-04-24)

1、HTTP介绍 HTTP 协议有多个版本&#xff0c;目前广泛使用的是 HTTP/1.1 和 HTTP/2&#xff0c;以及正在逐步推广的 HTTP/3。 HTTP/1.1&#xff1a;支持持久连接&#xff0c;允许多个请求/响应通过同一个 TCP 连接传输&#xff0c;减少了建立和关闭连接的消耗。 HTTP/2&#…

基于STM32和阿里云的智能台灯(STM32+ESP8266+MQTT+阿里云+语音模块)

一、主要完成功能 1、冷光模式和暖光模式两种灯光 主要支持冷光和暖光模式两种&#xff0c;可以通过语音模块或手机app远程切换冷暖光 2、自动模式和手动模式 主要支持手动模式和自动两种模式&#xff08;app或语音助手切换&#xff09; (1)自动模式&#xff1a;根据环境光照…

vscode 使用文件模板功能来添加版权信息

vscode 新建文件的时候&#xff0c;自动填充作者及版权信息 无需使用插件&#xff0c;操作如下&#xff1a; 选择 “首选项(Preferences)”。在搜索框中输入 “file template” 或者 “文件模板”&#xff0c;然后选择相关的设置项。 {"C_Cpp.clang_format_fallbackSt…

[lesson58]类模板的概念和意义

类模板的概念和意义 类模板 一些类主要用于存储和组织数据元素 类中数据组织的方式和数据元素的具体类型无关 如&#xff1a;数组类、链表类、Stack类、Queue类等 C中将模板的思想应用于类,使得类的实现不关注数据元素的具体类型,而只关注类所需要实现的功能。 C中的类模板…

Docker 开启远程安全访问

说明 如果你的服务器是公网IP&#xff0c;并且开放了docker的远程访问&#xff0c;如果没有进行保护是非常危险的&#xff0c;任何人都可以向你的docker中推送镜像、运行实例。我曾开放过阿里云服务器中docker的远程访问权限&#xff0c;在没有开启保护的状态下&#xff0c;几…

企业微信hook接口协议,根据手机号搜索联系人

根据手机号搜索联系人 参数名必选类型说明uuid是String每个实例的唯一标识&#xff0c;根据uuid操作具体企业微信 请求示例 {"uuid":"3240fde0-45e2-48c0-90e8-cb098d0ebe43","phoneNumber":"1357xxxx" } 返回示例 {"data&q…

抖音 小程序 获取手机号 报错 getPhoneNumber:fail auth deny

这是因为 当前小程序没有获取 手机号的 权限 此能力仅支持小程序通过试运营期后可用&#xff0c;默认获取权限&#xff0c;无需申请&#xff1b; https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/guide/open-capabilities/acquire-phone-number-acqu…

用斐波那契数列感受算法的神奇(21亿耗时0.2毫秒)

目录 一、回顾斐波那契数列 二、简单递归方法 &#xff08;一&#xff09;解决思路 &#xff08;二&#xff09;代码展示 &#xff08;三&#xff09;性能分析 三、采用递归HashMap缓存 &#xff08;一&#xff09;解决思路 &#xff08;二&#xff09;代码展示 &…

深度学习系列65:数字人openHeygen详解

1. 主流程分析 从inference.py函数进入&#xff0c;主要流程包括&#xff1a; 1&#xff09; 使用cv2获取视频中所有帧的列表&#xff0c;如下&#xff1a; 2&#xff09;定义Croper。核心代码为69行&#xff1a;full_frames_RGB, crop, quad croper.crop(full_frames_RGB)。…

公开课学习——基于索引B+树精准建立高性能索引

文章目录 遇到慢查询怎么办&#xff1f;—— 创建索引联合索引的底层的数据存储结构长什么样&#xff1f; mysql脑图 阿里开发手册 遇到慢查询怎么办&#xff1f;—— 创建索引 不用索引的话一个一个找太慢了&#xff0c;用索引就快的多。 假如使用树这样的结构建立索引&#x…

Spring - 3 ( 12000 字 Spring 入门级教程 )

一&#xff1a;Spring Web MVC入门 1.1 响应 在我们前⾯的代码例子中&#xff0c;都已经设置了响应数据, Http 响应结果可以是数据, 也可以是静态页面&#xff0c;也可以针对响应设置状态码, Header 信息等. 1.2 返回静态页面 创建前端页面 index.html(注意路径) html代码 …

frp 实现 http / tcp 内网穿透(穿透 wordpress )

frp 实现 http / tcp 内网穿透&#xff08;穿透 wordpress &#xff09; 1. 背景简介与软件安装2. 服务端配置2.1 配置文件2.2 wordpress 配置文件2.3 frps 自启动 3.客户端配置3.1 配置文件3.2 frpc 自启动 同步发布在个人笔记frp 实现 http / tcp 内网穿透&#xff08;穿透 w…