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

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

[复制链接]
STMCU小助手 发布时间:2021-8-13 14:27
需求背景
7 \+ D  ?  q% \3 i: |4 p; S/ R3 p: ^在使用FreeRTOS时,如果需要统计每个任务的运行时长及百分比,则需要提供一个计时基准。& y: B- R  ?; E4 l2 @6 {
5 |4 U$ a) e! H) {% Z0 K

5 ~( @" i" F4 d9 S% ]分别实现以下2个函数:( P) s$ k  y! y$ H! p
$ E' u: W  ~5 B
# C8 g1 O; s( z6 C3 E
void vConfigureTimerForRunTimeStats( void );    /* Prototype of function that initialises the run time counter. */
1 H+ x" z. \. g: d8 Uunsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */
& h# Y& J  J; h8 T
3 S$ M+ j3 p( _: O5 }3 d- t8 \7 r( Z. P) p" \) n% \
  ^8 @% }: m# ]! m% W
前一个函数需用初始化配置计时器;后一个函数用于在任务切换时获取当前计时值。
  c* T8 `# ^; P0 b3 @; f7 `7 o$ R
8 g$ j! U* n8 F' v  a' L$ M

2 x+ S  _+ Z8 P要求计时的频率比tick的频率要高一个数量级。目前tick为1KHz,则计时频率为10K比较合适。
" k( x7 u6 _$ y, o1 a  T1 {: d) G2 q# S0 e# d5 Y/ Z
& R1 y6 i7 \# @5 j/ s/ w
# `3 \! v8 E' \% _  G% [  j5 Y4 ]
方案分析
, J+ P4 f! j& @( }9 p+ F' q方案一:使用硬件定时器TIMx。/ f) s& E3 K: a1 ^' ~
  1. <font face="微软雅黑" size="3">
    " _2 R# ^4 I( x' e& k: u9 X
  2. void vConfigureTimerForRunTimeStats(void)) K- j; H0 _* K/ t4 f- x
  3. {1 s" L& y& r% C# F
  4.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    - ]6 o2 k% V: n& O# l

  5. ! K& U$ Z- q; k( o1 H* z- Y
  6.         // 时钟使能
    ' P: r% {+ D+ O% e7 m
  7.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);) g# K. F' V9 I3 r
  8. 5 M8 a4 {7 ~5 z' ?( x: }9 j
  9.         //定时器TIMx初始化
      C1 V0 i& S4 L8 x6 ~) w& e* r
  10.         TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / 1000000 - 1; //预分频后为1MHz% f# t/ D4 K* S, v! X
  11.         TIM_TimeBaseStructure.TIM_Period = configTICK_RATE_HZ * 10 - 1;3 f# U7 |" g) w9 f
  12.         TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;9 K: m1 a# j& b7 n
  13.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    & E" x5 c- ~5 M" B: [
  14.         TIM_TimeBaseInit(TIMER_FOR_RUN_TIME_STAT, &TIM_TimeBaseStructure);
      F( e& N1 \3 L5 o1 f
  15. & O( @; k" Y1 i* A( h' Y) H
  16.         TIM_Cmd(TIM3, ENABLE);% \, Y; }4 k4 f: X& ^. C& N
  17. }
    , }" a2 Q- J# m$ {( p- S

  18. 8 \' y, W1 d! b8 l
  19. unsigned long ulGetRunTimeCounterValue(void)
      ?) U/ z  [, B* _
  20. {# w0 P5 l/ m) m' c) e
  21.         return TIM_GetCounter(TIM3);" }% j* ~4 o% P- F+ @/ T* B% Y
  22. }
    # b2 n' N: v2 q( `2 y. v
  23. </font>
复制代码
问题:STM32F103的硬件定时器是16位的。最大计数值为64K,当计数频率为40K时,只需要1秒多一点就溢出了。
5 Q* b  a3 b0 q! d. b5 u
  m0 D/ E  R' s: K3 t$ S  S
+ ?0 y& q9 q5 O; k
方案二:使用2个硬件定时器级联,组成一个32位计数器. }# ]4 t/ N5 `. `& y' b5 C! C

  w. e# J- c& `4 @9 l* l

