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

【经验分享】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. /****************************************************************
    + B9 y1 p, ^$ _# Y. a8 k. w6 `
  2. * 函 数 名 : RTC_Init
    ( \3 k% t2 ?9 \
  3. * 函数功能 : RTC 初始化
    6 B2 A) O# ?# b" R
  4. * 输 入 : 无
      r6 m6 Y0 A6 {. n
  5. * 输 出 : 0,初始化成功" O8 N; {! }) V3 x2 i9 U( K
  6. 1,LSE开启失败3 F7 z! n4 L3 n' U( Y
  7. *****************************************************************/( f# Q- m; ?: F/ f1 n" n. Y
  8. u8 RTC_Init(void): G3 f. z& J; h# f
  9. {. V2 |' X0 C* F' {4 x4 @' U
  10. //检查是不是第一次配置时钟- R4 u' |+ {7 K  |+ f8 u
  11. u8 temp=0;
    5 ~( x2 ?- h6 w% {6 T" _# u
  12. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,+ {( ]1 Z$ s$ k8 z2 L9 i
  13. ENABLE); //使能 PWR 和BKP外设时钟8 t. C$ j2 Y" O( q% u0 {- h1 r
  14. PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问
    5 Q' H0 u; _7 u6 g
  15. if (BKP_ReadBackupRegister(BKP_DR1) != 0xA0A0) // 从 指 定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
    1 G5 ?9 z, m1 u; G) D+ j+ Q
  16. {3 Q/ z) u" E+ y
  17. BKP_DeInit(); //复位备份区域
    % V% L4 h- O) t- K
  18. RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE),使用外设低速晶振& f  {  m/ e, H+ k4 {& S
  19. while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)
    - G( y" o1 W4 y, b7 a, m+ z$ d
  20. //检查指定的 RCC 标志位设置与否,等待低速晶振就绪
    . k# ^6 T9 ^+ Y+ U2 n1 x4 l: e! L" s
  21. {8 o2 i. l: M3 B+ E
  22. temp++;
    * c3 \5 n2 {, x# M/ Q  z3 E
  23. delay_ms(10);0 m3 ~( _( }# c5 r
  24. }
    5 o9 E" E# I5 t3 n6 K; E
  25. if(temp>=250)return 1;//初始化时钟失败,晶振有问题2 h% w8 J0 i! ?5 j. T/ b/ y, e" j  X
  26. RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置 RTC 时钟(RTCCLK),选择 LSE 作为RTC时钟
    6 B- X6 D% c6 Z! @4 d
  27. RCC_RTCCLKCmd(ENABLE); //使能 RTC 时钟% ?% u6 d3 c0 g6 n9 a: C
  28. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成: [0 t2 E, _, V1 k# K( X9 v
  29. RTC_WaitForSynchro(); //等待 RTC 寄存器同步/ T9 ]5 ~$ ?  [; C( C" A7 G; X
  30. RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC秒中断
    8 U0 U2 g2 W* Z. F) B
  31. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成2 J5 @3 [% I# R, ~6 `% M0 |
  32. RTC_EnterConfigMode();// 允许配置. ~8 @! P; L& Y0 @" i& U
  33. RTC_SetPrescaler(32767); //设置 RTC 预分频的值
    * T4 ^  c; j6 |( J4 K, W
  34. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成* w& E3 H  |1 h- m
  35. RTC_Set(2017,3,22,17,34,55); //设置时间% ^2 A: ~9 V# t6 D: H8 {$ m% L2 z3 {3 J4 ]
  36. RTC_ExitConfigMode(); //退出配置模式' T* w9 L3 l7 C. c% I
  37. BKP_WriteBackupRegister(BKP_DR1, 0XA0A0); //向指定的后备寄存器中写入用户程序数据  [, ^2 F/ s- ?0 L7 B# J
  38. }+ u* B; `6 y0 C7 \; |4 }6 p
  39. else//系统继续计时
      f% s" U- I+ H1 f/ z) Z" E4 V- o
  40. {
    / Y# i5 N; \# }* w( y" ?8 n
  41. RTC_WaitForSynchro(); //等待最近一次对 RTC 寄存器的写操作完成  c8 F) ]' w: l) g. x' z
  42. RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC秒中断
    - L; U7 {/ a; D3 R5 I' T
  43. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成$ \* h7 h; a: [% H) S9 ^
  44. }- I" D* T$ y, \3 H
  45. RTC_NVIC_Config();//RCT 中断分组设置
      d  G; C# V2 b. C- H
  46. RTC_Get();//更新时间& {5 s4 I# ~, C8 u! r$ V) ^& K( I
  47. return 0; //ok
    ( I6 n$ I& }2 W4 @3 I+ ~+ v
  48. }
复制代码

: M4 K: u3 p% H; |9 h" p; G/ F' J
    在 RTC_Init()函数中,首先使能电源 PWR 和后备域时钟,打开后备寄存器0 h4 y. n/ W$ Y- ^2 L
写访问,因为 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);
复制代码
( x  {7 ^* {  p" d
    参数 RTC_BKP_DR 可以选择是 RTC_BKP_DR1-RTC_BKP_DR42。
4 s0 y4 }; }3 W  z9 I' S8 F
读取备份域寄存器函数RTC_ReadBackupRegister 原形是:
  1. uint32_t RTC_ReadBackupRegister(uint32_t RTC_BKP_DR);
复制代码

! B" H3 N; j* j6 i1 m
    参数 RTC_BKP_DR 可以选择是 RTC_BKP_DR1-RTC_BKP_DR42。
0 G: ?8 b! y' [- c0 V5 |6 _
    最后我们的 RTC 初始化函数 RTC_Init 带有一个返回值,如果返回值为 1 表示 RTC初始化失败,否则成功。

# d. I1 @) N2 h# E' C! |
RTC设置日期时间函数
    在RTC 初始化函数内调用了一个 RTC_Set 函数设置日期和时间, 具体代码如下
  1. /****************************************************************
      I# C( Z& Y+ E6 Y7 S- |3 E
  2. * 函 数 名 : RTC_Set+ `+ h0 q5 P2 Z' O
  3. * 函数功能 : RTC 设置日期时间函数(以 1970 年 1 月 1 日为基准,把输入的时钟转换为秒钟)1970~2099 年为合法年份- S, r9 U: J. t0 y* F1 Q# Y
  4. * 输 入 : syear:年 smon:月 sday:日hour:时 min:分 sec:秒7 Z2 I* t; `5 L% E' E/ k
  5. * 输 出 : 0,成功1,失败  M9 s( ^7 S' k+ ~" w
  6. *****************************************************************/' l- q3 c$ E7 m6 P- J' ?: f& r
  7. u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)+ t4 |* d" r+ w3 O% a
  8. {
    / O2 T8 x! ]3 A
  9. u16 t;
    : P& A, F+ u! q) u% ?/ _
  10. u32 seccount=0;, _6 Y3 y% T9 V
  11. if(syear<1970||syear>2099)return 1;
    ; B7 ?+ B& R7 W' i3 `+ P
  12. for(t=1970;t<syear;t++) //把所有年份的秒钟相加+ `8 g8 f- Z2 r' M+ W
  13. {
    4 @8 o& h3 |0 w8 U& n& b
  14. if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数7 O0 p# N5 T  c
  15. else seccount+=31536000; //平年的秒钟数9 A- m, d' ~! @& B8 s% N
  16. }* ?8 U& u& d0 @# B6 |6 f
  17. smon-=1;
    , t) `) _, s. J. b6 O; F( N1 F
  18. for(t=0;t<smon;t++) //把前面月份的秒钟数相加
    + e3 Y. |4 k3 `1 N; Y  S. K
  19. {
    & |) @5 O; N6 ^
  20. seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
    ; A9 J7 ~! g  w
  21. if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数
    + N+ L3 d2 F- X3 L6 v: E/ B0 z- A
  22. }" L2 y/ x  |3 y+ D+ Q& z  _
  23. seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加
    ) G/ S! \: [: Y2 u) \- t. f
  24. seccount+=(u32)hour*3600;//小时秒钟数
    8 B5 J# l$ d5 K8 [% e
  25. seccount+=(u32)min*60; //分钟秒钟数
    * a3 Y. z$ e! ~; d/ l; }& ]; Q9 k
  26. seccount+=sec;//最后的秒钟加上去
    # N, [& \1 _9 f  v: ?
  27. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE); //使能 PWR 和BKP外设时钟. r: f7 E  @2 Q3 T9 A2 V2 I) |
  28. PWR_BackupAccessCmd(ENABLE); //使能 RTC 和后备寄存器访问
    9 {* U0 P  P. d$ N9 r
  29. RTC_SetCounter(seccount); //设置 RTC 计数器的值
    " ^4 c2 N; B3 o
  30. RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成7 r# `- C0 a$ o( G! O6 z
  31. return 0;
    + |% ~; h8 ?- j6 s  M  O5 p
  32. }
复制代码

: F0 K$ Y2 b1 _; @; H
    该函数用于设置日期时间,把我们输入的时间,转换为以 1970 年 1 月 1
) |% w) K8 `# o% c; z% W0 M& X
日 0 时 0 分 0 秒当做起始时间的秒钟信号,后续的计算都以这个时间为基准
的,由于 STM32 的秒钟计数器可以保存 136 年的秒钟数据,这样我们可以计时到 2106 年。
    Rtc.c 文件内还有一个闹钟设置函数 RTC_Alarm_Set,此函数与设置时间函数完全一样,只是函数名不同而已。

) o# _% ~- r& z- S+ S
赞 收藏 评论0 发布时间:2022-6-28 18:34

举报

0个回答

所属标签

相似技术帖

官网相关资源

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