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

【经验分享】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. /****************************************************************
    : _& m9 W3 j, [8 W. `  M7 D# F
  2. * 函 数 名 : RTC_Init
    . x- Z. A  @. h4 t5 E1 {2 z
  3. * 函数功能 : RTC 初始化0 t( _+ B  f6 T$ z) ~5 W# ^
  4. * 输 入 : 无
    - T+ p( X! Z5 M: `! Z1 M6 n
  5. * 输 出 : 0,初始化成功
    % |8 m9 x  g$ m! `- D4 G
  6. 1,LSE开启失败2 f) V+ X6 q! D+ g. g6 E- g" t8 W+ g
  7. *****************************************************************/8 t( F; K2 k! S2 C/ S. S, v
  8. u8 RTC_Init(void)
    4 h' _5 `/ k# g, s! S& N/ L/ u
  9. {% S( `* G: D: O1 u+ B* |1 c' P
  10. //检查是不是第一次配置时钟
    ! d4 K4 U9 j6 D$ R  _- ^$ T, t
  11. u8 temp=0;
    7 R+ D) ?0 K3 a1 Y) q* q* _8 j
  12. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,
    2 p* D3 @9 a7 |& ]. k2 a
  13. ENABLE); //使能 PWR 和BKP外设时钟! K6 V2 J, }) @. l4 O8 l
  14. PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问
    2 S6 h8 U( Q7 s% ?) i/ x3 T
  15. if (BKP_ReadBackupRegister(BKP_DR1) != 0xA0A0) // 从 指 定的后备寄存器中读出数据:读出了与写入的指定数据不相乎- ]' Z7 n9 ]  l" s6 Q5 u! u" l. M
  16. {
    4 y  a& u; E3 }# h+ B7 t
  17. BKP_DeInit(); //复位备份区域1 f. V/ {3 M* @8 O, }/ O' \
  18. RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE),使用外设低速晶振
    2 y# f3 Z) U$ O
  19. while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)% ]& ~% v2 d2 ]2 i
  20. //检查指定的 RCC 标志位设置与否,等待低速晶振就绪* E7 U; h0 Y; s; t) m+ s3 s
  21. {# U& `" W0 [6 P4 g
  22. temp++;
    % Z9 `! B2 ^$ w. e# E1 p( J; B
  23. delay_ms(10);2 J% L: n$ ~' _! V4 Q5 ?: ^
  24. }) ]. X$ M7 I: ]1 n& _3 x5 \
  25. if(temp>=250)return 1;//初始化时钟失败,晶振有问题
    ' E. ~% `3 n6 H8 v3 }  m
  26. RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置 RTC 时钟(RTCCLK),选择 LSE 作为RTC时钟! L5 n9 `; l$ x$ z9 F0 E0 I
  27. RCC_RTCCLKCmd(ENABLE); //使能 RTC 时钟" s  C! c' v9 M8 y
  28. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成9 v3 y* \( @, z8 f3 K' g2 B& S* B
  29. RTC_WaitForSynchro(); //等待 RTC 寄存器同步1 C" r2 d- d! G
  30. RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC秒中断
    : J  z6 O' b3 y' ~3 R) H
  31. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成5 v" |8 R: q; E) H) x" Q
  32. RTC_EnterConfigMode();// 允许配置
    # K" ]( K0 K, E6 h
  33. RTC_SetPrescaler(32767); //设置 RTC 预分频的值
    9 }, K" Q9 W, n: Y2 b& ~: J2 f$ c
  34. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成
    6 f; _% D: a* g
  35. RTC_Set(2017,3,22,17,34,55); //设置时间
    8 t4 ]% B" M, W( L' [. S) N. ^$ D
  36. RTC_ExitConfigMode(); //退出配置模式: H$ S5 [0 `+ u3 g/ f5 I: }
  37. BKP_WriteBackupRegister(BKP_DR1, 0XA0A0); //向指定的后备寄存器中写入用户程序数据
    ) E% q4 e' R+ \
  38. }
    7 @- D3 w( ]. i) s) ~& Q
  39. else//系统继续计时
      ~, m" W) [5 {$ ~: {
  40. {
    $ q0 J5 q( i4 S1 D
  41. RTC_WaitForSynchro(); //等待最近一次对 RTC 寄存器的写操作完成
    0 U6 M  ?. _6 B# [' f5 h$ ]  ^
  42. RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC秒中断
    * {. m% c/ f% {, C4 p9 [: K- S
  43. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成- g0 l! s, r; K+ Z) g- w
  44. }. I/ a$ D. l5 A, \' O6 s' E
  45. RTC_NVIC_Config();//RCT 中断分组设置: H2 f9 X- {0 M8 k
  46. RTC_Get();//更新时间4 G9 N4 }; c/ Y, s$ z
  47. return 0; //ok- F0 v  L$ g5 P& L
  48. }
复制代码
' p. H9 A  h, S7 \7 |0 y5 s+ [
    在 RTC_Init()函数中,首先使能电源 PWR 和后备域时钟,打开后备寄存器
) V. b3 j& I! U' k+ B
写访问,因为 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- C/ m' w6 s( T; o+ H
    参数 RTC_BKP_DR 可以选择是 RTC_BKP_DR1-RTC_BKP_DR42。; C  m5 I1 k* {8 g- b' J
读取备份域寄存器函数RTC_ReadBackupRegister 原形是:
  1. uint32_t RTC_ReadBackupRegister(uint32_t RTC_BKP_DR);
复制代码
& I2 Q2 d: Z* I4 y9 o: C
    参数 RTC_BKP_DR 可以选择是 RTC_BKP_DR1-RTC_BKP_DR42。
3 s& Z- n/ s: J+ a8 x
    最后我们的 RTC 初始化函数 RTC_Init 带有一个返回值,如果返回值为 1 表示 RTC初始化失败,否则成功。

. N' }: j. ^6 `# @
RTC设置日期时间函数
    在RTC 初始化函数内调用了一个 RTC_Set 函数设置日期和时间, 具体代码如下
  1. /****************************************************************+ N2 y9 w& X7 g: ?' @( M! ?
  2. * 函 数 名 : RTC_Set
    $ ~' r) W. k1 K3 G  l
  3. * 函数功能 : RTC 设置日期时间函数(以 1970 年 1 月 1 日为基准,把输入的时钟转换为秒钟)1970~2099 年为合法年份! Z4 V& V7 h: j8 \, y2 i! }
  4. * 输 入 : syear:年 smon:月 sday:日hour:时 min:分 sec:秒0 }( z* C9 m4 I# \$ w* o( L
  5. * 输 出 : 0,成功1,失败
    & f3 }8 ~  w# z# W. u# g$ f( ]9 p
  6. *****************************************************************/
    + Q# p1 p- x0 ~* M9 W% F
  7. u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)
    ( e1 ]2 x  X, I
  8. {
    + Q: _- n5 a3 ^2 O
  9. u16 t;
    8 c; P$ K+ U# M
  10. u32 seccount=0;
    8 M" |7 ?3 Q! w
  11. if(syear<1970||syear>2099)return 1;
    * g! U9 L# |# A' G- b& A5 J
  12. for(t=1970;t<syear;t++) //把所有年份的秒钟相加
    8 ^9 I  H8 s7 v$ V& X* F. A3 \, v% S) t
  13. {: U7 @$ v! }* n9 ?8 k% P* I6 g! `
  14. if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数, s7 n/ G1 _- Y- f2 d
  15. else seccount+=31536000; //平年的秒钟数3 w5 p; r9 ]3 _- K
  16. }
    ( y1 A. d( ^# |
  17. smon-=1;
    ' {7 a) s4 K' k4 @
  18. for(t=0;t<smon;t++) //把前面月份的秒钟数相加
    4 c/ }4 O: H7 t8 [* I
  19. {
    + f) ?! L( d  f! l7 _
  20. seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加# E) B8 E3 U) O. S# b5 z, q
  21. if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数
    - ?  P: b) w+ {' f2 }) _
  22. }7 w% I2 A4 g4 S6 V# ^1 I' U- f; D
  23. seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加0 V* x' j* [. F. |% q) u% {
  24. seccount+=(u32)hour*3600;//小时秒钟数
    4 ]3 X$ [* D& s4 `7 u
  25. seccount+=(u32)min*60; //分钟秒钟数& B1 l' Q9 x1 v" K) b0 k% `
  26. seccount+=sec;//最后的秒钟加上去
    ' P# m8 I' M8 ]- A% I% L( q
  27. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE); //使能 PWR 和BKP外设时钟
    9 ~9 d* y& Z6 X  a* f: O
  28. PWR_BackupAccessCmd(ENABLE); //使能 RTC 和后备寄存器访问
    ' \* d* P5 n( a+ {2 J( v* N/ I
  29. RTC_SetCounter(seccount); //设置 RTC 计数器的值4 B! ?% ~7 i6 F  z$ {! ~
  30. RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成9 o/ y  l: a: W; h( z
  31. return 0;
    , K* I$ J3 G: m
  32. }
复制代码

) D; N5 z  ?3 Z3 Q. g7 S
    该函数用于设置日期时间,把我们输入的时间,转换为以 1970 年 1 月 17 h% G) I5 j2 U! m0 m6 z
日 0 时 0 分 0 秒当做起始时间的秒钟信号,后续的计算都以这个时间为基准
的,由于 STM32 的秒钟计数器可以保存 136 年的秒钟数据,这样我们可以计时到 2106 年。
    Rtc.c 文件内还有一个闹钟设置函数 RTC_Alarm_Set,此函数与设置时间函数完全一样,只是函数名不同而已。
. F* z; _  `2 o3 q6 m' R5 G/ u9 `
收藏 评论0 发布时间:2022-6-28 18:34

举报

0个回答

所属标签

相似分享

官网相关资源

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