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

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

[复制链接]
jjldc 发布时间:2009-1-4 16:19
基于STM32处理器
4 j8 P- @7 g7 T4 oRTC只是个能靠电池维持运行的32位定时器over!
) f& _5 E! Y; `并不像实时时钟芯片,读出来就是年月日。。。5 Y* y' _5 W# |
看过些网上的代码,有利用秒中断,在内存中维持一个年月日的日历。4 P% e) ^% Y0 o4 c* I
我觉得,这种方法有很多缺点:( S0 t' ~% r/ k2 M
1.断电时没有中断可用( y, ]! k9 Z- Q3 M/ n
2.频繁进中断,消耗资源0 ~0 B& Q# X+ Y# b9 }4 W
3.时间运算复杂,代码需要自己写
4 |! }( Y( I3 d/ X+ z) p) S7 |4.不与国际接轨。。。。& I6 j3 m1 `* i8 ~) P: B: B
" ?; g; n0 `+ x; u) v
so,还是用标准的UNIX时间戳来进行时间的操作吧!
* D. @0 g& M. X; I& h$ Q6 q什么是UNIX时间戳?
1 S) ]# J* V$ c3 g% jUNIX时间戳,是unix下的计时方式。。。很废话
! ^( F. G" d8 G% @( o- I; I具体点:他是一个32位的整形数(刚好和STM32的RTC寄存器一样大),表示从UNIX元年(格林尼治时间1970-1-1 0:0:0)开始到某时刻所经历的秒数* B7 l! L. W9 R2 a, u* ^
听起来很玄幻的,计算下: 32位的数从0-0xFFFFFFFF秒,大概到2038年unix时间戳将会溢出!这就是Y2038bug
# l( `- n8 [: E8 h) ?" n. D) q不过,事实上的标准,我们还是照这个用吧,还有二十年呢。。。
' E0 y/ a" D3 e+ ]% \
) g& B5 A! V; I8 U  M5 _! WUNIX时间戳:1229544206  现实时间:2008-12-17  20:03:26
& c' t7 F/ c% d8 `- [2 W/ y7 ?. ~. n1 M$ v1 v/ V8 R
我们要做的,就是把当前时间的UNIX时间戳放在RTC计数器中让他每秒++,over
% t8 G8 W$ P+ |! S& V! U然后,设计一套接口函数,实现UNIX时间戳与年月日的日历时间格式转换 这样就可以了  r5 t' {. ^6 C9 ^
* M1 t  ~/ G8 Z! Y, E9 G  W; p
在RTC中实现这个时间算法,有如下好处:1 }/ _; U1 q, ]  T- d& d% H) ^( I
1. 系统无需用中断和程序来维持时钟,断电后只要RTC在走即可
( f8 b, n, I' K5 e8 q2. 具体的两种计时的换算、星期数计算,有ANSI-C的标准C库函数实现,具体可以看time.h
' q. z  O2 H3 D  k4 G( Y9 v' L3. 时间与时间的计算,用UNIX时间戳运算,就变成了两个32bit数的加减法8 g& u* x( I# E/ R" g% I, ~
4. 与国际接轨。。。
! k: x9 }0 U$ ~: q$ P5 K. K
+ u' y0 {' i6 o$ D" s! K1 f3 `3 }' v6 @' s- N: A  x! U1 n
幸好是与国际接轨,我们有time.h帮忙,在MDK的ARM编辑器下有,IAR下也有
( c5 K7 P) D; M6 p- L7 ]% k( Y其中已经定义了两种数据类型:unix时间戳和日历型时间
! B3 G# r. b" p time_t:       UNIX时间戳(从1970-1-1起到某时间经过的秒数)
% r$ L/ d' d( Y& C: I0 O& J     typedef unsigned int time_t;
1 ?( ?2 e- v2 J3 z# A, Y" \# f # y- h% A% z. V0 y+ b
 struct tm:    Calendar格式(年月日形式)
5 d/ ?" z! g. N* g  n7 ^
+ }) o  d$ W- e  i. M同时有相关操作函数
$ E" K- N0 _( O0 d; k0 d4 {( Cgmtime,localtime,ctime,mktime等等,方便的实现各种时间类型的转换和计算
+ f, |7 y- n& s- K  `, \
5 ]0 c* k# R1 e; |7 V$ N$ e5 H于是,基于这个time.h,折腾了一天,搞出了这个STM32下的RTC_Time使用的时间库
! N0 S. a2 K/ _* l( Y  t5 p, G9 n0 e: f, s4 P5 R% V6 E4 i

! X' p6 r- J# [) ?8 O% a5 O这是我的RTC_Time.c中的说明:
" w( \% U( M7 x# t; U9 P4 L
1 y2 ?9 q6 I, l* A# j! H 本文件实现基于RTC的日期功能,提供年月日的读写。(基于ANSI-C的time.h)
! D( h) u2 c" M' z8 |& Q0 m 
* t; {$ x7 E7 ^7 [ 作者:jjldc (九九)) q, q% ~/ r6 D( @
 QQ: 770586176 f; h2 C# N0 o) f
 & m4 ^$ g8 X. k9 N, j
 RTC中保存的时间格式,是UNIX时间戳格式的。即一个32bit的time_t变量(实为u32)
( ]& w  B7 s! ]& c6 j4 A& m" b0 @, j' o+ a% W/ O4 e
 ANSI-C的标准库中,提供了两种表示时间的数据  型:
3 [1 ]+ ^; o' k+ k time_t:       UNIX时间戳(从1970-1-1起到某时间经过的秒数)
6 f6 o, T! X. U. W  r8 v6 c$ O     typedef unsigned int time_t;9 I. K* W8 N9 Q$ O9 e4 p
 # q9 C4 @$ v; d$ d
 struct tm:    Calendar格式(年月日形式)
" R5 P5 ]9 [; X: f  j  \: T. d+ ^. F   tm结构如下:5 Z9 G% B% n+ d" q: G  z" u2 y
   struct tm {$ e4 Q8 Q+ R, C  \) H
       int tm_sec;   // 秒 seconds after the minute, 0 to 60
1 y& `' ~" \; E6 A                        (0 - 60 allows for the occasional leap second), B4 D& u; I8 _2 V4 S- u
       int tm_min;   // 分 minutes after the hour, 0 to 592 W4 C, H8 `1 s5 u
        int tm_hour;  // 时 hours since midnight, 0 to 23
3 |! n' }8 Z$ r        int tm_mday;  // 日 day of the month, 1 to 31
& K% m- M4 h' ~9 u( g9 Z! t        int tm_mon;   // 月 months since January, 0 to 11
- U* A/ Y' J; C1 u9 `" X        int tm_year;  // 年 years since 19003 d6 M  ]8 M: T8 }0 v% w7 T
        int tm_wday;  // 星期 days since Sunday, 0 to 6
# R# q  W1 q- E& v% v1 S        int tm_yday;  // 从元旦起的天数 days since January 1, 0 to 365
3 D( F* Q' N2 h8 K/ f8 E+ L         int tm_isdst; // 夏令时??Daylight Savings Time flag
8 D; F% g3 W, E6 D         ...$ C; d) x3 C# x+ V4 q( E
     }
