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

【经验分享】STM32实例-RTC实时时钟实验③-RTC设置日期时间函数

[复制链接]
STMCU小助手 发布时间:2022-6-28 18:34
  本实验使用到硬件资源如下:
(1)D1 指示灯
(2)串口 1
(3)RTC
    D1 指示灯、串口 1 电路在前面章节都介绍过,这里就不多说,至于 RTC 它属于 STM32F1 芯片内部的资源,只要通过软件配置好即可使用。D1 指示灯用来提示系统运行状态。串口1将读取的 RTC 时间日期信息打印出来。
    这里需要注意 RTC 不能断电,否则时间数据将会丢失,如果想让时间在断电后还可以继续走,那么必须确保开发板上的纽扣电池有电。
    实验所要实现的功能是:设置 RTC 时间日期初值,在 RTC 秒中断内使用串口打印出RTC 日期和时间,D1指示灯闪烁提示系统运行。程序框架如下:
(1)初始化 RTC,设置RTC 时间日期初值
(2)开启 RTC 的秒中断,编写 RTC 中断函数,
(3)在 RTC 中断内更新时间并打印输出
(4)编写主函数
    前面介绍 RTC 配置步骤时, 就已经讲解如何初始化 RTC。下面我们打开 “RTC 实时时钟实验”工程,在 APP 工程组中添加 rtc.c 文件(里面包含了 RTC 驱动程序),在 StdPeriph_Driver 工程组中添加 stm32f10x_rtc.c、stm32f10x_pwr.c 和 stm32f10x_bkp.c 库文件。RTC操作的库函数都放在 stm32f10x_rtc.c、stm32f10x_pwr.c 和 stm32f10x_bkp.c及对应的头文件中,所以使用到 RTC 就必须加入 stm32f10x_rtc.c、stm32f10x_pwr.c 和 stm32f10x_bkp.c 文件,同时还要包含对应的头文件路径。
    这里我们分析几个重要函数,其他部分程序大家可以打开工程查看。
