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

【经验分享】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. /****************************************************************
    + z4 w, ]  f6 t$ M
  2. * 函 数 名 : RTC_Init1 G$ W/ U& L3 m3 J; @- K$ }' O
  3. * 函数功能 : RTC 初始化
    ! d0 z. x% ]' |. Z2 h
  4. * 输 入 : 无8 R+ l7 ~* k) c# x9 k
  5. * 输 出 : 0,初始化成功' I' S  K7 ]& n2 D! o
  6. 1,LSE开启失败$ J( Y% H8 Z' D; D. d' m$ j$ }- ?
  7. *****************************************************************/
    : d% Q' h8 d8 O7 Q8 j
  8. u8 RTC_Init(void)! E( R% i# O0 O$ A# W8 k3 M
  9. {
    ! P. P& W& A5 D+ O8 v+ L2 a$ u
  10. //检查是不是第一次配置时钟$ ]9 j; @# u( i& v2 @' ]- c
  11. u8 temp=0;
    7 M$ _# o2 u2 e& ^/ h1 w; H9 O
  12. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,/ v) w" X. \8 B' Z( s  ]
  13. ENABLE); //使能 PWR 和BKP外设时钟* U( l- t3 H% `2 [# W" {
  14. PWR_BackupAccessCmd(ENABLE); //使能后备寄存器访问
    : R0 i! y* F  q- W4 j0 _
  15. if (BKP_ReadBackupRegister(BKP_DR1) != 0xA0A0) // 从 指 定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
    8 h' v5 a& G  f; B8 d, D9 p
  16. {% a9 a7 P8 r. W) y3 j8 S1 E' w
  17. BKP_DeInit(); //复位备份区域' g2 e# A* M! a$ [0 T0 B
  18. RCC_LSEConfig(RCC_LSE_ON); //设置外部低速晶振(LSE),使用外设低速晶振
    , E0 {- e5 ?0 L. N, `9 N& `) |/ x. \
  19. while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET&&temp<250)
    9 v7 n) A' ?" Z( l4 `8 e: J6 I' @
  20. //检查指定的 RCC 标志位设置与否,等待低速晶振就绪
    6 T- [+ M9 z# b6 T
  21. {
    - f3 ^& |  v" K% o) ~
  22. temp++;
    7 M. m4 u  n" _4 m
  23. delay_ms(10);
    9 X2 X; ^1 P/ ?, e0 O
  24. }5 x' H3 s! a' J+ l: U" v
  25. if(temp>=250)return 1;//初始化时钟失败,晶振有问题
    # c% a! }( _3 ]
  26. RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //设置 RTC 时钟(RTCCLK),选择 LSE 作为RTC时钟4 X5 a. l  [* T' D
  27. RCC_RTCCLKCmd(ENABLE); //使能 RTC 时钟- [) k5 P! b; @+ A
  28. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成
    ' D' b: U% T* I7 x, n) T' a- ]. Y, o
  29. RTC_WaitForSynchro(); //等待 RTC 寄存器同步+ T8 x0 ^8 _: G; e3 a- T! l
  30. RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC秒中断) j* Q- b; i' c( }9 I4 o) X6 X
  31. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成1 d1 T6 n) v; s+ k
  32. RTC_EnterConfigMode();// 允许配置( g. s, S) k$ F4 H
  33. RTC_SetPrescaler(32767); //设置 RTC 预分频的值/ k- i/ C  Y' q# ~7 _
  34. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成' e8 d( F( G" g
  35. RTC_Set(2017,3,22,17,34,55); //设置时间4 p$ V7 y' u0 l' b
  36. RTC_ExitConfigMode(); //退出配置模式8 W9 b9 \$ N$ H5 ~1 x$ F( k* p5 W3 l% q
  37. BKP_WriteBackupRegister(BKP_DR1, 0XA0A0); //向指定的后备寄存器中写入用户程序数据
    + |' m, N/ p1 t# Q
  38. }. J# [# Y6 e4 \7 C
  39. else//系统继续计时5 ^, z" n8 w( l) B( v
  40. {
    - \1 e6 {2 e& c6 `+ E8 a
  41. RTC_WaitForSynchro(); //等待最近一次对 RTC 寄存器的写操作完成
    / ]/ g% u1 m# ^1 _( f
  42. RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能 RTC秒中断. w  C) E6 X8 o& x/ W( G: U
  43. RTC_WaitForLastTask(); //等待最近一次对 RTC 寄存器的写操作完成+ g, r$ E# R, D; S
  44. }$ s3 N( ~& c7 v1 P! j
  45. RTC_NVIC_Config();//RCT 中断分组设置4 C& U% q& t: [0 g, F) c0 G5 f
  46. RTC_Get();//更新时间( ?$ _1 \6 C7 q7 q
  47. return 0; //ok7 e' \' A- V# {6 O& Y% W# d
  48. }
复制代码
. M3 ]1 o' a  J& B& d1 u/ Q7 U
    在 RTC_Init()函数中,首先使能电源 PWR 和后备域时钟,打开后备寄存器
- H! c' d* V7 g* k
写访问,因为 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 G3 S2 N  N
    参数 RTC_BKP_DR 可以选择是 RTC_BKP_DR1-RTC_BKP_DR42。+ E( Q: R' p) W1 D: E" l0 {- \
读取备份域寄存器函数RTC_ReadBackupRegister 原形是:
  1. uint32_t RTC_ReadBackupRegister(uint32_t RTC_BKP_DR);
复制代码

. ~, s1 P9 M# H; ?
    参数 RTC_BKP_DR 可以选择是 RTC_BKP_DR1-RTC_BKP_DR42。) w( s$ X9 g0 `1 e
    最后我们的 RTC 初始化函数 RTC_Init 带有一个返回值,如果返回值为 1 表示 RTC初始化失败,否则成功。
' U0 x* b% ?7 h# s
RTC设置日期时间函数
    在RTC 初始化函数内调用了一个 RTC_Set 函数设置日期和时间, 具体代码如下
  1. /****************************************************************
    1 ]$ |7 p0 s' [' B- i. s9 j6 w
  2. * 函 数 名 : RTC_Set
    ( V" \3 J. i6 A7 }) v' A' c
  3. * 函数功能 : RTC 设置日期时间函数(以 1970 年 1 月 1 日为基准,把输入的时钟转换为秒钟)1970~2099 年为合法年份' g2 e  ]3 @/ `& g5 D; d( {
  4. * 输 入 : syear:年 smon:月 sday:日hour:时 min:分 sec:秒
      P* Q5 Y) x" b/ V1 k: R
  5. * 输 出 : 0,成功1,失败
    % b  g% B' u& q2 g  V
  6. *****************************************************************/
    & G- X& _, j, N0 N2 |  M% E! Z
  7. u8 RTC_Set(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec)7 [* m) Q/ c4 Z- E1 e' D% m
  8. {) @8 B' y& N: z$ Q) g/ h
  9. u16 t;
      B* r9 X& N9 j4 X
  10. u32 seccount=0;# n* O; v! g% D  ~
  11. if(syear<1970||syear>2099)return 1;
    # H' S" X' O7 I7 I2 u% v
  12. for(t=1970;t<syear;t++) //把所有年份的秒钟相加1 _& v& I6 s; o$ M  N7 r( d" b
  13. {! X0 _+ \4 K% q( u, T) `
  14. if(Is_Leap_Year(t))seccount+=31622400;//闰年的秒钟数! h/ u. r! a# E7 [0 \3 x  C3 @7 B
  15. else seccount+=31536000; //平年的秒钟数  S( i# R) X% p
  16. }
    3 f! X# f% O% g/ q8 m
  17. smon-=1;
    ( f6 F1 Y4 @+ y7 r
  18. for(t=0;t<smon;t++) //把前面月份的秒钟数相加: x" X  {9 [' U5 ?% g; \* M
  19. {: j2 U# x. w& L) M6 V; G* V
  20. seccount+=(u32)mon_table[t]*86400;//月份秒钟数相加
    ) ^/ n6 r* h" }7 D: y$ I
  21. if(Is_Leap_Year(syear)&&t==1)seccount+=86400;//闰年2月份增加一天的秒钟数
    : d! e  ~( g: h! \4 i8 a
  22. }/ p# `/ r. f) W6 p$ g9 H' d
  23. seccount+=(u32)(sday-1)*86400;//把前面日期的秒钟数相加
    0 J% C2 e6 I3 G
  24. seccount+=(u32)hour*3600;//小时秒钟数* V; L7 \- T* v
  25. seccount+=(u32)min*60; //分钟秒钟数
    5 }1 p) @$ u3 _$ M9 a. ?
  26. seccount+=sec;//最后的秒钟加上去' E+ _  D! B( w; X2 X" R
  27. RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE); //使能 PWR 和BKP外设时钟
    ; e/ I) H! o2 \. ]
  28. PWR_BackupAccessCmd(ENABLE); //使能 RTC 和后备寄存器访问' G% T/ j* K8 ~9 c4 \& s' U
  29. RTC_SetCounter(seccount); //设置 RTC 计数器的值
    ; r# D' o$ Y4 M* S) n
  30. RTC_WaitForLastTask(); //等待最近一次对RTC寄存器的写操作完成. w8 V6 V" C# W. P. h6 Z
  31. return 0;
    . W: ]4 d" L, ?5 e
  32. }
复制代码

9 y6 d5 n1 H' G$ F( O/ F
    该函数用于设置日期时间,把我们输入的时间,转换为以 1970 年 1 月 1
; L) J6 p5 W; F2 R! o8 m: x5 I
日 0 时 0 分 0 秒当做起始时间的秒钟信号,后续的计算都以这个时间为基准
的,由于 STM32 的秒钟计数器可以保存 136 年的秒钟数据,这样我们可以计时到 2106 年。
    Rtc.c 文件内还有一个闹钟设置函数 RTC_Alarm_Set,此函数与设置时间函数完全一样,只是函数名不同而已。

# D, |) V% N! S' D& u1 O, k; d
收藏 评论0 发布时间:2022-6-28 18:34

举报

0个回答

所属标签

相似分享

官网相关资源

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