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

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

[复制链接]
jjldc 发布时间:2009-1-4 16:19
基于STM32处理器
, x4 D/ r  @0 \0 t7 D; TRTC只是个能靠电池维持运行的32位定时器over!
8 x, A% B: G( o/ |% H并不像实时时钟芯片,读出来就是年月日。。。9 P2 A$ [/ @) ]$ M7 T, k: b4 g
看过些网上的代码,有利用秒中断,在内存中维持一个年月日的日历。
7 W4 p- A' G% [% z0 H: r/ D" I我觉得,这种方法有很多缺点:
& M; j- W3 D, Z( o3 ]1.断电时没有中断可用
' h: N8 _7 I1 f' s; ^2.频繁进中断,消耗资源. o0 C7 h* F0 K, h
3.时间运算复杂,代码需要自己写
8 e' n/ H, }% ]7 J0 j" B; }, f4.不与国际接轨。。。。4 y- v7 B# J' I* {

2 q4 }9 ]6 w/ ]/ Y3 lso,还是用标准的UNIX时间戳来进行时间的操作吧!
* ~4 M* a3 z$ d; i, R3 b! T% M什么是UNIX时间戳?
1 k" c5 \5 J8 M  h' e8 F" h# XUNIX时间戳,是unix下的计时方式。。。很废话
4 t+ J; M9 Z! k/ C. ~具体点:他是一个32位的整形数(刚好和STM32的RTC寄存器一样大),表示从UNIX元年(格林尼治时间1970-1-1 0:0:0)开始到某时刻所经历的秒数2 f& M8 Z2 ?9 L
听起来很玄幻的,计算下: 32位的数从0-0xFFFFFFFF秒,大概到2038年unix时间戳将会溢出!这就是Y2038bug
; _5 Y  ^4 k7 v  ~7 X6 H$ y不过,事实上的标准,我们还是照这个用吧,还有二十年呢。。。
$ [3 I! ^$ o, E" H8 ^) ]* [1 V/ R/ N  @. Y3 o
UNIX时间戳:1229544206  现实时间:2008-12-17  20:03:26
0 m* \8 M* N% X3 q# v2 |4 V7 h3 b' i  O
我们要做的,就是把当前时间的UNIX时间戳放在RTC计数器中让他每秒++,over3 M& O8 a4 ?# a
然后,设计一套接口函数,实现UNIX时间戳与年月日的日历时间格式转换 这样就可以了3 G- x/ b! r# H$ O

2 W6 t9 m4 t: F) f8 _/ O在RTC中实现这个时间算法,有如下好处:
# |) e7 y" B/ k4 y: h1. 系统无需用中断和程序来维持时钟,断电后只要RTC在走即可
% G( Q1 Q! s+ o: `0 ?2. 具体的两种计时的换算、星期数计算,有ANSI-C的标准C库函数实现,具体可以看time.h: S- [. Q0 u/ u. ]) `( E  W* o
3. 时间与时间的计算,用UNIX时间戳运算,就变成了两个32bit数的加减法
5 I0 Y  p6 |2 u, m4 u5 W4. 与国际接轨。。。
# o. q( `6 I5 T* h1 F2 [* y* J# E2 l- T

/ g, p! a4 f0 P2 U0 J) @" _3 _幸好是与国际接轨,我们有time.h帮忙,在MDK的ARM编辑器下有,IAR下也有; h5 V" `# H9 ]' k
其中已经定义了两种数据类型:unix时间戳和日历型时间
4 c4 x6 p8 f/ `$ D2 D- { time_t:       UNIX时间戳(从1970-1-1起到某时间经过的秒数)
+ U6 u! \% A: h$ X" m# `( c     typedef unsigned int time_t;+ J2 T/ ^0 Y2 b  k) a5 V
 
( J% l3 @; }1 M) r1 g, l; `) H struct tm:    Calendar格式(年月日形式). R7 ~+ ]8 @1 y  Q- w' ^

7 U1 w: X! r- j* H/ H5 R! O+ \同时有相关操作函数9 y% C( u. \/ ^% h3 P4 E
gmtime,localtime,ctime,mktime等等,方便的实现各种时间类型的转换和计算
$ ~% k6 F) h/ G
+ C. ~) V3 {6 \% ~  M) G+ q+ q0 H) \9 f8 ^于是,基于这个time.h,折腾了一天,搞出了这个STM32下的RTC_Time使用的时间库& t( s" D- L. j5 d, ?) Y# G; q

( ]5 w% P. Y" \, h& A5 q& q! N% a  F/ ~  q
这是我的RTC_Time.c中的说明:
/ p1 J0 P. l( O
) ~9 k0 b, E4 \. ^" `& R 本文件实现基于RTC的日期功能,提供年月日的读写。(基于ANSI-C的time.h)
5 {2 C& v* b; r 
) b  U+ ]2 r9 y' B3 R$ z 作者:jjldc (九九)) `5 J4 R. G  E* G' P6 i' K  K
 QQ: 77058617
