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

【经验分享】STM32_RTC

[复制链接]
STMCU小助手 发布时间:2022-2-9 21:34
关于日期,关于时间、STM32也提供了强大的RTC模块、、至于RTC模块到底是哪三个英文单词的缩写,我就不说了、好了,言归正传、这个语气、请大家想想周星驰唐伯虎点秋香当中华安与对穿王的对白:我俩、、、言归正传:
       在这里、先别急,咱们来看看一般的RTC模块(芯片):
   1、 描述:RTC芯片是一种能提供日历(年月日)/时钟(时分秒)、数据存储等功能的专用集成电路;
   2、应用环境:通常使用后备电池,以保证其在系统掉电的情况下运行;
                      其时钟源由外部32.768KHz晶振提供,可以实现闹钟功能。
   3、作用:应用于某些系统的时钟信号源和参数设置的存储电路。
                RTC具有计时准确、耗电低和体积小等特点,特别是在各种嵌入式系统中用于记录事件发生的时间和相关信息, 如通信工程、电力自动化、工业控制等领域。
   再来看看STM32中RTC有哪些区别呢(概述,具体分析请别急哈、):
   1、不具有提供日历/时钟功能;
   2、能够提供一个精确的秒周期信号:配置RTCCLK以及RTC_DIV,使得预分频器产生频率为1秒的秒脉冲(TR_CLK),作为RTC的时钟基准。
   3、具有闹钟功能。
   4:特点:(1)保护寄存器---防止误操作(请注意这一点哈,非常关键)
                (2)3个事件/中断源:秒、溢出、闹钟(连外部中断线17上,用于将MCU从停止模式唤醒)
                (3)RTC内核和时钟的设置位于备份区域(也请注意这一点哈,因为要使RTC能记忆,就靠它了):
                        有独立的VBAT供电;
                        只能由备份区域复位才能将其复位;
                        从待机模式唤醒后,RTC的设置仍被保留。
     啊哈、、以上摘自STM3210X+其余模块培训资料、、在这里摆出来就是为了给大家有一个比较全面的认识先、、莫告我盗版哈、、好了、、接下来,来看看时钟吧、、
   翻开“葵花宝典”第STM32篇之RTC参考手册可以看出:可以选择以下三种RTC的时钟源:(直接看图哈)这下就不说是美丽的涂鸦了、、、

. T4 z2 B8 a+ R$ l, Q' Z
051121509634374.png
  
在这里,我们选择独立的32.768KHz晶振(LSE)来作为外部时钟源、提前说下:只要在RTC的预分频转载寄存器中写入0x7fff(也就是32767),就可以产生以秒为单位的信号了、、
接下来,我们来看看参考手册里的一段话:(RTC核心)由一组可编程计数器组成,分成两个主要模块。
第一个模块是RTC的预分频模块,它可编程产生最长为1秒的RTC时间基准TR_CLK。RTC的预分频模块包含了一个20位的可编程分频器(RTC预分频器)。如果在RTC_CR寄存器中设置了相应的允许位,则在每个TR_CLK周期中RTC产生一个中断(秒中断)。
第二个模块是一个32位的可编程计数器,可被初始化为当前的系统时间。系统时间按TR_CLK周期累加并与存储在RTC_ALR寄存器中的可编程时间相比较,如果RTC_CR控制寄存器中设置了相应允许位,比较匹配时将产生一个闹钟中断。
    接下来请容许我介绍下几位“大神”:
  A( C$ ]2 Q# G3 J7 Q1 Z; k

2 m- P7 z. G' w9 O8 J# v. m$ [
051218002769750.png
   
     从红色区域我们可以看出我们这里要实现以秒为单位的计时,就要设置RTC_CRH的最低位为1;
接下来请看(请注意红色区域,再对照前面红色字体的标注):
# `+ d2 C% p6 }4 n: b
8 ]' z  ~5 T; }! p9 x1 r$ Z
051224236986521.png

