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

STM32F103的RTC模块用作32位计数器

[复制链接]
STMCU小助手 发布时间:2021-8-13 14:27
需求背景  L+ F( S, T, ^* b  Q
在使用FreeRTOS时,如果需要统计每个任务的运行时长及百分比,则需要提供一个计时基准。9 ]0 K0 A; `- C: `. T! t8 o

, f! q# G) e" P' _2 c

/ Z+ j" f3 {6 G9 j0 a+ L分别实现以下2个函数:
, h/ D; l  x5 D1 h/ G" W+ q2 C

$ e) i; ^; g" Zvoid vConfigureTimerForRunTimeStats( void );    /* Prototype of function that initialises the run time counter. */& z7 w5 Z" p: y/ o5 k* G
unsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */, d" i9 n: m' x  V9 |  S/ O: q
: n# j! c2 J# X5 \8 C( y

+ \" r, u- a9 T0 N, c( _

" j3 P0 F7 S, ]4 E" R前一个函数需用初始化配置计时器;后一个函数用于在任务切换时获取当前计时值。
, c" |* U  c$ y' y# w7 @" N$ J/ f2 S+ ^. H

8 T' r) s5 L) T3 [3 R要求计时的频率比tick的频率要高一个数量级。目前tick为1KHz,则计时频率为10K比较合适。
8 Q5 [' d/ E% M+ ^6 G' Q* }
. P$ O  \' Z7 |

