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

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

[复制链接]
STMCU小助手 发布时间:2021-8-13 14:27
需求背景
# x! f$ F+ a0 M; I在使用FreeRTOS时,如果需要统计每个任务的运行时长及百分比,则需要提供一个计时基准。5 U% v- y0 T6 `3 N4 |

: J* M$ J& O7 h2 }' s1 s1 T" |. R

. N: t  N5 i, w" a5 U5 a分别实现以下2个函数:
& [: h* b5 d, B* ]7 O- ]- v0 d! X! S8 r: W9 H/ A
+ {. b6 x0 N9 @4 C$ O' n
void vConfigureTimerForRunTimeStats( void );    /* Prototype of function that initialises the run time counter. */0 t1 v, m3 o% x
unsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */
2 n9 T% i3 ?: s' T( G1 R" X
. |/ V5 b0 U' ]* P1 a1 }; _. k& t9 j) W& O+ T2 `+ I3 y* W

% P3 g9 X4 k# g% t  M( l/ {前一个函数需用初始化配置计时器;后一个函数用于在任务切换时获取当前计时值。
) R3 g" G! o; D8 S
  v7 w) }9 F1 O9 a( @1 r9 ^

& V8 z; v2 W* T要求计时的频率比tick的频率要高一个数量级。目前tick为1KHz,则计时频率为10K比较合适。
# `% g, d& a' o! f7 M, C0 H" n- f
6 U7 q, L0 }2 y5 p/ C0 p