8 b2 X5 F* w+ `% `" V% W4 K* o
还有几个寄存器在此就不做具体介绍了,大家可以参考中文手册,在此仅列出:
     RTC预分频装载寄存器(RTC_PRLH/RTC_PRLL)
     RTC计数器寄存器 (RTC_CNTH / RTC_CNTL)
     注:因为RTC是由独立的时钟源提供,不挂载在ABP桥上,但是,奇怪的是;软件又是通过ABP1桥来访问RTC的寄存器,由于可读寄存器只在RTC ABP1桥时钟进行同步的RTC时钟上升沿被更新,可读标志位也是这样,这就涉及到一个概念:同步,假如ABP1被刚刚开启,在第一次的寄存器更新之前,从ABP1桥上读取的RTC的寄存器就有可能被破坏了,为了避免此种情况的发生,在读取寄存器的时候一定要等待他们同步、、至于如何操作、、请看上图寄存器的红色标记
    好了、、人需要记忆、、否则失忆了,对彼此都不是一件好事、、当然、RTC也一样、、你不希望RTC在系统复位或者一些意外后而是RTC失效、、所以、、RTC也要有记忆的功能、至于如何记忆呢?STM32也为我们提供了BKP模块:翻开“葵花宝典”第STM32篇之BKP备份寄存器有这么一段描述:
备份寄存器是42个16位的寄存器,可用来存储84个字节的用户应用程序数据。他们处在备份域里,当VDD电源被切断,他们仍然由VBAT维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位。
  所以,我们在这就要开启BKP的时钟、、
  然而、、事情并不是那么的简单、、在这里、、仅仅打开BKP的时钟还不够、、因为某种特殊原因、、请看
" N' K, B' C7 X! D. ]) e
051247554638557.png

