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

【经验分享】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. /****************************************************************$ D" L% `& a  G) ]. M' }
  2. * 函 数 名 : RTC_Init: L+ ^1 J' E" j2 t
  3. * 函数功能 : RTC 初始化& i2 _( w- ~9 K( D3 v9 y
  4. * 输 入 : 无. Y2 N, D3 A7 K
  5. * 输 出 : 0,初始化成功
    9 z5 T% p- ^% C" C  W" f' E8 z
  6. 1,LSE开启失败
    ( o! F. u! F* @, I
  7. *****************************************************************/
    , J7 o/ v1 F- i# y% Q% s
  8. u8 RTC_Init(void)
    9 b% k" l( z3 P& h$ L7 B3 v# `
  9. {- ^) a/ V) R1 ]5 I' z& f
  10. //检查是不是第一次配置时钟" V9 z; M9 D3 |: _$ e2 S: Q7 ?4 d
  11. u8 temp=0;. d$ Y4 r) ?4 ^( Q$ K1 g
  12. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,2 u) S% x9 N: p
  13. ENABLE); //使能 PWR 和BKP外设时钟+ f8 j% m& \0 c: _( J2 S
  14. PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问- l9 i! p/ }, x3 Z" X
  15. if (BKP_ReadBackupRegister(BKP_DR1) != 0xA0A0) // 从 指 定的后备寄存器中读出数据:读出了与写入的指定数据不相乎( t/ r/ H" x& g! N/ V
  16. {& T/ T" a( ~$ y! q( k% `
  17. BKP_DeInit(); //复位备份区域
    # l( b  @7 X: o
  18. RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE),使用外设低速晶振
    8 _! {$ h/ C3 z) z, q7 m, J
  19. while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)
    + n8 @: R0 H* b7 E9 g
  20. //检查指定的 RCC 标志位设置与否,等待低速晶振就绪% J- ~7 ?/ n/ @( T% z
  21. {
    - q5 U7 x& L% R+ r1 x
  22. temp++;! Z1 Z, b* {- [- A3 C
  23. delay_ms(10);
    ' C4 i, k3 @. Q% _) A9 r0 c+ G
  24. }
    , r% g, D& S+ u4 q) v( @6 H5 H; w3 Y
  25. if(temp>=250)return 1;//初始化时钟失败,晶振有问题
    3 L' @( {8 @. q) ~9 J$ a
  26. RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置 RTC 时钟(RTCCLK),选择 LSE 作为RTC时钟6 z' M7 w* ~# W& ]8 M4 o/ P' |
  27. RCC_RTCCLKCmd(ENABLE); //使能 RTC 时钟
    9 D; |( d/ ^- i: E5 T( A
  28. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成
    / u: t4 Y- b8 F
  29. RTC_WaitForSynchro(); //等待 RTC 寄存器同步  E) |& F/ s: y2 ^6 a# z
  30. RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC秒中断
    - A- q+ B/ U, Z+ V8 `6 H  E
  31. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成
    3 _& {; q/ _0 x# j, I( I; I
  32. RTC_EnterConfigMode();// 允许配置
    1 a% y: ^6 D* H4 R
  33. RTC_SetPrescaler(32767); //设置 RTC 预分频的值
    . P3 x! U, f1 M2 i1 |2 C
  34. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成9 K" c' d2 |. O$ `, \4 E
  35. RTC_Set(2017,3,22,17,34,55); //设置时间
    ( Y7 @- Z7 l" }. H2 g2 }
  36. RTC_ExitConfigMode(); //退出配置模式4 T$ ~+ D2 ?- n; [1 I
  37. BKP_WriteBackupRegister(BKP_DR1, 0XA0A0); //向指定的后备寄存器中写入用户程序数据% t2 i; ?8 V% C
  38. }' V% W; v; F$ G( G
  39. else//系统继续计时
    1 S* @+ l5 q$ ^: f' V
  40. {# j2 o( Y4 T! ~8 u. @
  41. RTC_WaitForSynchro(); //等待最近一次对 RTC 寄存器的写操作完成
    + y+ `2 C2 M6 \2 S* R1 p4 W0 S
  42. RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC秒中断' [1 n4 {0 [5 x  V: `. }7 W2 e6 N! s
  43. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成
    3 r7 r3 w1 G7 L0 g
  44. }
    0 x! P' Z  e" v2 x/ p
  45. RTC_NVIC_Config();//RCT 中断分组设置
    ; ]5 T! t8 K7 j
  46. RTC_Get();//更新时间3 B. r3 o5 _3 \; Y7 t
  47. return 0; //ok9 m4 V" }5 w+ k. E7 e/ ~  D6 C
  48. }
复制代码
' I8 v$ j" K8 n# I
    在 RTC_Init()函数中,首先使能电源 PWR 和后备域时钟,打开后备寄存器
; ]* j& Y% \0 L9 g7 q4 o0 O9 D: V* \
写访问,因为 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);
复制代码
1 h; k8 W- Q9 O; m* ~1 C: q
    参数 RTC_BKP_DR 可以选择是 RTC_BKP_DR1-RTC_BKP_DR42。/ x- j! z0 m. Y7 f# P! b% x8 i
