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

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

[复制链接]
STMCU小助手 发布时间:2021-8-13 14:27
需求背景
5 g4 W8 |1 p* P' N: p5 I在使用FreeRTOS时,如果需要统计每个任务的运行时长及百分比,则需要提供一个计时基准。/ M0 S4 s# J  y
4 K/ H8 C2 `1 U" n0 b
8 G4 w! L0 V$ e
分别实现以下2个函数:" _0 v/ Y8 u( |6 N! g5 h
# m: m& F, c/ X: L2 `" U

# R# d9 [) B. _' e# m0 I6 {void vConfigureTimerForRunTimeStats( void );    /* Prototype of function that initialises the run time counter. */* y$ s  ?  V: {" o* _" ~
unsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */
; X# p/ @% O& d! ~  p! U
1 o3 N( K6 s& B, I6 n. P
4 O9 g5 f. A' d
9 D1 T1 v4 V" B' D) H( K
前一个函数需用初始化配置计时器;后一个函数用于在任务切换时获取当前计时值。+ J( M! w3 O2 J- l
  U2 S: A1 h. {7 X
5 ~' J& X2 L) }) z% n
要求计时的频率比tick的频率要高一个数量级。目前tick为1KHz,则计时频率为10K比较合适。2 @9 ^4 z4 b( b% Y0 c* [/ p+ A
/ _9 M* m8 Q) K( \# u
0 y- {- Q  c3 a; o7 {

% I% v$ L7 x/ P! ]4 ?方案分析
9 w& p( k- `$ Y7 i' p1 y: V方案一:使用硬件定时器TIMx。
" G! Y0 v  t' |: @
  1. <font face="微软雅黑" size="3">, v/ |- g( X1 g) C* k8 V$ @8 R3 ?
  2. void vConfigureTimerForRunTimeStats(void). J" M6 @1 @- M5 ]! U
  3. {/ E$ U& ~+ h/ a, |1 U
  4.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;$ o4 W* R0 B% o4 }+ K, E# E2 S  I

  5. # l, w3 ?, ^" U6 i5 E* ^( [
  6.         // 时钟使能
    2 N4 j+ h3 J1 B
  7.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    2 f& Z4 @9 ~! E9 c9 ?
  8. , _4 B+ g2 M! ^  e# E2 ~" q
  9.         //定时器TIMx初始化0 ^  r* g- w* `+ {9 x+ b
  10.         TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / 1000000 - 1; //预分频后为1MHz# a0 }3 t  J  m% ~
  11.         TIM_TimeBaseStructure.TIM_Period = configTICK_RATE_HZ * 10 - 1;& n* L( d' d& k" V$ u  `
  12.         TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;$ x" m+ G7 m8 R7 E
  13.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    2 S% h' r7 l% h7 u# y
  14.         TIM_TimeBaseInit(TIMER_FOR_RUN_TIME_STAT, &TIM_TimeBaseStructure);
    " t, T9 P+ D( w* `5 S

  15. 0 c; |* ~' f) X, O, k7 R* N
  16.         TIM_Cmd(TIM3, ENABLE);
    0 F# H" h; V: D
  17. }& f$ e, Y/ G2 w0 o! |
  18. 7 Y- p# h  X0 {7 g  W  u* k
  19. unsigned long ulGetRunTimeCounterValue(void)
    6 i3 X  V7 ]9 e% u: o! h. E$ `7 s
  20. {
    + N$ G5 |" p: N
  21.         return TIM_GetCounter(TIM3);
    1 [( Y. i9 w% j" t% Q. G

  22. . j3 a$ t. w9 d6 W
  23. </font>
复制代码
问题:STM32F103的硬件定时器是16位的。最大计数值为64K,当计数频率为40K时,只需要1秒多一点就溢出了。4 J, D+ I4 A( t% I7 [0 G

3 W& k  E  L+ f) B

) t. I0 h1 y8 H4 O3 g) S/ v$ a方案二:使用2个硬件定时器级联,组成一个32位计数器  X4 _8 |5 n! a( J4 H
  y+ f3 \% k7 H% n3 j
) t* m6 ]# z+ c( W0 q2 {
方案三:使用os的tick
6 J: ^/ ~: z5 W6 d代码如下。. r$ b6 a' Q; ]' h/ L4 X. B1 W
  1. <font face="微软雅黑" size="3">{</font>
复制代码
问题:精度较低。
: k2 k* O1 f5 v
5 H7 W2 I: q$ m0 A
9 c) m# ^: D; b  x5 z" U
方案四:使用RTC作为计数器7 ]: {4 [9 B( g3 m; S
具体如下。' \8 {, g: x1 K2 r" n3 E: B
& q  ]2 Q* f& |+ [

; e2 `: C6 g+ \; U- z" ^使用RTC作为计数器
9 z; |6 o$ Q! c9 r在STM32F103中,RTC的本质并不是一个实时时钟模块,只是一个计数器而已。可以配置为每秒加一,然后软件将秒数转换为日历时间(类似于unix中,以1970-1-1为起点的秒计数)。
% o' m5 i# x' F6 C' \
* f5 D2 a% W! T
6 r5 w0 k  W" Y( D2 d! ]
现在不需要时钟了,就把它用于一个10KHz的计数器。最大可计时长为4G/10K = 400K秒,约为100多个小时。
. U/ o2 W# H4 b5 |9 q% g# ~' I6 s6 |; m4 H

& [, E  p: e8 F0 X+ `RTC的时钟源:使用内部低速时钟LSI。然后再4分频,即可得到10KHz。2 E/ Y% c3 A' C( \0 k- A: g+ Q
1.png
8 C% S5 u2 @# _" w0 l; q5 g/ p; J# p

$ r5 X# ?$ T1 O4 d0 H3 I2 Z$ Q) r& |
: [+ x! n2 j, k- D
4 h% I# v& r5 S  ^4 _( L
RTC工作时需要配置以下几个寄存器:9 k$ @3 J  ^# m; ^, i; `' `& X
使能PWR和BKP模块时钟
1 v4 P- O5 P4 F! k9 g$ T) l3 p 2.png
+ f, z- U" v2 c
7 l1 Z- ^2 n) C6 }: j9 W- B5 d

: D9 m  H- h% h, j  A. d, vDisable Backup Domain write:8 y! T, J+ Y" [: G' i1 W; O. l
3.png * \1 o% N" Q# |; I. z+ H

0 D5 v( t- E! K9 f3 \2 d4 P
" \( w% o6 q, b' W/ h% K. ?
开启LSI:
: y9 _3 s0 K6 y) h# a 4.png
8 H3 V- `% o. Z* h  @4 E9 B* X' h! ?; M- H7 q+ {& C: ?

; s, ^) m0 ~; F复位备份域:8 s, `4 J# k! ^. S1 L4 w0 o6 _
3 g; |0 a) T( ~6 Q9 E+ t, X

! ~/ c4 x; x+ @* E0 d1 [, Q先将BDRST设置为1,再设置为0。否则,不能更改RTCSEL等参数。, ~' w7 Y7 R) y
5.png - l: [, z( I/ G7 V+ |& s
4 c5 Q; b; F5 O) |# J3 h

( w; n8 g+ Y# l4 e) k5 U参见手册:6.3.9 备份域控制寄存器 (RCC_BDCR)' e4 _( ]' T* e3 t2 y( C
% ]/ w  d  g: L  k" a: A

7 l0 j$ G" n& r9 m0 y2 [+ @- X* e注意: 备份域控制寄存器中(RCC_BDCR)的LSEON、LSEBYP、RTCSEL和RTCEN位处于备份域。因此,这些位在复位后处于写保护状态,只有在电源控制寄存器(PWR_CR)中的DBP位置’1’后才能对这些位进行改动。进一步信息请参考5.1节。这些位只能由备份域复位清除(见6.1.3节)。任何内部或外部复位都不会影响这些位。. g; r' ?' y9 C* H. s
6.png
2 z- R0 N) U8 [  x5 R
4 O/ C! N. t/ n4 a- Y

4 T" e4 m: U; wRTC时钟选择LSI:
: |5 T& F& V; {' l; v 7.png
& Q, n; Y; T4 l9 W) r6 t* C+ x8 l& K3 m3 o! h: d
& }2 P8 Y: M& ^! S. T$ q
RTC时钟使能:
& K) e5 Q6 P# m& ]' R 8.png $ M% q7 g2 {/ Z  g4 v- K
: f/ ]% @. [. ]

2 }: u+ T' ?/ C4 W6 M; d/ L/ r设置分频系数:
$ M" T/ ?; C1 `$ @. |& Z) w' H 9.png , p+ g8 E' u4 e$ }
7 y/ S& x' w! q7 U0 ?+ v* f1 S

, z& H% _. U9 k7 t
4 p( X" F$ q+ y7 V* ~% z

* |" U' e7 P$ P; N" c 3 B& R8 a" s6 ?' Q* Q2 y! s
7 n1 R* c0 z! h: [

: N# a* {! T1 f$ w6 u1 a+ A代码如下:5 h0 C( d0 ]; W$ K
  1. <font face="微软雅黑" size="3">
    & L7 s9 G6 ?, C+ N' b! R0 q" B5 {
  2. void vConfigureTimerForRunTimeStats(void)
    7 O1 e6 o; x' d" H5 ]
  3. {
    ( U- |8 v) }& G! b# B/ h
  4.         // 使能模块时钟9 I/ I% U* |. I9 R2 Q0 D
  5.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR, ENABLE);6 {- n: |( K9 J  B7 q# u# A" C

  6. 4 i" C" e9 x  `' S
  7.         // 使能备份区域访问。将PWR.CR.DBP置1.* X" t! S+ \) I  F) a3 t
  8.         PWR_BackupAccessCmd(ENABLE);
    ( c9 f; E+ c+ J9 ]! Z; b) K2 K, X( p
  9. - Q  N( L& V4 B2 b+ F$ ?$ p6 L! h
  10.         // 复位备份域(Backup Domain)3 i8 {! J% L4 E% P  O
  11.         BKP_DeInit();
    / T9 c1 S) l( O* }
  12. . A9 t% l0 [7 U* o0 h
  13.         //启动内部低速晶振9 t$ p) P+ N. {6 n& z
  14.         RCC_LSICmd(ENABLE);4 m& X  |% \9 U

  15. 9 y, u, X$ L" H6 f
  16.         //等待外部低速晶振重启
    - U( Y7 B: e2 U5 w* v' |
  17.         while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);7 l. }; O1 G* Z; Z/ e
  18. & I- |+ h0 e( _4 Z& B" l$ t% [
  19.         RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);, d% v6 p4 X% O, y9 F& B! s' z5 \4 C
  20. ! x0 l  x, c$ K2 E
  21.         RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
    ! w* G% ?) l" a! p0 u! J6 L
  22. * X/ X" I# e1 F
  23.         RTC_WaitForSynchro(); //等待RTC寄存器同步完成3 ], A0 P+ _1 w% f4 g

  24. ( l) K' e: D6 J: j/ g3 h
  25.         RTC_WaitForLastTask(); //等待最后一次对RTC的寄存器写操作完成
    ) c5 Z/ z% K8 \; h

  26. ) b6 R" D* E6 o$ L9 A# e" C9 _
  27.         RTC_SetPrescaler(4);        // 4分频后为10KHz
    * d: g  u3 t/ Y! D

  28. : e/ E6 p3 v6 \
  29.         RTC_WaitForLastTask();7 q$ C+ R) d- _6 F, E# y/ m  K
  30. 2 A" f) N, D( p
  31. }8 z6 S7 t+ z$ K- W! a; K  F

  32. ( J3 \2 @( u* k7 _& ?. D
  33. /*-----------------------------------------------------------*/$ O: [7 ]  i: i+ f$ f! ]- Y8 Q

  34.   r% n" k$ ?+ V% q% K; `0 p
  35. unsigned long ulGetRunTimeCounterValue(void)8 H, k1 e" Z" W/ r& Z6 u0 V, h8 O
  36. {/ I4 l5 t* C4 U
  37.         return RTC_GetCounter();6 s( Z2 X. n, X8 e4 e
  38. }
    7 u  ]6 P5 X. }" K, m+ A& [
  39. </font>
复制代码

5 x: T7 M& i: `& }4 r" f" m/ j: r9 K4 I( T% }
收藏 评论0 发布时间:2021-8-13 14:27

举报

0个回答
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版