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

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

[复制链接]
jjldc 发布时间:2009-1-4 16:19
基于STM32处理器, S$ D! P% }) f9 Z7 z
RTC只是个能靠电池维持运行的32位定时器over!- i; a# |% F/ C3 W
并不像实时时钟芯片,读出来就是年月日。。。
7 b- y2 ^1 L, S( b' ]. V8 w) H' \看过些网上的代码,有利用秒中断,在内存中维持一个年月日的日历。3 [0 R: s/ M9 Q7 |  M! {
我觉得,这种方法有很多缺点:$ z3 U1 T' d1 |( }2 b
1.断电时没有中断可用$ S+ r" _1 [1 w+ Y! E$ S; ~) l
2.频繁进中断,消耗资源
- _; B2 `- W+ d, l3.时间运算复杂,代码需要自己写
8 g9 D' ^+ l  {, v! j( T6 t" h$ S4.不与国际接轨。。。。
# |* X( i+ u- q+ T- t8 G$ P& K  K- J
so,还是用标准的UNIX时间戳来进行时间的操作吧!
9 {9 S$ ~) B$ \3 |9 _! `什么是UNIX时间戳?4 d9 ?0 x7 @8 X
UNIX时间戳,是unix下的计时方式。。。很废话
) o, y# _( e( l) @7 l& L. a, }7 m具体点:他是一个32位的整形数(刚好和STM32的RTC寄存器一样大),表示从UNIX元年(格林尼治时间1970-1-1 0:0:0)开始到某时刻所经历的秒数) m! Q4 {. L% q; C$ S' C2 G
听起来很玄幻的,计算下: 32位的数从0-0xFFFFFFFF秒,大概到2038年unix时间戳将会溢出!这就是Y2038bug1 @0 p7 y2 H" J7 a6 Y) N
不过,事实上的标准,我们还是照这个用吧,还有二十年呢。。。. d+ E5 ^7 f" T4 t  F9 M

. X8 W1 e% j# }; uUNIX时间戳:1229544206  现实时间:2008-12-17  20:03:26
% C7 x7 F/ _+ d5 M: W: z; [* _9 V: l$ W5 m1 H5 H7 a. v
我们要做的,就是把当前时间的UNIX时间戳放在RTC计数器中让他每秒++,over
+ I' _( C  C# @" a( r然后,设计一套接口函数,实现UNIX时间戳与年月日的日历时间格式转换 这样就可以了
8 N# C/ d* U5 F6 P, `2 e$ D9 C. i; `* L+ b& R, n# X- V9 ~$ U# H) h
在RTC中实现这个时间算法,有如下好处:2 ]2 l1 ^" z6 B' D# }; F3 ^# W. d
1. 系统无需用中断和程序来维持时钟,断电后只要RTC在走即可
$ X) ^" \8 H7 H0 D% g4 L! ~2. 具体的两种计时的换算、星期数计算,有ANSI-C的标准C库函数实现,具体可以看time.h9 Z; L" K+ G! v; `3 B
3. 时间与时间的计算,用UNIX时间戳运算,就变成了两个32bit数的加减法
. o/ `& w5 n# \) \4. 与国际接轨。。。: v8 U+ T) F: H" E7 r9 S5 b9 u

6 v1 Q7 i, M" Q! r9 Y( [- y9 Q. D- k. j8 `) f& i  \3 z
幸好是与国际接轨,我们有time.h帮忙,在MDK的ARM编辑器下有,IAR下也有/ p9 H" p7 K/ T0 n1 \6 D+ q$ D
其中已经定义了两种数据类型:unix时间戳和日历型时间
0 ?! V* N2 S6 X3 R0 j time_t:       UNIX时间戳(从1970-1-1起到某时间经过的秒数). e: Q7 h3 c  \( A
     typedef unsigned int time_t;
: P' z; N, ~7 b6 A" n 5 p" H/ ?+ R2 r8 t& o) S
 struct tm:    Calendar格式(年月日形式)
; |) q1 P8 l! d7 ^: U. C+ ?- j! d" k: J/ B0 m: G. \
同时有相关操作函数
/ f1 A! J* @+ N. \gmtime,localtime,ctime,mktime等等,方便的实现各种时间类型的转换和计算+ Q2 N2 E% h; J  E7 d
1 E6 m% @- b3 {0 L' j
于是,基于这个time.h,折腾了一天,搞出了这个STM32下的RTC_Time使用的时间库
8 j4 c) g* @) D8 Q! K  Q8 c" `1 V+ D9 P, M1 P+ }( m4 J