* t* R5 O- r0 y2 G 
) D# X4 A  u* j RTC中保存的时间格式,是UNIX时间戳格式的。即一个32bit的time_t变量(实为u32)0 d9 v8 B* y* `  m& I+ w
+ M5 n7 W6 h& U! f! R5 M( g
 ANSI-C的标准库中,提供了两种表示时间的数据  型:8 \4 F$ ?$ B% G
 time_t:       UNIX时间戳(从1970-1-1起到某时间经过的秒数)
. r8 _- `7 v4 [. y/ N     typedef unsigned int time_t;
; a% j/ j* X, b" K4 W& l, E5 `; Z+ S ) \; ]# |) j$ C) t; Z  Y
 struct tm:    Calendar格式(年月日形式)
" S$ O2 m& O- x# ?9 A5 j+ J   tm结构如下:
2 C5 X1 K% _. G   struct tm {/ |1 W) u' m: Z9 h6 j" c. j
       int tm_sec;   // 秒 seconds after the minute, 0 to 60' n; Z9 a( g$ i  y6 ^5 [) a9 J
                        (0 - 60 allows for the occasional leap second)
) O2 U3 e, i) z- \5 M. c       int tm_min;   // 分 minutes after the hour, 0 to 59! h4 w: I5 }" D* w' b. }) P
        int tm_hour;  // 时 hours since midnight, 0 to 237 B* N* x. ]7 V* i
        int tm_mday;  // 日 day of the month, 1 to 318 E* w; g5 A$ R$ F) G7 \
        int tm_mon;   // 月 months since January, 0 to 11* E: N" {& G6 u* {0 T$ `
        int tm_year;  // 年 years since 19007 q( F9 O7 F4 C4 ]0 u) P' I7 k
        int tm_wday;  // 星期 days since Sunday, 0 to 6$ b" w1 e- _/ f# {- U+ \
        int tm_yday;  // 从元旦起的天数 days since January 1, 0 to 365
1 A. t' X2 I# V, u5 a         int tm_isdst; // 夏令时??Daylight Savings Time flag
  ^$ m# X4 N+ O9 j" s         ...
