你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

发布基于ANSI-C的RTC_Time库,利用UNIX时间戳格式,无中断实现万年历

[复制链接]
jjldc 发布时间:2009-1-4 16:19
基于STM32处理器
! W& P/ |9 ^# C$ R& J- B! Q$ b& ^RTC只是个能靠电池维持运行的32位定时器over!
' A1 g& j1 y3 s% m并不像实时时钟芯片,读出来就是年月日。。。  w" t4 q& Z! x' t2 _8 F
看过些网上的代码,有利用秒中断,在内存中维持一个年月日的日历。
- [  S0 `; {" i- J0 X, K我觉得,这种方法有很多缺点:
+ J$ r) h% p6 W) p" S) M% H1.断电时没有中断可用" O2 [) @% E$ S
2.频繁进中断,消耗资源; _0 W+ [: z& r/ F% x
3.时间运算复杂,代码需要自己写
5 O6 O4 f) Y9 W$ T$ j* t4.不与国际接轨。。。。8 X9 h2 u6 b+ m/ P9 K$ m- r0 ^
. w% d+ p- e! B, |& Y; m% z  A
so,还是用标准的UNIX时间戳来进行时间的操作吧!$ B: K& W1 ~! n3 L% X7 I& b
什么是UNIX时间戳?
! j. S/ u! s. ]/ \UNIX时间戳,是unix下的计时方式。。。很废话6 J6 b- o: q& q" j0 G8 i* E
具体点:他是一个32位的整形数(刚好和STM32的RTC寄存器一样大),表示从UNIX元年(格林尼治时间1970-1-1 0:0:0)开始到某时刻所经历的秒数
: b- @0 I2 }- W0 f% l' h听起来很玄幻的,计算下: 32位的数从0-0xFFFFFFFF秒,大概到2038年unix时间戳将会溢出!这就是Y2038bug
2 u$ t& a  [+ [/ N+ r3 ~/ b不过,事实上的标准,我们还是照这个用吧,还有二十年呢。。。3 Z- p& V: m# H- r

5 X- |' y3 s5 J' W2 z$ E1 gUNIX时间戳:1229544206  现实时间:2008-12-17  20:03:26 $ Z" J8 e6 I& X8 n2 E
& ?. _  A) }/ j/ C
我们要做的,就是把当前时间的UNIX时间戳放在RTC计数器中让他每秒++,over
7 ^0 R$ \$ x+ O然后,设计一套接口函数,实现UNIX时间戳与年月日的日历时间格式转换 这样就可以了5 x; t( e4 ~" A
( f* a- |; B' _
在RTC中实现这个时间算法,有如下好处:
5 p2 B& r% M8 _7 W/ x1. 系统无需用中断和程序来维持时钟,断电后只要RTC在走即可
/ Q0 G. l: y. S3 {6 a2. 具体的两种计时的换算、星期数计算,有ANSI-C的标准C库函数实现,具体可以看time.h$ N1 a* x. Y: H
3. 时间与时间的计算,用UNIX时间戳运算,就变成了两个32bit数的加减法* ]* l0 e; u$ k$ S, Y' u
4. 与国际接轨。。。
7 F9 C9 a! Q8 f+ v  H
5 o! C3 D2 b- f4 G9 q4 a/ K5 f5 u5 ?7 S* e
幸好是与国际接轨,我们有time.h帮忙,在MDK的ARM编辑器下有,IAR下也有" L2 j0 U) L/ M/ n/ [% C0 W$ S
其中已经定义了两种数据类型:unix时间戳和日历型时间* t7 u+ K) ~3 r4 N& y& A
 time_t:       UNIX时间戳(从1970-1-1起到某时间经过的秒数)6 l& s) Y, F" p7 F4 P5 x: M
     typedef unsigned int time_t;7 S* H2 }2 W! e
 * H% n; \* p+ e; b5 \2 w! n
 struct tm:    Calendar格式(年月日形式)! Q( F& l& Y- R* y& p! c" G& n! P

1 |, }5 S1 d. T# m" U# G" \同时有相关操作函数- q- L9 r' g' E% A. i/ U
gmtime,localtime,ctime,mktime等等,方便的实现各种时间类型的转换和计算
4 j' K) o; `) A- s) K$ |* y6 E
于是,基于这个time.h,折腾了一天,搞出了这个STM32下的RTC_Time使用的时间库  K. m' X/ C! v) N
* n3 r  ]9 [8 ]3 d. Q# S1 k" _1 N