4 c( c  Q' n! F8 D3 ]( O方案三:使用os的tick- q( O  _7 H0 U/ e
代码如下。
) A$ M3 o) O* r; e" w
  1. <font face="微软雅黑" size="3">{</font>
复制代码
问题:精度较低。
6 \( f2 ]/ G7 t
" ]! _( y7 U9 h4 q

/ ~( _# H( N) g( t方案四:使用RTC作为计数器
" Q+ L5 X: [. n- q) l% s' a9 k' s具体如下。/ Q: ?" ~& f" L

8 o( W+ m) R" `

  X; W' K6 k0 v- |; @使用RTC作为计数器
/ |  V2 I+ }; m在STM32F103中,RTC的本质并不是一个实时时钟模块,只是一个计数器而已。可以配置为每秒加一,然后软件将秒数转换为日历时间(类似于unix中,以1970-1-1为起点的秒计数)。
+ }3 `. ~- E0 i. C% d1 d
+ U6 l0 l# q  b+ P0 f  h

  j" g, `& E2 I& n' Z+ S# R2 M: E7 R现在不需要时钟了,就把它用于一个10KHz的计数器。最大可计时长为4G/10K = 400K秒,约为100多个小时。- u  P" e- l$ c: W; ]
1 U1 a7 ~, O, }8 W' @) u+ p; l6 ]