" a3 r5 C5 O6 B. n' P, y/ w     }
/ c" }- M$ ?( w, B# x* u! e8 O     其中wday,yday可以自动产生,软件直接读取
, D0 n* x( q5 j7 G  C     mon的取值为0-11
% X9 m* Y1 A, o: |& t+ t9 ~    ***注意***:
$ V+ R% R5 Y/ c    tm_year:在time.h库中定义为1900年起的年份,即2008年应表示为2008-1900=108
& v6 V& D0 c0 Y  q( E6 Y     这种表示方法对用户来说不是十分友好,与现实有较大差异。, S$ Y8 \; E& W
     所以在本文件中,屏蔽了这种差异。0 ?! g; y* O3 ^/ k$ I, \& p2 Y* o3 Z6 ~
     即外部调用本文件的函数时,tm结构体类型的日期,tm_year即为2008* d6 G( i) L+ o6 i9 m3 P% l$ l
     注意:若要调用系统库time.c中的函数,需要自行将tm_year-=1900' a+ R. o0 H# ^
 
; I9 g' F( d% |0 g  R1 M 成员函数说明:7 z0 L2 z2 y* |  o2 ^
 struct tm Time_ConvUnixToCalendar(time_t t);
! F# h8 r; H8 f6 {2 u, _     输入一个Unix时间戳(time_t),返回Calendar格式日期+ O8 K( N2 B2 w
 time_t Time_ConvCalendarToUnix(struct tm t);
  o+ a8 f  x2 C6 @/ i; {( T( v     输入一个Calendar格式日期,返回Unix时间戳(time_t)
0 [7 J4 M5 f. V& W  t4 r1 Y time_t Time_GetUnixTime(void);  R) o, c+ j! A6 K+ ~- a
     从RTC取当前时间的Unix时间戳值& Y* t  E- i* E& q8 V' \- W
 struct tm Time_GetCalendarTime(void);
3 x4 Y0 ~% n/ l  o     从RTC取当前时间的日历时间# ]$ U5 Y$ J' `7 Y
 void Time_SetUnixTime(time_t);
& d8 u( p+ z& M5 B5 c1 R0 e1 U' G2 m; J     输入UNIX时间戳格式时间,设置为当前RTC时间
2 U4 K* o0 H+ i1 J4 j  b void Time_SetCalendarTime(struct tm t);
- s, o% e2 d; f3 N; L, N* T$ z     输入Calendar格式时间,设置为当前RTC时间4 h5 V  A5 n" U2 j: T, k
 
2 ?- u" Y. o7 a 外部调用实例:
* \1 f: f3 o" {  M 定义一个Calendar格式的日期变量:
- U- e1 W( U, ]+ W- l/ S+ J struct tm now;# r+ t1 {$ o' ^# l% H% Z( Z
 now.tm_year = 2008;  b9 d7 U- ~( B$ l& _" ]
 now.tm_mon = 11;        //12月0 y. E# `# y8 |. D6 j
 now.tm_mday = 20;
' I6 M2 Y2 I! v& d" a% ]0 N now.tm_hour = 20;% s, e9 |5 {+ |6 a- E% b, D
 now.tm_min = 12;
$ N- ]4 m7 b: V6 ?) l# l now.tm_sec = 30;. P6 f) D: b0 `3 O+ h1 s8 K6 K
 
9 d3 D$ j! O5 `% N2 W2 c- w1 d1 N7 _ 获取当前日期时间:: I/ |% y* Z$ ^, ^( y! a( F
 tm_now = Time_GetCalendarTime();
) [  m! a3 z$ s0 t6 l  F0 k( o 然后可以直接读tm_now.tm_wday获取星期数2 h! r9 J+ H1 r
 2 C! J% K- J' V; Z' p8 u' a
 设置时间:
$ t% V; Z3 d8 |: t3 Z( p Step1. tm_now.xxx = xxxxxxxxx;
& o6 x2 h9 Y8 r  t8 r7 `0 O& ~. T3 p Step2. Time_SetCalendarTime(tm_now);
4 n, s# n9 [2 |6 o 
  Y$ T/ a" w1 y& m 计算两个时间的差
/ D0 @& S6 z6 m% `  w& W struct tm t1,t2;& V" B7 e0 d9 n
 t1_t = Time_ConvCalendarToUnix(t1);' \  F' c; d: S  n( d7 p2 g" k7 G2 b8 c
 t2_t = Time_ConvCalendarToUnix(t2);
$ Z4 M* A* ~+ |8 b3 T dt = t1_t - t2_t;
3 z, ]9 M6 U) A1 h& `7 B dt就是两个时间差的秒数
! i; B# y+ G/ t7 h% _, U dt_tm = mktime(dt);    //注意dt的年份匹配,ansi库中函数为相对年份,注意超限/ x7 O& b* F  w8 Q
 另可以参考相关资料,调用ansi-c库的格式化输出等功能,ctime,strftime等
- R" V9 b9 o! ^& C" ]( B" c5 m 6 r1 X  D- y: t6 [, g4 Y% T/ q' t

7 i: v9 e; k; F- ^0 {6 Q6 J这是包含了RTC_Time的工程实例,可以用来参考
  V) F+ Y& W* d" ~. Y, o基于MDK环境9 U* G' ]* Z# A- j/ x6 y) ]
 
# B5 [- Q- v1 |( `# C 

发布基于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 手机版