: T$ X/ o" ?% K& J这是我的RTC_Time.c中的说明:
$ O- _1 R7 s7 ^0 L- S3 Q0 H% }1 K9 C/ F, P- B0 a8 L
 本文件实现基于RTC的日期功能,提供年月日的读写。(基于ANSI-C的time.h)- X2 S( z! X7 b7 q& D
 & U0 o1 u& r' r% ?
 作者:jjldc (九九); C0 i/ k3 }! Q5 V
 QQ: 77058617( x) [9 ?, d; t$ W: ~
 
) B) _7 p- _, [) q+ k, b, Z- Q RTC中保存的时间格式,是UNIX时间戳格式的。即一个32bit的time_t变量(实为u32)
# ~1 ~3 B: z3 \# s' O; G7 F, \
0 ~" b" ~; s- m* L ANSI-C的标准库中,提供了两种表示时间的数据  型:3 \9 w2 C; X; f! a
 time_t:       UNIX时间戳(从1970-1-1起到某时间经过的秒数)
" e/ H$ H8 I( |* K) v4 ?     typedef unsigned int time_t;: Q* d( F0 N" w% L  c8 x3 h
 
/ H) P# G; H! g) v struct tm:    Calendar格式(年月日形式)
' m7 }) f) ]/ h8 R) s   tm结构如下:
( A( U+ }5 m+ O% h2 Z   struct tm {7 G! ^, O4 e$ A# G3 d  h) q9 ~5 k
       int tm_sec;   // 秒 seconds after the minute, 0 to 60* j- D4 _- A  y5 w" j
                        (0 - 60 allows for the occasional leap second)
. N$ j8 X8 J( ], g       int tm_min;   // 分 minutes after the hour, 0 to 59
% W; J! |/ G5 A& x, b        int tm_hour;  // 时 hours since midnight, 0 to 23
' `0 _5 `; }: |) N        int tm_mday;  // 日 day of the month, 1 to 31, F' D6 |0 I" q, g  {2 R
        int tm_mon;   // 月 months since January, 0 to 112 X& G# l5 Z' o! W, T8 t0 }. P: n' Q* o$ p
        int tm_year;  // 年 years since 19008 m7 q" V: d4 X: c
        int tm_wday;  // 星期 days since Sunday, 0 to 6/ V" b7 J6 o$ ?* G
        int tm_yday;  // 从元旦起的天数 days since January 1, 0 to 365. {, M7 R" X/ ~, T( z* \9 h
         int tm_isdst; // 夏令时??Daylight Savings Time flag: P2 s1 \+ b' i  N& t
         ...3 ?# g/ x8 ?' l# E0 m: _
     }/ i' V4 w4 q& @( D2 [
     其中wday,yday可以自动产生,软件直接读取
" q& ^. M0 U9 y" k     mon的取值为0-11
3 c: g, I! @' y& S    ***注意***:
7 b5 S) l4 {% k$ \$ L: Y    tm_year:在time.h库中定义为1900年起的年份,即2008年应表示为2008-1900=108
! ~9 T% o. T( t     这种表示方法对用户来说不是十分友好,与现实有较大差异。! {8 B7 ]  }' ^# E0 B7 e
     所以在本文件中,屏蔽了这种差异。- R3 Q/ i7 N& z7 W) S
     即外部调用本文件的函数时,tm结构体类型的日期,tm_year即为20084 U" j9 Q* T) ]! T$ `
     注意:若要调用系统库time.c中的函数,需要自行将tm_year-=1900
  y* Q# e$ M$ q) |+ s 