+ ~0 u: E) {9 {1 {6 R) e- M2 B这是我的RTC_Time.c中的说明:  w, n+ C0 {3 V' Y. }1 L

" {" J0 ]! F/ B 本文件实现基于RTC的日期功能,提供年月日的读写。(基于ANSI-C的time.h)
: h' u" u/ n. W3 I! S: f0 w& I' i * ]: z, ^( f# _$ Y, w. {+ T$ o
 作者:jjldc (九九)
9 y$ ^6 ^( _. @$ k' R QQ: 770586173 t, L7 c: s; L8 O% i& z
 
7 f8 U8 q" W: f. X0 W" N9 X: o& o4 e RTC中保存的时间格式,是UNIX时间戳格式的。即一个32bit的time_t变量(实为u32)' |/ ^; h: h: d& ?

, f! ]0 b2 P4 o7 t: J- |+ m ANSI-C的标准库中,提供了两种表示时间的数据  型:
. p9 h& J* @; m; P2 Z, H% Q  d) i$ n time_t:       UNIX时间戳(从1970-1-1起到某时间经过的秒数)
8 Y/ p" \  C' T     typedef unsigned int time_t;: y5 y8 d8 f7 s# K) v, [
 
) S" \' v0 \& e! D struct tm:    Calendar格式(年月日形式)
. Q; E# _" R$ B0 o9 i6 U7 O4 _3 {   tm结构如下:* ?, d; S3 T! `
   struct tm {
0 y9 ]  }9 \$ }& O6 o) K6 ~       int tm_sec;   // 秒 seconds after the minute, 0 to 60
) ^) J. ?* N4 w8 p! d* Z/ ]7 n( A9 z- j                        (0 - 60 allows for the occasional leap second)7 D/ l, y) V% \4 K
       int tm_min;   // 分 minutes after the hour, 0 to 59- b. b! ^3 p! X) M. o
        int tm_hour;  // 时 hours since midnight, 0 to 23
% `7 t5 f- \# L. I; p! i. X        int tm_mday;  // 日 day of the month, 1 to 31
5 Y  _) C  i: Z# S  ?        int tm_mon;   // 月 months since January, 0 to 11, ?2 H& t) X+ h3 a0 z- O
        int tm_year;  // 年 years since 1900% e" k7 M9 M% |, I* ?; [  d
        int tm_wday;  // 星期 days since Sunday, 0 to 6$ b) r6 d; L5 [! a
        int tm_yday;  // 从元旦起的天数 days since January 1, 0 to 365  Z4 Q& J  x, c+ Z5 y. n
         int tm_isdst; // 夏令时??Daylight Savings Time flag
+ e& m  f& _3 d) ~% y$ E  n         ...$ ]4 H. ~8 o/ D- k  u/ r
     }4 M2 v0 N: d0 q' W" o
     其中wday,yday可以自动产生,软件直接读取; w% _/ O: S5 H1 `! I6 d
     mon的取值为0-11