读取备份域寄存器函数RTC_ReadBackupRegister 原形是:
  1. uint32_t RTC_ReadBackupRegister(uint32_t RTC_BKP_DR);
复制代码

1 C1 J, Y& `" O* s4 |/ C2 s
    参数 RTC_BKP_DR 可以选择是 RTC_BKP_DR1-RTC_BKP_DR42。
5 S9 a) }  N8 i! f0 b- s
    最后我们的 RTC 初始化函数 RTC_Init 带有一个返回值,如果返回值为 1 表示 RTC初始化失败,否则成功。
1 n2 K! g: ^0 B0 o& O7 k+ ^
RTC设置日期时间函数
    在RTC 初始化函数内调用了一个 RTC_Set 函数设置日期和时间, 具体代码如下
  1. /****************************************************************
    9 c" V4 W! ?4 ?& |
  2. * 函 数 名 : RTC_Set
    0 d$ S0 C5 ~+ ]* i2 l
  3. * 函数功能 : RTC 设置日期时间函数(以 1970 年 1 月 1 日为基准,把输入的时钟转换为秒钟)1970~2099 年为合法年份
    / F* s7 E8 _+ g; C
  4. * 输 入 : syear:年 smon:月 sday:日hour:时 min:分 sec:秒5 Z& w2 u: |9 l4 K7 i
  5. * 输 出 : 0,成功1,失败7 k7 F8 _1 K1 ?; ?3 o
  6. *****************************************************************/7 v' j5 Z* P5 e$ G; Q* L( Q* I& S
  7. u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)" }! Y/ U9 F3 U' F2 J% L
  8. {( [1 b" S' s# d. `! B
  9. u16 t;; B" Y( S% w5 d) `
  10. u32 seccount=0;, F& ~1 _5 j  q) Z6 _' k
  11. if(syear<1970||syear>2099)return 1;
    + G2 y9 n- a9 ^# u( ]  I
  12. for(t=1970;t<syear;t++) //把所有年份的秒钟相加' j; {: t2 Z" F3 H: S0 \6 E7 T
  13. {! H4 u& k. ~3 @1 ~  w6 W: d
  14. if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数
    . W( G$ }/ Z) G+ n' ?6 [
  15. else seccount+=31536000; //平年的秒钟数
    # n( O0 [/ r1 `# t0 x+ b7 F# Y
  16. }
    . s1 r+ I6 G; S7 v: D) s: ^: d1 g9 ~
  17. smon-=1;
    # @) d7 I& M9 w* R5 K& I) S& _
  18. for(t=0;t<smon;t++) //把前面月份的秒钟数相加$ k/ n' q; F- x& r6 O
  19. {
    7 W0 E) [! K7 J+ d& ?! D* ~
  20. seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加: M5 B$ B4 @# q: L, R
  21. if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数+ z' G9 W# G- ^1 j4 U6 T( I
  22. }# u: ^  o! t3 f& f6 c
  23. seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加$ @) g, K4 n0 }
  24. seccount+=(u32)hour*3600;//小时秒钟数
    # s3 |. n1 ?" \) ?( h5 o1 i
  25. seccount+=(u32)min*60; //分钟秒钟数
    * U8 e+ }/ I2 e& ^) N- F# Z
  26. seccount+=sec;//最后的秒钟加上去( I* Q3 r4 e, \  q* x, h9 i
  27. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE); //使能 PWR 和BKP外设时钟
    2 k' {$ F& h" N
  28. PWR_BackupAccessCmd(ENABLE); //使能 RTC 和后备寄存器访问
    0 t* v' t+ q  L& ^: I7 T& J# l7 h
  29. RTC_SetCounter(seccount); //设置 RTC 计数器的值
    ! ]8 w+ F0 Y/ I8 @- }0 d/ e/ j
  30. RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成
    4 [' ?8 T. s" M2 C4 a! o
  31. return 0;
    $ x# t1 r0 ^2 o: O! e( k
  32. }
复制代码
1 B" m3 Y0 q! M' e
    该函数用于设置日期时间,把我们输入的时间,转换为以 1970 年 1 月 1
; z# |/ z6 E" d# h9 _/ ~8 O' L
日 0 时 0 分 0 秒当做起始时间的秒钟信号,后续的计算都以这个时间为基准
的,由于 STM32 的秒钟计数器可以保存 136 年的秒钟数据,这样我们可以计时到 2106 年。
    Rtc.c 文件内还有一个闹钟设置函数 RTC_Alarm_Set,此函数与设置时间函数完全一样,只是函数名不同而已。
- ]/ ~3 S3 p) X3 r& c7 ~! H! _
收藏 评论0 发布时间:2022-6-28 18:34

举报

0个回答

所属标签

相似分享

官网相关资源

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