* r+ r5 |( b, R* _. ^ 8 G+ Q- d) b! A) B
方案分析- e6 |7 c4 G2 q' T' |
方案一:使用硬件定时器TIMx。3 h7 G( y. g$ P+ v  x
  1. <font face="微软雅黑" size="3">
    * K2 u/ t0 T5 u# Y8 h
  2. void vConfigureTimerForRunTimeStats(void)
    2 `4 P5 |7 z3 M# D: G* g, e5 K9 V
  3. {
    . s/ ]' r& x! W. @, b
  4.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;9 n1 C+ e0 r. a

  5. & M1 d$ B- {2 T( U5 K
  6.         // 时钟使能
    % R  M& ]6 Z  U: |$ I
  7.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
    ( A4 l0 \/ F2 Y1 s: e  F5 u" u

  8. $ ^/ v0 @& W  `8 ]
  9.         //定时器TIMx初始化, \+ x* v0 \# ]( V
  10.         TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / 1000000 - 1; //预分频后为1MHz
    5 Y( e2 a) T6 X1 M- ?; {* Z
  11.         TIM_TimeBaseStructure.TIM_Period = configTICK_RATE_HZ * 10 - 1;( ^1 F# `7 T; r- u' R9 ?& n
  12.         TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
      L1 `& u) b/ |9 g9 H( N% P
  13.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;1 l6 B: S/ T. M7 o. o
  14.         TIM_TimeBaseInit(TIMER_FOR_RUN_TIME_STAT, &TIM_TimeBaseStructure);
    % B  q. x, `2 m$ }# W, E% u" `, |
  15. 1 t* a+ ~; B% L; g
  16.         TIM_Cmd(TIM3, ENABLE);; K! c' z! P/ ^) v. Z1 O, h
  17. }
    ( @; M0 j! {5 P. H+ J6 P

  18. 5 N2 N8 D$ R  {- R7 m! N: y+ H
  19. unsigned long ulGetRunTimeCounterValue(void)
    . d# q5 [# O( c9 C* c* G
  20. {
    " _* ?0 ~& b+ D0 ~: X$ ~- P& k  l
  21.         return TIM_GetCounter(TIM3);" C$ l9 r! C- x: l
  22. + S% t. [% _6 I* E# P2 U" \
  23. </font>
复制代码
问题:STM32F103的硬件定时器是16位的。最大计数值为64K,当计数频率为40K时,只需要1秒多一点就溢出了。
" {. X  ~! E/ @; g. E; M: X+ i6 X. b
, t% h" c+ Y% Y6 q. J# G) `
方案二:使用2个硬件定时器级联,组成一个32位计数器4 ^# \1 _4 r8 |9 m8 k
% z) o# @5 @, Y1 O$ e' M1 p
* I5 f  c2 L4 z, U: F: s, c
方案三:使用os的tick
( w5 @  y7 n7 C9 x4 w代码如下。
, }# D. J" {# S$ O
  1. <font face="微软雅黑" size="3">{</font>
复制代码
问题:精度较低。
. N- A; U: E5 f1 a8 f  n8 t; T
. n4 k6 G  l" e& X7 R
5 i, o8 S0 _. Y4 M! x
方案四:使用RTC作为计数器7 I7 d% p8 T, O, L; t
具体如下。# E6 e# N+ [4 V& ~
4 U9 D  h9 M3 z1 p$ O% U
. A, r+ V) n2 [: H
使用RTC作为计数器
) K/ ~* F5 c% o在STM32F103中,RTC的本质并不是一个实时时钟模块,只是一个计数器而已。可以配置为每秒加一,然后软件将秒数转换为日历时间(类似于unix中,以1970-1-1为起点的秒计数)。1 _) F5 }4 @* z, c* H0 w0 i
- @0 e6 u9 h+ |! ?2 O

5 q, B0 p+ A7 {, @现在不需要时钟了,就把它用于一个10KHz的计数器。最大可计时长为4G/10K = 400K秒,约为100多个小时。: k3 G0 y9 i& m5 W' X& U+ s5 L
0 u9 a% C% J: b7 Y* E- q

6 a$ ~) r5 L8 v+ t4 t" ?+ N. t7 LRTC的时钟源:使用内部低速时钟LSI。然后再4分频,即可得到10KHz。: a. K: \4 W! ]$ V/ H
1.png
- ~: E7 T0 v  C" b# n1 |; q: g% `+ p+ m

# p* L3 ]& J" k9 _
3 M% z" T0 g' ^& p- h$ @
9 o. {# L8 n, {7 m9 N
RTC工作时需要配置以下几个寄存器:9 G3 I( g8 [6 z7 Z& t5 q9 {
使能PWR和BKP模块时钟6 b" k( R! B7 A7 `2 `) ]# e' i/ a
2.png ; r4 h# \( f  x' R. R$ @
5 w+ P' x& L. T' ~& _% c: ^0 A
: ~2 p+ H. f0 k* c* t( s: F/ |# m
Disable Backup Domain write:
4 v( S" S! O6 y7 A7 K 3.png
& q& C$ l, ^" e1 P& B/ F: z
8 {( ^1 X9 Y1 N: N9 a  z8 t8 h' S3 O

3 q0 L3 w; X1 O; O4 L/ p4 g  w, ]开启LSI:
2 i( t' d9 P0 D3 W' E' }9 { 4.png
0 Q3 z: R9 f* S9 L- u. |( y
' l$ ?8 A9 S# q/ F6 N- q$ d

6 A  ?! f8 U* G& W8 g复位备份域:' \5 @! F6 U& }) S" M9 _- v

+ M/ P8 V' I$ ^9 o! V& z7 ?

7 d/ u% \9 w/ G先将BDRST设置为1,再设置为0。否则,不能更改RTCSEL等参数。
+ Q% \) R& J! l( b& K 5.png
% N' J' k- o( Z& z8 r
7 g, ?: f; t, b6 ^* g
! I+ O7 ]1 m0 N5 c" H: _
参见手册:6.3.9 备份域控制寄存器 (RCC_BDCR)( S6 d. ^6 O* L* d* B
" ?9 f* r/ J/ p9 N) s' Y
0 x  r. H& T* a8 M
注意: 备份域控制寄存器中(RCC_BDCR)的LSEON、LSEBYP、RTCSEL和RTCEN位处于备份域。因此,这些位在复位后处于写保护状态,只有在电源控制寄存器(PWR_CR)中的DBP位置’1’后才能对这些位进行改动。进一步信息请参考5.1节。这些位只能由备份域复位清除(见6.1.3节)。任何内部或外部复位都不会影响这些位。
% t7 N& ^5 p5 w6 d/ v+ ` 6.png 7 M) |+ j. c1 c4 K
" |& j) Z( h  v9 P
8 \5 f0 ]4 F9 _4 n1 z% H* @
RTC时钟选择LSI:3 c* g3 S3 F* ?; u% \+ @3 d4 E
7.png 4 w7 W' F& ?) D

9 e/ a# b& v$ p! j0 i
  F+ ^( c! R3 Z' D- ?! r; N- e
RTC时钟使能:
0 j0 A3 f. |8 B! H 8.png
$ y% n0 p0 G. Z$ Y" S
& c7 I* v- P5 Q. r5 Z

, @; ^1 P- N+ N设置分频系数:
6 g3 u/ \0 j) N8 j1 r/ |% P 9.png ! M$ m6 T6 p, m( `/ b
$ M- b, p5 f, W, G

# z8 H# O( n' Y' j) B
' K2 L% s# K; z3 V% B6 W& l% C7 y; c- [+ v
5 t/ P! `, F3 ]  M% d

& v1 @( a) J" z! f- Z' l9 n' `0 l' H
* {! N% E2 m2 q) U! D6 i
代码如下:
) `2 l2 I/ H# U7 }, d* z- q3 X
  1. <font face="微软雅黑" size="3">" R3 M: i# ?. X9 p  b) g. q- i$ X
  2. void vConfigureTimerForRunTimeStats(void)
    ; y8 f+ Q1 u' y+ X
  3. {! m$ x  ]5 B0 H' B5 s- {3 ?4 L+ K
  4.         // 使能模块时钟4 q9 }6 Q. `+ p7 {( u6 [7 K/ \
  5.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR, ENABLE);" {3 w  \' E1 x, y4 o

  6. & T/ ?. v3 i* ^9 G: D
  7.         // 使能备份区域访问。将PWR.CR.DBP置1.
    8 h' q  m& [  e/ M  ^; D5 F
  8.         PWR_BackupAccessCmd(ENABLE);2 g8 o/ E! p$ n0 J( l) ^
  9. - x3 I) |' r3 Q- {9 g9 C
  10.         // 复位备份域(Backup Domain)
    ! }$ w, y; k8 P. y: E+ F$ [# b
  11.         BKP_DeInit();* e+ D. H* w& a; _- n

  12. & D' y9 t  i$ t% J- X# x4 h$ j# O
  13.         //启动内部低速晶振1 X  [! r& g  D! E1 |
  14.         RCC_LSICmd(ENABLE);
    2 o) R+ X! w% k* U" c7 ]

  15.   ?; c+ |  r# @8 n. h. F, q
  16.         //等待外部低速晶振重启
    ) L) M; J4 h* _- o) X
  17.         while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);9 h/ ^- L! I3 J& ~" }1 W. K" m

  18. . M. _( {+ Q! f, T% K  e
  19.         RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);1 c% o: L2 s; X) |' y

  20. ' s" S6 j; F, z1 @" C% [9 G, k  z
  21.         RCC_RTCCLKCmd(ENABLE); //使能RTC时钟+ H" f1 Y7 |, v4 p& a
  22. ' F5 ]! D4 k/ Y+ O
  23.         RTC_WaitForSynchro(); //等待RTC寄存器同步完成
    8 u" u) @3 F7 A) N
  24. ! g6 E5 R. `. Q7 X6 m; y- @
  25.         RTC_WaitForLastTask(); //等待最后一次对RTC的寄存器写操作完成  P8 N* k* ]& V2 c( V3 V0 ~4 n

  26. ! i9 S' |! v9 X8 X' i/ d5 \' }
  27.         RTC_SetPrescaler(4);        // 4分频后为10KHz! u5 q4 A* w: {( ^# N9 [

  28. " H$ H. f8 u$ m& T1 I
  29.         RTC_WaitForLastTask();
    * y+ b8 y3 V, m1 V9 }, y
  30. 8 Q& v1 d! J7 x9 c/ H9 b
  31. }
    $ T, y: u6 J4 Y$ h5 J
  32. 3 I, H% {% o8 R
  33. /*-----------------------------------------------------------*/
    $ G  f+ J. ~( {8 p+ N

  34. ' F; ~! D: Q% h6 j$ L
  35. unsigned long ulGetRunTimeCounterValue(void)
    / {9 G& g/ `# c; G
  36. {
    & O6 A! d1 u( x0 x# M1 C
  37.         return RTC_GetCounter();
    1 |( k! s0 X/ J, o  e" ^
  38. }
    5 x! g) f) }0 U' X' f
  39. </font>
复制代码
' |# E/ ^) P$ o$ B
8 i0 R( S: o) S1 M) m
收藏 评论0 发布时间:2021-8-13 14:27

举报

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