, b$ g. r: L/ u% |) x    ***注意***:
9 ~1 C/ ?4 e7 S, ?! ~2 r& x    tm_year:在time.h库中定义为1900年起的年份,即2008年应表示为2008-1900=1084 |8 m7 T# s  u7 w: O( T. q
     这种表示方法对用户来说不是十分友好,与现实有较大差异。- w0 p4 g$ O( S/ p/ q* N" H
     所以在本文件中,屏蔽了这种差异。
: l; S. u0 f5 X; ?     即外部调用本文件的函数时,tm结构体类型的日期,tm_year即为2008
2 F# X8 B! W5 u4 L5 X     注意:若要调用系统库time.c中的函数,需要自行将tm_year-=19000 P- u& t9 L& l
 
, f$ y1 g# O/ [! J* m( V4 H1 z 成员函数说明:
1 I: T9 \( a% d% ?" z' C struct tm Time_ConvUnixToCalendar(time_t t);, d3 V6 Z$ T5 n6 y+ K4 N$ n" W
     输入一个Unix时间戳(time_t),返回Calendar格式日期
3 G% i& ?, V0 ` time_t Time_ConvCalendarToUnix(struct tm t);3 u6 U/ u7 A0 E4 ]7 E6 c9 o3 n
     输入一个Calendar格式日期,返回Unix时间戳(time_t)1 D0 T' K- k+ ?8 ?( B' C% v4 K8 i
 time_t Time_GetUnixTime(void);9 x6 B/ W3 |4 ?- F
     从RTC取当前时间的Unix时间戳值
9 L, m' a/ m! o- `. m struct tm Time_GetCalendarTime(void);7 X, h( J! g+ \& T# y! x0 u
     从RTC取当前时间的日历时间
6 q" \' R9 ]" X5 O& N2 D% v! E" Q void Time_SetUnixTime(time_t);
& \/ x' A* R* A/ _% H     输入UNIX时间戳格式时间,设置为当前RTC时间, {6 ~9 d, Z* W# u5 t, U
 void Time_SetCalendarTime(struct tm t);/ z: C* g$ B& ~, A; G4 Y3 I0 d5 x
     输入Calendar格式时间,设置为当前RTC时间
# \8 S; c5 V* b& Y0 K3 t 1 Q6 V) U' h7 u7 y' R
 外部调用实例:
9 S$ g9 ^! X; k* x( l9 G1 h/ l) ] 定义一个Calendar格式的日期变量:
4 ?/ q% H3 {( V0 r$ }- F5 H; u struct tm now;- i  v1 T) I7 n( u6 k
 now.tm_year = 2008;
( y$ X0 D% {$ f3 p now.tm_mon = 11;        //12月
4 D8 g! Z8 V, \' `) i now.tm_mday = 20;- m' C% |8 H7 Z, i, e- ?2 I
 now.tm_hour = 20;9 F2 c2 d) m  G. s
 now.tm_min = 12;6 l& b1 A$ o2 g& y3 _7 E
 now.tm_sec = 30;+ Q: e0 W: W4 ]1 \! F/ P1 A
 
1 L! M% Y7 K, g( h% j+ z 获取当前日期时间:
* R' }& s) x" Y  O% p2 X2 { tm_now = Time_GetCalendarTime();
- {& b" N, ^( @1 M0 N 然后可以直接读tm_now.tm_wday获取星期数
% h; ~7 L. U# I 
3 K# t1 A1 \, _( P- L 设置时间:$ ~% `0 Y: w) I( n
 Step1. tm_now.xxx = xxxxxxxxx;
7 p5 H6 v& D, P3 W Step2. Time_SetCalendarTime(tm_now);% P  e# {: u* D8 [$ G. L
 
: x! F/ A# m. N$ e9 U$ b' @( D 计算两个时间的差
3 P+ k+ }. Z# l struct tm t1,t2;* L( K. Y0 g5 J; N( T* X
 t1_t = Time_ConvCalendarToUnix(t1);
' f- q. B; \& a6 ]: D+ ~ t2_t = Time_ConvCalendarToUnix(t2);/ N& ^* H5 M1 }3 t
 dt = t1_t - t2_t;
/ D0 H: r0 b4 G( _4 |9 M4 M dt就是两个时间差的秒数2 C/ F: S. ]/ C" G  w8 T
 dt_tm = mktime(dt);    //注意dt的年份匹配,ansi库中函数为相对年份,注意超限
4 N" l+ N' N4 b/ `, O% s 另可以参考相关资料,调用ansi-c库的格式化输出等功能,ctime,strftime等( ~: @3 d( ?- O, x! V% p) ~# u
 # S: f+ r+ i: f( _3 d! I" U2 o

/ q* p( ~  U# R0 T% W这是包含了RTC_Time的工程实例,可以用来参考
, f  S$ }0 H3 _% e) F基于MDK环境
: O+ c8 s$ a* o$ u1 U; [ 
, C; |+ d* C' {8 A+ C1 D% Q 

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