5 r: Q$ D# C& K4 A  `7 p$ X3 Z - _7 [" Q+ Q) \. r. M2 ?
方案分析
8 F! z# }! Z; Z4 U! }方案一:使用硬件定时器TIMx。4 P  Z8 f  r; J4 N* }- k
  1. <font face="微软雅黑" size="3">: H6 U" ]+ ]) N1 B. x
  2. void vConfigureTimerForRunTimeStats(void)
    1 m" Y- i" ~6 z/ j  G) o$ s# w. Q
  3. {
    ) R( [3 `3 ]2 L$ c" U6 K: Y- X
  4.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    5 `( u. S5 ]' n5 K/ ]0 r1 i

  5. 8 G% j5 J  k$ U* N$ ?- @' ^
  6.         // 时钟使能
    4 n9 J' j8 e1 }' m$ o* P
  7.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);- M* P( u( O6 |, T( D; g6 o

  8. ! {) M3 X& w$ \: Q4 F
  9.         //定时器TIMx初始化- o4 M. P& A" ~0 Q/ a4 [) s, Q
  10.         TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / 1000000 - 1; //预分频后为1MHz
    # O1 T- P. J; I' I5 X
  11.         TIM_TimeBaseStructure.TIM_Period = configTICK_RATE_HZ * 10 - 1;8 r* Z0 Q' Q3 ?! j" J6 {4 K
  12.         TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    6 V/ O) X6 ^/ r  u9 E* v
  13.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;& u+ Q! H% q8 H( \2 \; Z# m8 O
  14.         TIM_TimeBaseInit(TIMER_FOR_RUN_TIME_STAT, &TIM_TimeBaseStructure);' z; t- h/ `5 r5 H
  15. 1 G9 f% M7 M/ N4 X$ r
  16.         TIM_Cmd(TIM3, ENABLE);9 @0 L: z$ T5 z4 |1 w- C
  17. }$ o! v( ?9 _+ g4 ~$ @8 j% `
  18. : O! _6 c7 ?8 H. m( Z: G- v
  19. unsigned long ulGetRunTimeCounterValue(void)
    3 c6 g3 ]$ u& a! t
  20. {
    1 X$ P' C* @! z; o
  21.         return TIM_GetCounter(TIM3);) h% W" K3 H# E3 ?

  22. , \6 S7 w2 n& E; Z& Q
  23. </font>
复制代码
问题:STM32F103的硬件定时器是16位的。最大计数值为64K,当计数频率为40K时,只需要1秒多一点就溢出了。4 V! s7 l- J$ n5 _" M/ ?0 O
3 V( c! f: g7 K( ]
& N* N5 `; N0 y+ Q
方案二:使用2个硬件定时器级联,组成一个32位计数器
9 Q" t. ~. e8 E) l7 o3 c) |, D7 G3 }# Q5 Y* ~1 \
# C, G4 [! H% h$ b9 P, E' D9 G7 ?
方案三:使用os的tick  r0 A& j2 c, D' |* a
代码如下。" \9 I$ C: Z' Y' G  o/ B$ @
  1. <font face="微软雅黑" size="3">{</font>
复制代码
问题:精度较低。) S1 h7 v: t2 }/ O8 h7 `6 ?

. Y, P) C/ M' ]5 b; h- D- {7 i* N

% p% ^' \! S% x. h' n方案四:使用RTC作为计数器
+ @2 V" j' Z6 H! R: B/ {' E具体如下。: @+ ~# R% Y' k: ^* z9 ^" B1 J7 N0 a

- l$ W3 ^5 C/ m- _: w$ u

/ T/ s6 X( l4 G; h- ]( F使用RTC作为计数器8 K3 D+ L6 {6 F) M8 s
在STM32F103中,RTC的本质并不是一个实时时钟模块,只是一个计数器而已。可以配置为每秒加一,然后软件将秒数转换为日历时间(类似于unix中,以1970-1-1为起点的秒计数)。6 E4 W2 g7 f- I$ L2 y- s' ?) s5 E# Z
6 w* O7 X  D5 E& |$ x

" S& H/ g' P2 }# E0 f现在不需要时钟了,就把它用于一个10KHz的计数器。最大可计时长为4G/10K = 400K秒,约为100多个小时。
' ]% P) r" h# U5 q+ @4 d/ M
# x& X1 \0 a' Y/ t% a

* W5 R3 p7 \8 \RTC的时钟源:使用内部低速时钟LSI。然后再4分频,即可得到10KHz。
! H0 L- Y2 t- ^5 [6 b. s* J 1.png
$ E$ e* V' {# V, V. V( x% F/ f* t  }. f' Z' f

! O# t  G. I& i/ T6 g) r% ?7 R9 j7 l( u3 U  J% @+ O) S% e; J! S

* l) ]  D2 L+ O) C7 H" M: QRTC工作时需要配置以下几个寄存器:6 L& K' Q: W9 E5 [* W! j
使能PWR和BKP模块时钟! q2 R) \# @3 A7 [. m4 T
2.png & [+ G$ O& \( z  `5 J
* [, I* t- @/ T) ^/ F+ [# O

; e) `5 E$ u7 C9 h" A+ t5 {; d) o% KDisable Backup Domain write:
0 }. V4 p6 Q- q6 C 3.png
- M5 [+ p7 _. T' ~' _1 t3 ^8 g, ?! w1 h+ W) i, }- m8 w& U

1 G3 s4 B2 L- ?开启LSI:0 d& x7 ^& ]/ k7 C
4.png
6 _6 l% B4 B4 |1 `( C
) ^! b& O! J! y

6 a+ E0 w/ p2 t. @复位备份域:$ C5 c+ _3 J$ y1 _' r. q8 @' J

7 \# l8 E+ B- p8 C3 G; j- ^" M
- g- j) H7 k7 _4 j
先将BDRST设置为1,再设置为0。否则,不能更改RTCSEL等参数。
9 [( V: ], f& A+ X% O 5.png 4 W+ Z; [. y& n2 H6 t* y; t) k

) n) O8 R7 `' q5 y  N; T
9 Z6 t2 z6 j, T: {. B6 j
参见手册:6.3.9 备份域控制寄存器 (RCC_BDCR)" Y7 ^$ M% r# b" X/ Q' ^2 I! M0 r
) l. p5 z& [, l% \$ Z5 {
) A' T$ L4 t/ [* x- ]" D$ t
注意: 备份域控制寄存器中(RCC_BDCR)的LSEON、LSEBYP、RTCSEL和RTCEN位处于备份域。因此,这些位在复位后处于写保护状态,只有在电源控制寄存器(PWR_CR)中的DBP位置’1’后才能对这些位进行改动。进一步信息请参考5.1节。这些位只能由备份域复位清除(见6.1.3节)。任何内部或外部复位都不会影响这些位。! t  ~2 W$ J0 w7 Q) J% p
6.png : Y" N4 M, v' ~$ k
+ I& t, J7 r1 z+ T
9 y5 D; m* i+ j
RTC时钟选择LSI:8 j2 Q5 g0 z& n
7.png " y8 w  y! j) _0 z/ X

- i, K& y& I0 r% d; p- D: O6 v; f
, z$ y; G8 p9 t
RTC时钟使能:
' I+ `9 P) p) L1 u- R 8.png ! V! Y. q  A5 R) I# W4 s5 A1 ]