RTC初始化函数
要使用 RTC,我们必须先对它进行配置。初始化代码如下:
  1. /****************************************************************
    : v2 }$ c& ~: X; {8 H' l( b) r% l; ~5 f
  2. * 函 数 名 : RTC_Init) d% `4 K7 \* K; l, Z! ]" O
  3. * 函数功能 : RTC 初始化
    4 P; G) b4 \1 n5 L
  4. * 输 入 : 无' V' J/ Z+ V, G) S
  5. * 输 出 : 0,初始化成功5 l( S) }# I# E0 t
  6. 1,LSE开启失败" N! B) z$ k9 G3 A' F$ n  t
  7. *****************************************************************/: c$ ^$ {1 z1 y' T' M5 K
  8. u8 RTC_Init(void)
      p% T  q# O( u1 S7 t7 K4 P$ D
  9. {$ H( w1 W4 B' C. z; a+ P6 e: ]
  10. //检查是不是第一次配置时钟
    : Y* {( L# r2 X" {. l
  11. u8 temp=0;
    ! W6 i( J( l1 O7 a$ d' r1 t8 g
  12. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,
    / X( Q" u8 ~) G  Q3 l% F7 n
  13. ENABLE); //使能 PWR 和BKP外设时钟
    ( p& J: m5 J8 J8 C9 Q
  14. PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问6 g9 w: G- O6 Q5 r) z" e5 w# ~7 I
  15. if (BKP_ReadBackupRegister(BKP_DR1) != 0xA0A0) // 从 指 定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
    1 z% }$ z+ s# \% |+ ~% X' u
  16. {
    # [8 b# W" Z. f7 V% S  W- t, }( G
  17. BKP_DeInit(); //复位备份区域& m4 C+ `- O" V" k  ~
  18. RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE),使用外设低速晶振
    7 E- b: b3 r. Z: i% ]' J0 S
  19. while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)
    % U' G2 a3 @: E5 Q8 @3 _( \
  20. //检查指定的 RCC 标志位设置与否,等待低速晶振就绪
    + p+ o( e. f5 F
  21. {1 |, A$ g* ]) {0 _' Y5 I
  22. temp++;% b3 W& i; b# T% A
  23. delay_ms(10);
    4 u) v. i% x' f  h) V( i, I" ~. q
  24. }: t+ ?; g: s! D/ \
  25. if(temp>=250)return 1;//初始化时钟失败,晶振有问题. [0 |/ m7 E! g/ s
  26. RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置 RTC 时钟(RTCCLK),选择 LSE 作为RTC时钟
    4 \5 |! D( J/ E' i+ n$ ]% w
  27. RCC_RTCCLKCmd(ENABLE); //使能 RTC 时钟3 ?& `9 j; c2 Z/ O
  28. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成$ P3 o1 o4 T4 Y% y
  29. RTC_WaitForSynchro(); //等待 RTC 寄存器同步5 N1 S$ O5 x! P- Q+ }* O
  30. RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC秒中断2 l5 q' a, t# r
  31. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成& Q7 B, H" \. }! L
  32. RTC_EnterConfigMode();// 允许配置; B+ N3 L: w5 [1 k1 ]4 X3 |
  33. RTC_SetPrescaler(32767); //设置 RTC 预分频的值' L; A/ ]1 y& t8 g% j' ~
  34. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成% |9 ?7 u, W# z; E; Y
  35. RTC_Set(2017,3,22,17,34,55); //设置时间
    1 N. W2 k$ W& D9 z! J, ]
  36. RTC_ExitConfigMode(); //退出配置模式# x) \9 m4 ~9 }7 O# A8 m& {
  37. BKP_WriteBackupRegister(BKP_DR1, 0XA0A0); //向指定的后备寄存器中写入用户程序数据1 k# R2 @% E7 ?, U1 p+ ]0 t
  38. }. r- l' q/ ?* N1 ~! N+ H
  39. else//系统继续计时
    ! U9 b. r" F9 a" u( ~, l
  40. {4 ~$ |4 l: r: i5 r6 {
  41. RTC_WaitForSynchro(); //等待最近一次对 RTC 寄存器的写操作完成
    # i1 p- R6 Q0 W) I
  42. RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC秒中断# Q( b8 z$ v" P+ k: t
  43. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成
    0 X* ?, j) R  f6 }
  44. }8 F: j# M- s* m  D
  45. RTC_NVIC_Config();//RCT 中断分组设置5 b: @! v8 `& u$ K* X1 V" Y
  46. RTC_Get();//更新时间3 i+ x8 n: v9 O5 }& F2 U
  47. return 0; //ok
    * _' w3 W: g4 Z- M: G( F6 ?
  48. }
复制代码

& X& a7 J; {4 ?  R7 d
    在 RTC_Init()函数中,首先使能电源 PWR 和后备域时钟,打开后备寄存器
* S, W8 H. {& T' A2 [
写访问,因为 RTC 初始化和初值的设置只需执行一次即可,第一次初始化 RTC,我们只需按照前面介绍的RTC配置步骤完成, 在设置 RTC 时间和日期初值时是通过 RTC_Set 函数完成,其实里面还是调用 RTC_SetCounter 完成的,这里单独写这个函数是为了方便设置RTC时间和日期。默认我们将RTC初值日期设置为2017年 3月22 日,初值时间设置为17 点 34 分 55 秒。
    设置好时间后我们调用函数 RTC_WriteBackupRegister 向 RTC 的 BKR 寄存器(地址 0)写入标志字 0XA0A0,用于 标 记 时 间 已 经 被 设 置 了 。
    这 样 ,再 次 发 生 复 位 的 时 候 , 通 过 调 用 函 数RTC_ReadBackupRegister 判断 RTC 对应 BKR 地址的值,来决定是不是需要重新设置时间,如果不需要设置,则跳过时间设置,这样就不会重复设置时间,使得我们设置的时间不会因复位或者断电而丢失。
    写备份域寄存器函数RTC_WriteBackupRegister 原形是:
  1. void RTC_WriteBackupRegister(uint32_t RTC_BKP_DR, uint32_t Data);
复制代码
5 c* c. l9 z- @1 W- [
    参数 RTC_BKP_DR 可以选择是 RTC_BKP_DR1-RTC_BKP_DR42。- l' p, B) h$ }' V; U+ m1 o5 t
读取备份域寄存器函数RTC_ReadBackupRegister 原形是:
  1. uint32_t RTC_ReadBackupRegister(uint32_t RTC_BKP_DR);
复制代码
4 l0 R0 J* |7 J0 }2 l4 }$ e6 J
    参数 RTC_BKP_DR 可以选择是 RTC_BKP_DR1-RTC_BKP_DR42。
; u3 v: K5 X( }( j2 v# K
    最后我们的 RTC 初始化函数 RTC_Init 带有一个返回值,如果返回值为 1 表示 RTC初始化失败,否则成功。

4 d1 f/ r# N1 ^7 V+ X. K
RTC设置日期时间函数
    在RTC 初始化函数内调用了一个 RTC_Set 函数设置日期和时间, 具体代码如下
  1. /****************************************************************5 }: c5 x8 Z& ]8 e9 n
  2. * 函 数 名 : RTC_Set. _: \. z3 b( ]
  3. * 函数功能 : RTC 设置日期时间函数(以 1970 年 1 月 1 日为基准,把输入的时钟转换为秒钟)1970~2099 年为合法年份
    1 f! i4 @0 G2 \) ?! z& k) c
  4. * 输 入 : syear:年 smon:月 sday:日hour:时 min:分 sec:秒
    ' S9 _! c! D& \8 Q
  5. * 输 出 : 0,成功1,失败
      B* M  e7 P) q. \3 `, e
  6. *****************************************************************/
    4 |4 @( ~: b# K% J( A( o
  7. u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)9 {* @7 H+ q8 A+ X- r4 L
  8. {
    1 P! ^( X; [" ^; k
  9. u16 t;
    % y, Z- |" g+ R) f- |0 r- y. Q
  10. u32 seccount=0;: m! l" ^9 \, V" [% }3 I8 L) b$ B) F' v
  11. if(syear<1970||syear>2099)return 1;
    & d- `) _, d6 n
  12. for(t=1970;t<syear;t++) //把所有年份的秒钟相加+ `& F) H/ @9 k
  13. {
    " N* d' F" M4 \' @/ P
  14. if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数/ F+ K* O0 H" b* o2 }: @
  15. else seccount+=31536000; //平年的秒钟数) I9 _& E/ R6 I
  16. }
    0 s4 |1 |# ?* Y( O* u# r
  17. smon-=1;
    8 y7 J8 _, e6 s. p/ w7 U" A
  18. for(t=0;t<smon;t++) //把前面月份的秒钟数相加7 ^$ y6 u, e: o* n3 `) C( l
  19. {# `0 r( s, D/ E0 P; E  [) D5 h8 G
  20. seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加; E' ^# k, {. ~& r
  21. if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数
    0 G' ^! Q( P3 c5 S* l' e7 ^4 t
  22. }
    " X2 c; M7 l5 t* h2 M
  23. seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加
    / ^% h9 H" b  S3 d
  24. seccount+=(u32)hour*3600;//小时秒钟数
    9 V9 f" z/ ~# \, C3 b( c, Q( |: _' f
  25. seccount+=(u32)min*60; //分钟秒钟数
    7 A% v( ]4 Z) B/ H* E: [
  26. seccount+=sec;//最后的秒钟加上去  v: q" z# n1 Y; N& F* ~  |0 l
  27. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE); //使能 PWR 和BKP外设时钟. H; A0 D; S# ]5 }/ B2 J3 b( h
  28. PWR_BackupAccessCmd(ENABLE); //使能 RTC 和后备寄存器访问- a- a! k/ p6 [: u; t, j
  29. RTC_SetCounter(seccount); //设置 RTC 计数器的值* L( \( }8 O7 ]5 J9 }  f- s0 [9 }
  30. RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成9 q+ P7 w; M. A1 H; S) P
  31. return 0;# q% a: e' K6 T& z
  32. }
复制代码
/ s$ ~  o% `" f0 t
    该函数用于设置日期时间,把我们输入的时间,转换为以 1970 年 1 月 1
3 p8 m* r4 X, n, S' K; r9 e
日 0 时 0 分 0 秒当做起始时间的秒钟信号,后续的计算都以这个时间为基准
的,由于 STM32 的秒钟计数器可以保存 136 年的秒钟数据,这样我们可以计时到 2106 年。
    Rtc.c 文件内还有一个闹钟设置函数 RTC_Alarm_Set,此函数与设置时间函数完全一样,只是函数名不同而已。
5 |" V- R7 x  {; ^" j
赞 收藏 评论0 发布时间:2022-6-28 18:34

举报

0个回答

所属标签

相似技术帖

官网相关资源

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