, z: F% ~/ p& d, M
因为系统复位后,RTC和后备寄存器处于被保护状态以防意外写入、、所以在此也要打开PWR的时钟,在这里,我们需要取消保护,向后备寄存器写入一个字节0x5050或者0x0505都行,以标注时钟已经配置过了、、到时检查这个字节来决定是否要重新配置、、
而BKP PWR时钟都是挂载在ABP1桥上的:
# S: B* ~9 `4 j& q- R5 w+ p
051252407605184.png
: k3 a" o) ^$ t2 P9 X' X
那我们要怎么来操作呢:请看代码注释:
  1. 1 u8 RTC_Init(void)
    7 z" \4 q5 p4 Q, K- x
  2. 2 {+ d" a, y) d0 t5 m- C
  3. 3    //检查是不是第一次配置时钟5 E+ B6 \" x) a" h  m5 U* v
  4. 4     u8 temp=0;
    * {% X/ w- o  Z9 S3 {3 L+ T" ^
  5. 5   
    $ z: M1 Q  ?' b5 [8 w5 ~7 P  o
  6. 6      if(BKP_ReadBackupRegister(BKP_DR1)!= 0x5050)//从指定的后备寄存器中读出数据,读出了与写入的指定数据不相同,这时候需要初始化) v: p) |8 x5 Z5 J0 D# n5 G2 r. G
  7. 7      {
    4 {& V2 x! c+ m; d; v
  8. 8       //1/通过使能PER和BKP外设时钟来打开电源盒后备接口的时钟使其能对后备寄存器和RTC的访问# g9 E% f1 ]0 A9 q9 m! P
  9. 11    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能时钟
    ! \4 M# s# F2 r) g0 h
  10. 12    PWR_BackupAccessCmd(ENABLE);    //取消备份域写保护13          //2/复位备份域,开启外部低速振荡器- Z7 |! u$ H7 @3 E' C2 x
  11. 14          /* Reset the BKP registers */ BKP_DeInit();1 j* _5 g/ o+ e' f
  12. 15          /* Enable the HSE */ RCC_LSEConfig(RCC_LSE_ON);- `8 ?6 Y3 \0 _3 k
  13. 16          ( |' u6 h( P' Q0 I
  14. 17   while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)//等待低速时钟准备就绪,在选择时钟前一定要等待时钟就绪、、否则、后果严重
    $ f5 i/ Q1 J6 i4 ^
  15. 18          {* ?; O4 R  G% z! E; e
  16. 19         temp++;0 d& V% S8 ~* b5 B% I
  17. 20              delay_ms(10);
    - a3 J- w) _0 Y) S0 k- r
  18. 21      }4 }: |/ Q' T2 q7 Z
  19. 22          if(temp >= 250)8 _- s8 T0 ^7 }
  20. 23          {
    * L: C0 n' N- F$ {( U
  21. 24         return 1;( B* ]; R6 g5 [+ u. z6 o
  22. 25      }         
    0 A( O1 B; b1 e5 w7 ]! ?1 U' E
  23. 26          //3/选择时钟和使能时钟/ V- t, e  d/ U& O1 ~
  24. 27          /* Select the LSE as RTC clock source */RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);: o9 ]4 ^! O: v& B/ K
  25. 28          /* Enable the RTC clock */RCC_RTCCLKCmd(ENABLE);
    3 W* E8 A; B5 X$ V
  26. 29          RTC_WaitForLastTask();    //等待最近一次对RTC寄存器的写操作完成。注:一定要等写操作完成5 D2 @: G+ @+ W7 \1 R
  27. 30          RTC_WaitForSynchro();        //等待RTC寄存器同步
    ' ^- h8 \- z4 G4 J
  28. 31          , p0 S7 Q: Z. c! S1 \- ]; r8 z, B
  29. 32          RTC_ITConfig(RTC_IT_SEC, ENABLE);        //使能秒中断* e& Z% Z. T1 w9 V9 j
  30. 33         
    # x5 t5 y3 Y8 _- ~* x8 e
  31. 34          RTC_WaitForLastTask();    //等待最近一次对RTC的写操作完成
    7 ]9 F1 R" U# k  i' _$ ]
  32. 35          RTC_EnterConfigMode();/// 允许配置   
    ' f; v1 o' Q3 K8 t8 r0 p( V
  33. 36          7 a; b6 X! b' |6 g
  34. 37          RTC_SetPrescaler(32767); //设置RTC的预分频值" T/ G* n9 O; Z
  35. 38         
    & D: [% P0 N" Q. a4 m" z9 w
  36. 39          RTC_WaitForLastTask();    //等待最近一次对RTC写操作的完成4 \; |' [2 b$ o* O& Q- P; g$ @
  37. 40         
    + V; b5 q  c' ^+ c3 [
  38. 41          RTC_Set(2014,5,4,12,0,5);  //设置时间8 w/ O5 O% C4 l* A  l6 ]5 U/ b% v
  39. 42          7 x; |- @  \" Z
  40. 43        RTC_ExitConfigMode(); //退出配置8 |! J0 F3 ~5 @5 a$ o
  41. 44         
    , D$ y: l" g. S* {
  42. 45      BKP_WriteBackupRegister(BKP_DR1, 0X5050);    // 向指定的后备域写入一字节        
    ! ~1 l" K, R1 \8 B# l( B2 r- {
  43. 46   A1 W/ r: c- {( w1 `7 ?9 x
  44. 47     }
    ( P. B; j. j, o7 i9 N7 \/ r* Q- G
  45. 48         else //否则,系统继续计时
    2 [# b4 W) C  }$ X' X7 N( h
  46. 49         {) P! W( x3 I0 A
  47. 50          RTC_WaitForSynchro();   
    % D+ }9 Y9 V( a5 L' m
  48. 51           RTC_ITConfig(RTC_IT_SEC, ENABLE);    //开启秒中断
    # t  [: ?" k  k; E+ B
  49. 52           RTC_WaitForLastTask();    ) q5 E. \* @9 `6 z9 [- H8 j% m( g
  50. 53     }
    0 ]& m% E! S$ Q6 p
  51. 54         RTC_NVIC_Config();
    ) t5 x0 Y( N8 f1 S. U" I7 E- U
  52. 55         RTC_Get();//更新时间$ ^4 F3 G2 F5 n) K& t& l& t
  53. 56         return 0;# J* A. ?! K! }" |9 ~; |4 M
  54. 57 }
复制代码

' a: Z$ a8 m; z9 D1 v
% ^' {7 X7 k" j# `  T
   可以看出、、如果我们要配置下一次,一定要等待上次对RTC的操作是否完成,如果没有,就必须等待上次结束才能开始下一次的操作、、同时,如果要对相关的寄存器进行写操作。、一定要进入配置,配置完之后记得退出配置//..
     接下来,给中秒中断的中断服务函数,相信大家也比较清楚了:
  1. 3 void RTC_IRQHandler(void)
    9 J1 y% C1 \- O7 F% @
  2. 4 {         1 `* i; F4 Q3 M# f. a6 q( L7 X5 s. P
  3. 5     if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
    - a* [: u  ^+ V) ]' n4 b# d
  4. 6     {                            0 M9 p3 R! D5 x% {! r0 J
  5. 7         RTC_Get();
    & h0 y0 N' l! E2 s" W  x
  6. 8      }6 a+ i# V1 t. p0 e4 m4 T8 p5 V4 p5 I9 Z
  7. 9     if(RTC_GetITStatus(RTC_IT_ALR)!= RESET)
    7 x) a" u& K5 U! ~! j* Q
  8. 10     {
      x6 v0 ^; o& K
  9. 11         RTC_ClearITPendingBit(RTC_IT_ALR);      
    . c; V6 D# K9 r7 [0 z" u
  10. 12       }                                                   
    # P) T0 I* [7 o2 [: `6 {7 H4 }0 g
  11. 13     RTC_ClearITPendingBit(RTC_IT_SEC|RTC_IT_OW);        - ~: {, x9 F) O- D
  12. 14     RTC_WaitForLastTask();                                                   
    . P) c( q7 H5 b0 [4 v
  13. 15 }
复制代码
. u5 d  I2 u  Y+ P1 ~, F0 @8 r) V
注:对于相关的库函数,由于篇幅的原因,在此就不仔细列出来了、请大家谅解、、大家可以参照固件库、、
在这里给出战舰原子的时间算法程序:就不细讲了、、大家好好研究、、说实话、、我也有些不太懂、所以请大家多多交流:
  1. //判断是否是闰年函数//月份   1  2  3  4  5  6  7  8  9  10 11 12
    * E/ B+ R( F5 u
  2. //闰年   31 29 31 30 31 30 31 31 30 31 30 31
    ) m! E! h4 E% u0 V' x
  3. //平年   31 28 31 30 31 30 31 31 30 31 30 318 i# ]" G4 |+ Y
  4. u8 Is_Leap_Year(u16 year)9 C. b+ [" A" @% n
  5. {              5 m% x- V2 X" c3 f8 n4 [
  6.     if(year%4==0) //
    ' y  k' D1 s; ~, ?9 ^3 o
  7.     {
    ( H3 [8 z, Y9 O3 w6 M
  8.         if(year%100==0) 3 U+ s- _8 t! n8 S6 n2 {7 W9 t
  9.         { ( }9 E0 k- S& T) F, n: Y9 b
  10.             if(year%400==0)return 1;
    2 D% ], T* K1 Q' B1 [: G' o$ f
  11.             else return 0;   ! Z8 l6 T6 @; n& o" u& }
  12.         }else return 1;   
    : P& U; X& k0 U$ e! v
  13.     }else return 0;    2 }, Q; R2 V: C9 a$ y* v  k: J/ r
  14. }   
    4 o: m' R: P7 Q+ y! H$ o
  15. //设置时钟//时钟=》秒//月份数据表
    : Q* Y' z& f% x& H5 N0 c
  16. u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据(我不清楚是怎么来的)  //这里 const 表示这个数组里的值不允许改变   * a, |" C0 a& S/ I2 B" ~/ v
  17. //平年的月份日期表! K& n( t* z8 c' p0 n
  18. const u8 mon_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};
    0 A& B# u4 I& Q+ }" M

  19. 8 d! c- P* T( y# T4 n8 n9 z
  20. u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)9 \2 E" L) N  M
  21. {2 f! z3 X% e) D6 N" k
  22.    u16 t;7 ^. S( F' t" V- Q
  23.     u32 seccount=0;& [9 T8 I0 ~8 c7 ^3 V1 u% o
  24.     if(syear<1970||syear>2099)return 1;      
    ( f2 u# R' {- P; z/ p
  25.     for(t=1970;t<syear;t++)    //把所有年份的秒钟相加
    : M3 _9 e) ]! r  s3 |6 r6 R1 J+ D
  26.     {
    / D+ W* K# {7 H5 F1 X0 U3 U1 a% E
  27.         if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒数! V) R2 P0 c: Y1 b9 B* m% w; C( ]
  28.         else seccount+=31536000;              //否则为平年3 M' N+ B5 H3 c7 s' A
  29.     }3 c( F9 `) b$ _3 B4 T8 n4 ?
  30.     smon-=1;9 x; R0 I$ G2 s  H/ h) _
  31.     for(t=0;t<smon;t++)       //把前面的月份的秒数相加
    - o& O0 W" u' f1 f! q
  32.     {4 }! j1 O. o" O( \
  33.         seccount+=(u32)mon_table[t]*86400;//月份秒数相加
    ' Q: U2 l9 Y) {5 p! Q
  34.         if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一条的秒数% q: w5 Q/ \' e
  35.     }
    + Y  o, P$ T/ a$ ~! `
  36.     seccount+=(u32)(sday-1)*86400;//把前面日期的秒数相加4 K9 [6 S3 B8 o/ a. _
  37.     seccount+=(u32)hour*3600;//小时
    4 f4 Z& }, I7 j5 o
  38.     seccount+=(u32)min*60;     //分钟4 [' p) x- q. J: j
  39.     seccount+=sec;//总秒数& e1 d7 F5 Q% C& V8 v* Z/ r
  40.    
    / G1 o( I' r. O7 D2 |2 S( H  D
  41.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);     , V/ G/ O. u: _% L
  42.     PWR_BackupAccessCmd(ENABLE);   
    # a6 i7 e  |- {5 f
  43.     ; s6 t2 C" D, p5 f
  44.     RTC_SetCounter(seccount);   
    ( C! p. y$ l5 V8 X" h% C# ~/ c1 i" {8 ^
  45.    
    : j, ~/ g; |: i& M
  46.     RTC_WaitForLastTask();   //注意、、此时也要等待、、- q! U2 G9 D9 V% @- L" z" C
  47.     return 0;        : z5 }4 C) b4 q7 a  {, Z
  48.    
    5 N# ?: z' W2 L, r  M; e8 a7 _, q
  49. }
    6 g) ~$ e& @' b. J. P* z5 w5 T, V7 W
  50. //返回当前的时间
    3 E9 g! j# D4 ?' r3 i' B
  51. u8 RTC_Get(void)
    & e% U, p; D. R) q
  52. {
    # C0 R* z* F* S; j, z
  53.     static u16 daycnt=0;  \) c& x! g" w0 T1 ]4 O6 P
  54.     u32 timecount=0; " S, x9 M) p9 J) _& U/ }! i( ~
  55.     u32 temp=0;
    1 _( j7 }' {, ~/ ~0 j
  56.     u16 temp1=0;      $ J( Q7 u4 q! w. E6 m! n
  57.     timecount=RTC_GetCounter();     
    - {1 A0 u+ p& d& e/ [  N7 H$ @
  58.      temp=timecount/86400;
    - Z9 X, ?* a5 K: h6 ]! Y
  59.     if(daycnt!=temp)% _1 `; P( i; S4 C! A, z/ g7 a
  60.     {      3 A9 w4 R  v- W9 j9 E1 |
  61.         daycnt=temp;' q9 B) |- H3 ^1 c, Y3 H
  62.         temp1=1970;   
    ) y$ b' a6 a9 k; P
  63.         while(temp>=365)
    . l* T1 S, A: B# m5 t* P2 i7 c
  64.         {                 
    . t5 a; a4 R/ U9 F" n
  65.             if(Is_Leap_Year(temp1))
    5 M! F4 |/ ~) l! E' N1 a" k
  66.             {* }. k& _" }2 p0 s- w% I# n
  67.                 if(temp>=366)temp-=366;. b9 w% X' l  }6 v
  68.                 else {temp1++;break;}  
    ( c& e8 M! K+ J5 T9 C. N
  69.             }# R/ Y6 h1 P8 G, V( }9 ^' a
  70.             else temp-=365;   
    ; C5 O6 ]  i1 i
  71.             temp1++;  
    9 r  Z% |' I( {
  72.         }   - |* B9 S/ J2 H% ^# a% s
  73.         calendar.w_year=temp1;; ^8 P  G- I7 j, [# [
  74.         temp1=0;' N) v6 p) U  ~
  75.         while(temp>=28)
    & b8 a+ N- u+ W- O8 t( `$ J
  76.         {6 C  u2 A0 Q! ?5 ^5 N6 p( k2 O, X0 Z
  77.             if(Is_Leap_Year(calendar.w_year)&&temp1==1)% Q" t$ z, b, h, p& g/ g9 B
  78.             {6 \2 c; {# M) V& X9 a" h
  79.                 if(temp>=29)temp-=29;8 O6 J, Q8 N# V  d9 {3 v, ^
  80.                 else break; + r0 L2 x3 p& G$ \, [( o7 F0 F# {
  81.             }5 }. g4 \3 j; g5 z. ~
  82.             else % E+ U+ k. x: H, z0 @6 x/ P, L
  83.             {
    $ n  B1 H+ h, N6 B3 q3 x* V1 y
  84.                 if(temp>=mon_table[temp1])temp-=mon_table[temp1];//ƽÄê
    1 S* N1 e) a: J# V7 C
  85.                 else break;
    . X+ w$ D' V% d6 W
  86.             }2 U5 z: ?4 f  ^- N. D
  87.             temp1++;  
    " l- k" u: p! G+ s
  88.         }4 ~* @# y, ]7 Q; f, P: @9 H6 c
  89.         calendar.w_month=temp1+1;   
    , k2 ^  T7 T4 w+ Z
  90.         calendar.w_date=temp+1;     
    ) t" D, S2 m# e6 T) S
  91.     }' l* M) g7 R' U. X& a
  92.     temp=timecount%86400;            
    5 _3 @* y- o& r3 [+ F+ E1 J# d
  93.     calendar.hour=temp/3600;      
    . \& l3 w, `5 Y7 ?" c: E0 s
  94.     calendar.min=(temp%3600)/60;   
    2 z& |, l5 q" ^" a9 C
  95.     calendar.sec=(temp%3600)%60;   
    % h/ ]% J. d6 A5 [' K
  96.     calendar.week=RTC_Get_Week(calendar.w_year,calendar.w_month,calendar.w_date);0 ]8 e# f) M; m% c4 O/ N
  97.     return 0;
    : ^  Y2 N6 _, U. d: q
  98. }     % N& E+ a7 n/ k6 |) ]4 y# Y4 q
  99. //获得是星期几 为了帮助理解,在原子论坛里找出一份,(别告我侵权哈,我在这里引用哈)           
    ( F! c$ A" |5 \
  100. u8 RTC_Get_Week(u16 year,u8 month,u8 day)! F, a* t4 m# ], T6 O- H
  101. {      q  g4 K! [1 W/ T5 `& B) A
  102.     u16 temp2;
    5 y9 D; ?% R% s+ a. T. y0 p" C0 K
  103.     u8 yearH,yearL;
    ) V5 _1 g6 K" G. J
  104.     7 s# [+ I4 y! r/ Q
  105.     yearH=year/100;    yearL=year%100; ; i, j. e! r' ]! S$ `0 g/ A- P1 |
  106.     // 如果为21世纪,年份数加100  + a1 D( i" Q2 _$ V" R
  107.     if (yearH>19)yearL+=100;
    ; M  b) U; r& |- `. x
  108.     temp2=yearL+yearL/4;   
    : h* m7 R- }  E9 ?; c& f
  109.     temp2=temp2%7; $ n  Q" V! y- }. c. L/ U0 [
  110.     temp2=temp2+day+table_week[month-1];
    - m% Q; }: E2 [+ q; l
  111.     if (yearL%4==0&&month<3)temp2--;
      B9 s; y. M% }6 R5 v  O7 N
  112.     return(temp2%7);
    + ]) G6 U8 g' W! C" m; M
  113. }
复制代码

$ U/ |- f8 U- V. Y" n
有时候,想知道公元某年某月某日是星期几,可以用下面的公式算出来:                
' R2 U& w  B! \: m9 Z3 @, m  X
     这里的方括号表示只取商的整数部分。式中:
% X, r6 ^' y, m; R1 T5 l& `

. @" z/ E" x; j. _2 ]) B& y
  x:这一年是公元多少年。
  y:这一天是这一年的第几天。
  s:星期几。不过要先除以7,再取余数。没有余数是星期日,余数是1、2、3、4、5、6,
    分别是星期一、星期二、星期三、星期四、星期五、星期六。
比如,今年国庆节(2010年10月1日)是星期几?
  x=2010。
  y=31+28+31+30+31+30+31+31+30+1=31×5+30×3+28+1=274。
  s=2010-1+502-20+5+274=2770,2770÷7余5。
所以,今年国庆节是星期五。
如果,你只想知道这个公式怎样用,到这儿就可以了。而要想知道这个公式的道理是什么,那可就说来话长了。
“星期制”是公元321年3月7日,古罗马皇帝君士坦丁宣布开始实行的,并且规定这一天为星期一。实际上,就是把公元元年元旦(公元1年1月1日)规定为星期一。(相当于公式中的x=1,y=1,所以s=1。)
通常1年有365天,365÷7=52……1,就是说比52个星期多1天。所以,同一个日期,下一年是星期几,就要比上一年向后推1天。比如,上一年元旦是星期三,下一年元旦就是星期四。
通常,每过1年,同一日期是星期几就要向后推1天”,是理解这个公式的关键。
要想知道某年某月某日是星期几,首先,要知道这一年元旦以公元元年元旦是星期一为起点,已经把星期几向后推了多少天,还要知道这一天是这一年的第几天。而要知道这一年元旦已经把星期几向后推了多少天,可以从公元元年到这一年已经过了多少年算起,先按1年向后推1天计算,再根据闰年的规定进行调整。
闰年的规定是:年份是4的倍数的一般都是闰年,其中,年份是整百数的一般不是闰年,只有年份是400的倍数的才是闰年。
现在,可以解释公式中各部分的含义了。

" A8 u0 k3 r& s* |) ?( l
收藏 评论0 发布时间:2022-2-9 21:34

举报

0个回答

所属标签

相似分享

官网相关资源

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