1 \% V  Y6 `" o, |: |6 T- A* y3 D) Y
/ ^! O, H' I% S0 c0 a! A" n3 V
设置分频系数:
% q* o( k  _& \% i 9.png + ?- h9 x) c5 {) y

4 ]7 }9 A8 @$ Q/ `
( u; w+ {  ?1 ^" A$ H3 W
4 ]" X  x  x. t2 q* a8 F$ P0 T) ?) S5 w5 p

  q  H, @. f' A 0 G+ }/ Q$ M7 U, f

, b- I' `- @- s! o& ^$ H! t* @/ y

+ ?* \0 @$ x- p代码如下:+ a+ D- e- P* A& [' k! X
  1. <font face="微软雅黑" size="3">: Q. ]1 K2 _8 C
  2. void vConfigureTimerForRunTimeStats(void)
    - ?) d& `5 I. ?# v
  3. {7 X" v; I: _+ e
  4.         // 使能模块时钟
    8 `& Q% ?! _* A+ R* s
  5.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR, ENABLE);
    - R' T& A  D: y* L1 W4 L

  6. 6 y% m$ _/ y/ T, `; @
  7.         // 使能备份区域访问。将PWR.CR.DBP置1.
    ! D, F1 v# S; T  M, T
  8.         PWR_BackupAccessCmd(ENABLE);
    , a% }2 E, A  t2 F4 a8 M" W1 q3 c

  9. - }$ Q- k% w: H- e
  10.         // 复位备份域(Backup Domain)
    : U, N: a9 `7 K! i+ R* @
  11.         BKP_DeInit();
    1 U% X& A8 e" J# t4 j7 h  R$ f

  12. ( f2 u, L$ H% @
  13.         //启动内部低速晶振
    0 H: h) U$ |6 G# ?( \" t4 n
  14.         RCC_LSICmd(ENABLE);: _0 U# H5 @' F% g, ~
  15. ' n' |+ x; Q8 N; t
  16.         //等待外部低速晶振重启
    ! T+ Q( v9 a- |& j: e) j7 w& a3 S
  17.         while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);
    9 \6 e* q) W5 G% r/ N% B, H

  18. * P+ W; {# f* h* z
  19.         RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
    8 {! a9 G4 h- O* @$ k$ D+ _0 g( A, ~0 t
  20. 4 z1 V1 J: O1 N! k
  21.         RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
    3 B$ `2 S5 k. d0 I2 z

  22. 7 S5 }+ Y7 U6 f8 {6 ?
  23.         RTC_WaitForSynchro(); //等待RTC寄存器同步完成
    2 [. N1 `" F( N! J

  24. 0 {/ {4 ]. L! u8 a
  25.         RTC_WaitForLastTask(); //等待最后一次对RTC的寄存器写操作完成
    % ~: ?( d7 O; g' z) h( w
  26. 8 u: k% d! @* i* J( |: _7 R
  27.         RTC_SetPrescaler(4);        // 4分频后为10KHz& A( D, m' i- i1 T$ j
  28. % r5 ?9 T; L% T+ ]$ \1 D7 {! i
  29.         RTC_WaitForLastTask();% c; Y, {0 H5 B3 I, [3 P: m

  30. 0 N9 \. R7 {% x# ^$ s
  31. }& H( F" P" S/ a

  32. : K$ V- D+ H# C9 m
  33. /*-----------------------------------------------------------*/
    # W6 K& r2 m* @3 j( v  J- T, R
  34. ( j% O" C+ J. z
  35. unsigned long ulGetRunTimeCounterValue(void)' K7 l% ?9 b! {& V5 h5 T) u
  36. {5 v5 j0 C% x% [" i) p
  37.         return RTC_GetCounter();
    2 W) {8 [: |. h3 h( z; ^2 U: m3 z! t
  38. }
    6 M. q" g5 Z! F4 L# A$ G/ S9 A
  39. </font>
复制代码
4 r# a. c# F) [/ {0 F6 T
# I! m( t% r, v, l. I: z
收藏 评论0 发布时间:2021-8-13 14:27

举报

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