# R$ \5 [5 ], tRTC的时钟源:使用内部低速时钟LSI。然后再4分频,即可得到10KHz。
, f( m' _# I- ?6 \ 1.png
% \1 Y; A( E7 H& S& d0 j
8 [, O& W' J* Q% q
# ~+ D+ P, `: ~4 x# r; \0 K
2 E6 J, q* l; c1 m: u
, [! u' ~7 R. t. E, F
RTC工作时需要配置以下几个寄存器:
. J3 M0 y- I5 t. E, C, e使能PWR和BKP模块时钟5 E; Z, O) \( i. F6 F
2.png 4 `. M! a3 T1 ^: n- _2 ^/ J4 c

! G6 L7 U8 h) d

7 v- n/ u9 I9 Y2 h7 a# iDisable Backup Domain write:, x3 a; t0 `" I- N
3.png ) b- w- w: x: u1 n) T8 {: S
* Z7 C. s0 h! m, Y

7 ]* [: `3 Q- N, m- K开启LSI:
3 P. h7 \7 b+ d: Q( \! T0 h, G 4.png
3 B! f, l0 B( N0 Z4 S% v3 `' ]8 B5 C  d, C2 u  X1 e+ m; x
# U2 E9 [, c: ]
复位备份域:% \& Q' ]" Q5 l7 x

* K+ ~/ i+ s& G5 L; p  C( }" M7 Q
- Q+ p7 V3 B6 t: X, R4 C$ r
先将BDRST设置为1,再设置为0。否则,不能更改RTCSEL等参数。5 q! `6 z6 H! x& `! ]$ y8 E
5.png 4 l! W$ e+ d) K+ ~( V/ C5 _: n' ?
7 L7 L0 e, x* h2 V  E

" I& }* d7 N5 o" a参见手册:6.3.9 备份域控制寄存器 (RCC_BDCR)
7 q/ |  T' m- ~( y0 C$ P1 U$ K3 L3 h: ~- _+ k
; [* M; a. X6 I9 V4 |
注意: 备份域控制寄存器中(RCC_BDCR)的LSEON、LSEBYP、RTCSEL和RTCEN位处于备份域。因此,这些位在复位后处于写保护状态,只有在电源控制寄存器(PWR_CR)中的DBP位置’1’后才能对这些位进行改动。进一步信息请参考5.1节。这些位只能由备份域复位清除(见6.1.3节)。任何内部或外部复位都不会影响这些位。% m8 @7 x1 h% A1 p. Z
6.png " Q# _, C9 A1 t& n5 Q& p3 g

9 S9 M7 r: F5 Z- e5 x7 w

' s% f8 k, v1 W9 d$ nRTC时钟选择LSI:  Z9 g* I1 [, p0 c7 r$ @$ V
7.png
: \: @4 g% w0 X
8 X0 v+ x2 ~4 ]6 m" G; A3 }

0 k3 D! S$ S  j( V2 G2 l" ZRTC时钟使能:
; d# f1 b" h6 {6 r2 | 8.png ; c( H, o- ]- L( K) W9 t# i$ J0 f

1 u9 S6 W  z0 w6 Q
5 `* n1 ?5 h. Y8 b4 G5 ^1 x
设置分频系数:
- @: e* b/ x/ |. }; {* [* Q' }9 M 9.png
% N) i1 B4 H& N' j5 x- @! d
5 g. G' {$ A* R/ ?1 a
: x) ^. ]* ^; r$ H& {

' o1 ^, ]! p+ h) y

* D$ |! R: t8 B) d3 k1 j! y4 [! k1 u & K0 s7 D: r' w9 c/ n- n: t
$ s1 C- |5 g' d, D
, J! K  [# y3 h- D1 Q6 ]0 z5 p5 h
代码如下:
$ R; o8 l, n7 y" \  U# Y
  1. <font face="微软雅黑" size="3">
    4 ~; I. c8 K* N* a, k! B7 {
  2. void vConfigureTimerForRunTimeStats(void)6 ^6 o9 L& p' M6 u
  3. {
    7 Z+ i4 ^+ z" }- o: w  n. ^
  4.         // 使能模块时钟' K) i+ t4 X$ Y. d& o- _; O
  5.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR, ENABLE);, e/ H+ V& W) A& d3 Z* |( {: p
  6. 3 s: M7 v' P+ J1 c
  7.         // 使能备份区域访问。将PWR.CR.DBP置1.1 V8 U7 W4 h) I
  8.         PWR_BackupAccessCmd(ENABLE);
    ( F% ?# O8 ?, ]* P0 W! P

  9. ( f, s' |4 M/ Z8 p# s% k8 ~1 M
  10.         // 复位备份域(Backup Domain)/ O# X9 y4 _2 }8 T5 S
  11.         BKP_DeInit();
    + J8 P4 \3 z' I, V6 c( Z

  12. ' J% I% n# k/ q! [0 R& @
  13.         //启动内部低速晶振
    , c  A. a  j! A7 k
  14.         RCC_LSICmd(ENABLE);+ K' I0 R- Z( }3 y. |% Q/ W
  15. - Y- @2 U! |  C8 H/ }  X
  16.         //等待外部低速晶振重启
    ' [, ?" K) m2 I
  17.         while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);) B: H- Y' B; p6 h

  18. 2 q: J* _" L" F% P# l+ ]; T$ f& D- ]1 S
  19.         RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
    ( g: i- g9 a4 p$ M) y
  20. 2 j, |! s1 R. C( t% s
  21.         RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
    - t& Y# _+ Z  y% ^  s+ _

  22.   k' X& Q1 x' @1 J; Q" Z
  23.         RTC_WaitForSynchro(); //等待RTC寄存器同步完成
    8 p2 r! m; h3 d- E: P# J+ K  v

  24.   w- e5 t; J, k$ \
  25.         RTC_WaitForLastTask(); //等待最后一次对RTC的寄存器写操作完成
    8 ^' E- ~8 `. Y* d6 J* u8 y
  26. 9 v; T) F5 g; O9 N+ y0 K' l% x  F
  27.         RTC_SetPrescaler(4);        // 4分频后为10KHz
    + Z/ M6 d5 C# U$ f/ w
  28. " P% g2 t: v4 w& t. A0 S
  29.         RTC_WaitForLastTask();" S2 V" a  f$ b& V  |

  30. , }# v! a1 p6 w9 g4 d+ r: C6 g
  31. }
    / |3 D0 r4 s# u$ N5 t
  32. 9 `8 K) h2 a9 ~. a
  33. /*-----------------------------------------------------------*/
    % e% L$ o7 K) K6 ?$ R' E) ~7 U
  34. # N8 F& m5 l) H9 S; N- H$ X
  35. unsigned long ulGetRunTimeCounterValue(void)4 i+ t: |: m; D2 S% w
  36. {
    # O( c" B( H! u6 N0 P' M
  37.         return RTC_GetCounter();5 t' T5 E) s: ?, m# J; G. _" I
  38. }
    # k! @: k; F- a# G
  39. </font>
复制代码

, `2 u+ }/ s1 ^" q- X1 d- \2 V! p; T% E. ^% `- o+ |
赞 收藏 评论0 发布时间:2021-8-13 14:27

举报

0个回答

所属标签

相似技术帖

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