- o8 z4 N& B6 V' a 成员函数说明:8 w) C( t3 ~4 z& v
 struct tm Time_ConvUnixToCalendar(time_t t);& [7 x! P# V" E$ X# @- w4 j3 `
     输入一个Unix时间戳(time_t),返回Calendar格式日期
1 K& M1 j4 D& W8 c' F# j time_t Time_ConvCalendarToUnix(struct tm t);
& ~7 {, S: J. f2 A; I/ ?3 ?8 d' B     输入一个Calendar格式日期,返回Unix时间戳(time_t)3 m: r7 `( ~& Q
 time_t Time_GetUnixTime(void);1 x7 s+ m! w1 V+ Q! D! z
     从RTC取当前时间的Unix时间戳值
# {+ f: ~' z* o9 R+ ^3 |9 d struct tm Time_GetCalendarTime(void);
8 P, V2 ^: k- M( v7 B0 M+ ^8 \     从RTC取当前时间的日历时间
: T+ H8 H: i7 K, W: ~8 N void Time_SetUnixTime(time_t);. f: X9 y0 {8 U( W
     输入UNIX时间戳格式时间,设置为当前RTC时间! m' R, [1 [4 F$ r3 l/ h8 {, C
 void Time_SetCalendarTime(struct tm t);5 C2 G5 D) o. r* T
     输入Calendar格式时间,设置为当前RTC时间  w, z% W5 z& L9 |  x
 4 c8 t  @% e; W7 I& i# S8 p9 b
 外部调用实例:
' {: _% K9 Y  a# b 定义一个Calendar格式的日期变量:
4 {, m5 f' u8 V9 J3 n/ D struct tm now;& S/ m7 y2 V4 v% q! `$ q7 j! r
 now.tm_year = 2008;
4 n4 m; q8 j8 Q1 C8 m now.tm_mon = 11;        //12月- J+ T  q* Z6 N( e' F
 now.tm_mday = 20;& a8 M. y# U& M# R; G" y8 X
 now.tm_hour = 20;& w* P( r+ f9 a- l; {
 now.tm_min = 12;
: J, u+ w5 F4 u+ [* z4 b/ L now.tm_sec = 30;
5 }& l8 X2 \, V  ]' Y5 J1 { 7 D* [+ S( m9 o4 [+ M9 C
 获取当前日期时间:
4 O9 N, G; R; U$ x) C tm_now = Time_GetCalendarTime();% _  c  s' o/ B
 然后可以直接读tm_now.tm_wday获取星期数
+ S/ R/ N% W2 i1 X: y 6 j: l% _( @3 g- c8 `- x
 设置时间:
0 ?# B4 Z1 `5 w9 l3 L5 Z9 d Step1. tm_now.xxx = xxxxxxxxx;; b4 L. d% E/ D$ X. G, C
 Step2. Time_SetCalendarTime(tm_now);, M" {' X( f* v8 g5 O8 N/ d0 g, g
 
- ]  l! [8 e+ E2 R" d/ C 计算两个时间的差, I' T. [7 p: I" ]: t4 j5 W
 struct tm t1,t2;
, d$ s2 l" u+ ?# [8 ]# `4 ~ t1_t = Time_ConvCalendarToUnix(t1);
, v$ T3 H$ o  h. Y4 p' b t2_t = Time_ConvCalendarToUnix(t2);7 J  N# c& u4 d; ~+ S6 p/ c
 dt = t1_t - t2_t;) X$ U) \8 e; }1 P
 dt就是两个时间差的秒数
6 G" |, U- w/ C dt_tm = mktime(dt);    //注意dt的年份匹配,ansi库中函数为相对年份,注意超限
- W6 o& b) C/ H% R' L2 p 另可以参考相关资料,调用ansi-c库的格式化输出等功能,ctime,strftime等+ K, u% z7 X/ \0 A* V" [
 
# W0 {$ o  t9 B5 r6 P. b" j. y9 n% G2 ^# Y
这是包含了RTC_Time的工程实例,可以用来参考
% R5 Q7 C" b0 R9 ~+ r基于MDK环境- K- j, ]+ M+ [, V% Z1 D3 ]" f1 w
 
2 c" `5 c8 ~; s* [( `' V 

发布基于ANSI-C的RTC_Time库,利用UNIX时间戳格式,无中断实现万年历.rar

下载

179.12 KB, 下载次数: 92

收藏 评论0 发布时间:2009-1-4 16:19

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版