写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做!
本文写于:2025.04.18
STM32开发板学习——第41节: [12-1] Unix时间戳
- 前言
- 开发板说明
- 引用
- 解答和科普
- 一、Unix时间戳
- 问题
- 总结
前言
本次笔记是用来记录我的学习过程,同时把我需要的困难和思考记下来,有助于我的学习,同时也作为一种习惯,可以督促我学习,是一个激励自己的过程,让我们开始32单片机的学习之路。
欢迎大家给我提意见,能给我的嵌入式之旅提供方向和路线,现在作为小白,我就先学习32单片机了,就跟着B站上的江协科技开始学习了.
在这里会记录下江协科技32单片机开发板的配套视频教程所作的实验和学习笔记内容,因为我之前有一个开发板,我大概率会用我的板子模仿着来做.让我们一起加油!
另外为了增强我的学习效果:每次笔记把我不知道或者问题在后面提出来,再下一篇开头作为解答!
开发板说明
本人采用的是慧净的开发板,因为这个板子是我N年前就买的板子,索性就拿来用了。另外我也购买了江科大的学习套间。
原理图如下
1、开发板原理图
2、STM32F103C6和51对比
3、STM32F103C6核心板
视频中的都用这个开发板来实现,如果有资源就利用起来。另外也计划实现江协科技的套件。
下图是实物图
引用
【STM32入门教程-2023版 细致讲解 中文字幕】
还参考了下图中的书籍:
STM32库开发实战指南:基于STM32F103(第2版)
数据手册
解答和科普
一、Unix时间戳
实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。
系统复位后,对后备寄存器和RTC的访问被禁止,这是为了防止对后备区域(BKP)的意外写操作。执行以下操作将使能对后备寄存器和RTC的访问: ● 设置寄存器RCC_APB1ENR的PWREN和BKPEN位,使能电源和后备接口时钟 ● 设置寄存器PWR_CR的DBP位,使能对后备寄存器和RTC的访问。
VBAT接3.3V电源,在BKP备份寄存器写入两个数据,然后再把它们读出来,显示一下,BKP备份寄存器和上一节学的Flash存储器类似,而BKP的数据,是需要VBAT引脚接上备用电池来维持的,只要VBAT有电池供电,即使STM32主电源断电,BKP的值也可以维持原状。现在STM32断电,但是VBAT有电,可以维持BKP的数据,再次上电后,在没有写数据的情况下,直接读出BKP,它的数据和断电之前是一样的,这说明BKP的数据在主电源断电后,得到了保持,并且按下复位键,可以按下复位键,BKP的数据也不会复位,那如果把VBAT的电池断电,再次拔掉主电源,重新上电,BKP的数据就清零了,因为BKP本质上,不能完全掉电不丢失,它的数据,需要VBAT引脚提供备用电源来维持,这就是BKP备份寄存器的特性。如果你的STM32接了备用电池,那BKP可以完成一些主电源掉电时,保存少量数据的任务,这就是第一个代码的现象。其实备份寄存器和VBAT引脚的存在,更多的是为了服务RTC的。
第二个代码,实时时钟。第一行是日期,目前给的一个测试时间,2023年1月2日,第二行是时间,目前是0时0分这些秒,第三行是时间戳的秒计数器,目前是16亿多。第四行时RTC预分频器的计数值。首先是复位,复位之后时间会继续运行,然后,实时时钟,在系统主电源断电后,他还要继续运行。关机后,里面时钟还必须要继续走,所以只要在VBAT接上了备用电源,在断开系统主电源,然后插上,可以看到时间数据不会丢失,并且,在主电源断开的时间里,RTC会继续走,不会因为主电源断电而暂停,这就是RTC实时时钟的程序现象。可以发现,RTC这个复位和主电源掉电后,数据不丢失,就是借用BKP来实现的,所以RTC和BKP关联程度是比较高的,这就是实时时钟的程序现象。
BUG,给主电源断电后,VBAT的电源还会给微弱地整个系统供电,这导致我主电源拔掉后,电源指示灯和OLED屏幕还会微弱地亮着,这是一个问题。还有的芯片,在进行RTC实验时,会出现RTC晶振不起振的情况,这会导致程序卡死在等待晶振起振的地方,这个问题我还没有找到完美的解决方法,但是在学习过程中,也是可以有一些替代方法可以使用的。
Uinx时间戳:定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数,不考虑闰秒。
这款STM32,它的时间戳是32位的数据类型,这个时间戳,在STM32程序中定义的其实是无符号的32位,无符号32最大数值是2^32-1.
世界上所有时区的秒计数器相同,不同时区通过添加偏移来得到当地时间.所有时区共用一个时间戳的秒计数器,也就是在伦敦秒计数器是0,在北京也是0,然后根据不同时区,再加上时间偏移,就能确定了。
当原子钟计时一天的时间与地球自转一周的时间相差超过0.9秒时,UTC会执行闰秒来保证其计时与地球自转的协调一致,计时标准不变,地球越转越慢,相差超过0.9秒时,我的计时系统就多走一秒,来等一下地球的自转,会出现7时59分60秒。闰秒机制的设计,也会造成一些程序BUG,1分钟会有61秒的情况。
秒计数器和日期时间,如何进行相互转换,这时候需要用到time.h模块。
C语言的time.h模块,提供了时间获取和时间戳转换的相关函数,可以方便地进行秒计数器、日期时间和字符串之间的转换,使用还是非常方便的。
秒计数器类型名,叫作time_t,其实是一个typedef重命名的类型,实际上就是int64类型,是一个64位有符号的整形数据。
下一个时间类型是日期时间数据类型strruct tm
年代是1900年。
在STM32中,使用的是typedef struct 新名字,这样的形式定义的。这里没有使用typedef,而是在花括号前给结构体起来一个名字,叫tm,这样在使用的时候,数据类型名,就是两个词struct tm,然后跟着的是变量名,这样的方式也是可以的。和我们STM32库函数里的方式是一样的效果。
接着最后一个,是字符串数据类型,类型名是char *,就是char型数据的指针,用来表示指向一个表示时间的字符串。
time()是用来获取当前时间的,这个函数,在电脑里,可以直接读取电脑的时间,但是在STM32是用不了的,因为STM是一个离线的裸机系统,它也不知道是什么时间,
有了秒计数器后,接着把它转换为日期时间的格式,第二个,gmtime,将秒计数器的值,转换为格林尼治,也就是伦敦时间,参数是const time_t ,秒计数器指针类型,是输入参数,返回值struct tm 是日期时间结构体指针类型,在这个图里,它的作用就是这里,秒计数器转换为日期时间。
time_data = gmtime(time_cnt);这样,就是指针跨级赋值;等号右边是地址,等号左边却是一个变量,这是不行的,有两个,一个是在右边,函数的返回值,加上*,取内容,
time_data= gmtime(time_cnt);
这样的好左右就都是变量了,结构体变量之间互相赋值,没问题,或者右边不加,定义的变量,我们定义为指针类型,这样等号左右都是指针,结构体指针之间互相赋值,也没问题,这两种方法都可以。
年时:是从1900年经过的年数,月是从月经过的月数。
问题
总结
本节课主要是学习了Unix时间戳,和如何用函数实现时间戳到现在时间的转换,相互的,转换与被转换。