$ A# @+ f6 }, O& r( X     其中wday,yday可以自动产生,软件直接读取
6 S3 L0 U! `4 Z) g     mon的取值为0-11# P# @, G, G& W$ `% V* q& n
    ***注意***:2 `9 G" v, r, f  ^$ p& a
    tm_year:在time.h库中定义为1900年起的年份,即2008年应表示为2008-1900=1083 J. a5 `" [& N  L& F9 V4 k/ K
     这种表示方法对用户来说不是十分友好,与现实有较大差异。
" n; y0 j4 P. O+ s1 E% ^     所以在本文件中,屏蔽了这种差异。
  T6 e2 H8 m7 K2 U: F, T$ R     即外部调用本文件的函数时,tm结构体类型的日期,tm_year即为2008
, ?1 p) S" J7 f& P/ N     注意:若要调用系统库time.c中的函数,需要自行将tm_year-=1900
' a3 a7 ], J% d! N; Y/ a1 l : E+ y5 i8 {7 K/ O' Z
 成员函数说明:
2 i* {5 i0 B9 M* ?" a struct tm Time_ConvUnixToCalendar(time_t t);
9 u, u/ c3 d2 K* Z     输入一个Unix时间戳(time_t),返回Calendar格式日期# D' T  S' K/ I
 time_t Time_ConvCalendarToUnix(struct tm t);9 a4 @- r( `& T+ E# |3 @4 s/ A% O
     输入一个Calendar格式日期,返回Unix时间戳(time_t)
( {5 C7 Q. B8 |5 M) F* o8 H9 m# D time_t Time_GetUnixTime(void);
' t5 E- P: Z1 z/ p     从RTC取当前时间的Unix时间戳值& e) U' p0 U% _6 F
 struct tm Time_GetCalendarTime(void);
4 E& R6 W# g" r1 @/ Z- t% U7 _     从RTC取当前时间的日历时间
. n  f& v4 t+ |7 U& e void Time_SetUnixTime(time_t);
( I2 ]* G$ i/ E0 E$ U' ?     输入UNIX时间戳格式时间,设置为当前RTC时间
- h7 J2 i  f# j# S! H! n- _! L1 \ void Time_SetCalendarTime(struct tm t);
, i. }1 S$ ], _1 V  H& m/ a8 X     输入Calendar格式时间,设置为当前RTC时间
8 v7 ^! V! _8 x1 [5 O& ] $ _2 V9 H( _, P# c5 }
 外部调用实例:
- Z+ Z1 ?- W6 N# V! w 定义一个Calendar格式的日期变量:
* v5 U8 F- {" |" H struct tm now;! m9 h7 C/ M, j8 {/ m/ \6 P0 j
 now.tm_year = 2008;0 f6 y0 R1 v7 d3 J, |! [- ~  K" V
 now.tm_mon = 11;        //12月! I6 m3 o' |+ I3 U$ s7 Q
 now.tm_mday = 20;
2 ]% }4 @) i' ^9 s, c5 T' C5 g: U now.tm_hour = 20;
3 D+ u; E4 d% n% A. c% W, U3 m now.tm_min = 12;
& ~4 |& \6 T% w! @/ {) B now.tm_sec = 30;5 ]8 p0 E& m6 n1 H* O0 d  s
 
% X9 ^/ {+ R8 a, g9 u 获取当前日期时间:
! v0 S, f* l) W tm_now = Time_GetCalendarTime();
" C1 f1 c" X8 n/ b6 J! ?4 P 然后可以直接读tm_now.tm_wday获取星期数: s; t3 L/ L* [  v& Z; E8 t
 
2 W" b" I$ ~% U5 T2 b7 I. e7 _) Z 设置时间:
$ C7 ~- q* [% V! t Step1. tm_now.xxx = xxxxxxxxx;0 B* c# S/ d. W5 V
 Step2. Time_SetCalendarTime(tm_now);
" w+ j$ w7 L) o0 ]1 ?* @& F 
1 e. I6 W; G7 L' A( }3 ` 计算两个时间的差
6 s. Q: S8 V- x7 P# z struct tm t1,t2;5 c& M( H  h) u$ N$ K
 t1_t = Time_ConvCalendarToUnix(t1);/ V8 O7 y4 r6 k
 t2_t = Time_ConvCalendarToUnix(t2);
/ ]0 ]1 k( ^* J1 G: j% M- ^ dt = t1_t - t2_t;
- W2 r+ U: E2 `& } dt就是两个时间差的秒数+ T6 R5 Q6 z! g2 V$ z. M: x
 dt_tm = mktime(dt);    //注意dt的年份匹配,ansi库中函数为相对年份,注意超限
7 F! O+ N9 Q1 ? 另可以参考相关资料,调用ansi-c库的格式化输出等功能,ctime,strftime等
) k7 f/ H+ e6 F3 a ) X" P" Z' {" _8 D
1 m2 M" c* j" s8 b, @' v5 b
这是包含了RTC_Time的工程实例,可以用来参考
/ \5 Y6 z5 W9 j2 T: ^基于MDK环境( @7 \9 k' \2 |2 d/ K7 p5 o" q
 2 e/ j8 H  f+ \- j  X# S2 P/ G
 

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

下载

179.12 KB, 下载次数: 92

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

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版