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

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

[复制链接]
STMCU小助手 发布时间:2021-8-13 14:27
需求背景
* d1 s, D8 s) G; Z# m在使用FreeRTOS时,如果需要统计每个任务的运行时长及百分比,则需要提供一个计时基准。
4 L! ^; L0 v) ^, B% h$ G! h1 l
7 s6 N( Z% [/ x! B$ K
8 g: Q: Q! t' A- g
分别实现以下2个函数:
7 |$ c1 x  i2 @
3 `1 F& G8 s/ X

; S5 u1 y) r" f6 ]/ fvoid vConfigureTimerForRunTimeStats( void );    /* Prototype of function that initialises the run time counter. */2 r. o& l% Y! O0 z
unsigned long ulGetRunTimeCounterValue( void ); /* Prototype of function that returns run time counter. */
5 j4 e3 J: x& A+ B: x* q. d' n
5 d9 _! L( X% y9 I) t" l
$ y; l7 v( V5 G' `4 L/ G- Q8 W
% u# c; c# J+ C  n4 ]
前一个函数需用初始化配置计时器;后一个函数用于在任务切换时获取当前计时值。! i7 p/ b  c3 u: Z9 e& d  p

5 G0 L  l5 z2 h( T; Z6 e8 M
* Y! h/ X0 L" D! _6 J, p
要求计时的频率比tick的频率要高一个数量级。目前tick为1KHz,则计时频率为10K比较合适。
% b5 Y! u# [: N0 m3 b7 I1 d) g
8 U$ G! C0 _; c: Q# t
7 s( X$ ]& w% Y6 V8 Q
$ s0 X* u, X9 s) D/ x# j
方案分析
: E( S# j5 r! _方案一:使用硬件定时器TIMx。2 e1 x3 z# H# o4 S# X, n. l1 T
  1. <font face="微软雅黑" size="3">9 X9 d$ N& K& d# Q0 Y# X, v. B
  2. void vConfigureTimerForRunTimeStats(void)5 @0 Z( K4 |( C
  3. {$ o3 H( R2 |: U$ g: k) @$ C0 D
  4.         TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    3 P0 t$ i. ]9 S( V/ m/ r
  5. & p+ L9 A8 v0 S7 q/ c* i% ~! t
  6.         // 时钟使能+ r9 Q' {  K1 ^9 j
  7.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);* f' q% E* K9 H" }& B  ^$ G1 S
  8. & z4 e" N# u+ w& w! K
  9.         //定时器TIMx初始化2 V  _3 z0 A+ d
  10.         TIM_TimeBaseStructure.TIM_Prescaler = SystemCoreClock / 1000000 - 1; //预分频后为1MHz1 _$ q& l9 ~9 ^& |2 {! a( r
  11.         TIM_TimeBaseStructure.TIM_Period = configTICK_RATE_HZ * 10 - 1;# C- R" R/ k5 o! }' o( G
  12.         TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    ( ]9 o& X+ A6 q8 t; [8 Q' [+ b
  13.         TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;3 W$ n( |( p" W" v
  14.         TIM_TimeBaseInit(TIMER_FOR_RUN_TIME_STAT, &TIM_TimeBaseStructure);2 E9 P8 U" n  y+ g' k1 `
  15. ; E& Q1 d$ g1 ]* F
  16.         TIM_Cmd(TIM3, ENABLE);
    ' T. ~0 m8 @& t" l' h% ~# Z9 p0 @8 L! `+ L
  17. }9 q  w- ?$ w, R- Q
  18. # a( n1 a6 x. q
  19. unsigned long ulGetRunTimeCounterValue(void)
    2 O1 O$ C' E5 K! a  ?( n
  20. {7 p& U. N/ I- H5 @1 O' A/ F- a
  21.         return TIM_GetCounter(TIM3);4 T6 `0 J( [4 E. s6 F# x

  22. 9 S# `3 x. `* }4 L; x4 K  Q
  23. </font>
复制代码
问题:STM32F103的硬件定时器是16位的。最大计数值为64K,当计数频率为40K时,只需要1秒多一点就溢出了。
9 X3 b$ _* Q1 c5 T% b
2 @. O# ^; P- b- \, }
" k* y! e9 r7 x2 R, P3 r
方案二:使用2个硬件定时器级联,组成一个32位计数器* ^1 w) h5 M$ R4 c
/ ~: w* x. k6 [5 W
) c- J% {3 N/ N6 L! K& T
方案三:使用os的tick
6 o) C2 P7 G8 h; s代码如下。5 r+ L5 ~, c# J7 D) b8 f5 w
  1. <font face="微软雅黑" size="3">{</font>
复制代码
问题:精度较低。
& S2 z0 r& Q' o$ P. f, v
$ W: W9 g# J  t/ g- J# O) `
+ a, ~6 o* l% e7 |6 g& p! G
方案四:使用RTC作为计数器
! C3 M- s4 Z/ X具体如下。. o) v% |/ t% z  H3 i, l
5 I" Q+ a& R- e) K/ I" @
9 F- P* ^! I- \
使用RTC作为计数器
, n1 i6 B8 @7 e% p, v在STM32F103中,RTC的本质并不是一个实时时钟模块,只是一个计数器而已。可以配置为每秒加一,然后软件将秒数转换为日历时间(类似于unix中,以1970-1-1为起点的秒计数)。) o; a! y: f3 n4 Y. S) W& ?
( f* j# _& m9 `: ]

) n# p2 ]7 R7 A( G9 \现在不需要时钟了,就把它用于一个10KHz的计数器。最大可计时长为4G/10K = 400K秒,约为100多个小时。( j) P2 t9 ^5 ]9 \7 I; [4 C+ }

0 b+ O* E: V0 E5 T6 w

2 I- ]  o4 J7 j# R- |RTC的时钟源:使用内部低速时钟LSI。然后再4分频,即可得到10KHz。, t% ]3 z. Q8 @
1.png
# s( L) T7 y) {( S: V1 v! y8 U" c

5 P  R9 P! Z+ b0 \9 ~0 I& U$ c8 g& \  _6 f
3 [% `: d/ I) M/ `4 u6 t4 X" h
RTC工作时需要配置以下几个寄存器:! q* j$ T% I2 s% E, X9 z9 E# H
使能PWR和BKP模块时钟
( m: }+ A2 o+ ]% n# b 2.png
4 t0 G, x. I' ]+ d3 @/ k2 Y6 b5 r% |; @) z

3 z8 T, t+ @2 ^% EDisable Backup Domain write:
0 D2 y  K% T1 @' q  D3 k( t9 Q& N 3.png
2 d% C+ c! \/ k$ {3 ~8 u% d$ o) s+ y
- j2 b! ]/ Q/ |4 W, U
开启LSI:
, J; B, X: B! {/ G 4.png
2 L% L9 Q  \9 N6 _5 a4 b* X+ a! z2 \6 r6 v! ^& T

7 d2 r+ f0 V6 X& l$ |复位备份域:1 Q4 Z6 Y3 P* A) l; C$ S

! W, @# v0 O. Z& z6 Z' m5 D

" i( x: w9 V. T1 J4 O' ^, P先将BDRST设置为1,再设置为0。否则,不能更改RTCSEL等参数。* z$ {+ c& _1 C& v
5.png   ^/ L  q! d' G' x' \1 E
4 m- m; E3 F0 W. I
8 h/ U% u9 E; O. b) Z7 u
参见手册:6.3.9 备份域控制寄存器 (RCC_BDCR)5 A/ O- s) z9 n" _7 y
9 D3 n0 P, M8 ]: q% x

* e* k, F( V: ?8 B2 x1 A; P注意: 备份域控制寄存器中(RCC_BDCR)的LSEON、LSEBYP、RTCSEL和RTCEN位处于备份域。因此,这些位在复位后处于写保护状态,只有在电源控制寄存器(PWR_CR)中的DBP位置’1’后才能对这些位进行改动。进一步信息请参考5.1节。这些位只能由备份域复位清除(见6.1.3节)。任何内部或外部复位都不会影响这些位。: k7 s& A6 a1 |9 l6 Q9 F' J. S6 x+ K
6.png
. |# a, N3 Z% W: X: W. k& x3 v
1 F2 @6 ~# B8 c! T) e) |( C
+ Y, P% h( ~9 L
RTC时钟选择LSI:
. J5 F" v( v8 b2 g' H6 k% ` 7.png
5 b! c! v" G3 b& U. ?2 t7 I4 ]& B& E5 k* f$ i( F/ V
( _( x, E4 e/ C  g3 D
RTC时钟使能:
3 P) a( I2 d: |$ W 8.png
0 u3 F- b! u! ?& c; u8 C! r9 e& F4 W
5 I3 r4 |, [; y5 l
设置分频系数:
+ e8 ^$ P3 H" h, D8 r2 @) c- Y 9.png : o; S- x- Y- `/ a' W5 U% D

! `/ r; W/ g, \' L  _% ^- V( o
2 z/ X- W- R! ]2 h
7 u7 r/ S7 Y, J8 W) }2 {
- u2 {# {- y& E

) M3 X; w4 {1 Y* {# U1 s; d2 M; F1 _* \" J2 P6 U- Q0 T3 R

6 ~- }8 f! F9 j代码如下:- Q7 ]0 c: g* B4 N  B( u: V, T7 H
  1. <font face="微软雅黑" size="3">
    % A! }, \' L2 V0 J% P1 F
  2. void vConfigureTimerForRunTimeStats(void)- d4 Q$ X4 k  }4 O- ^8 [2 _% ^
  3. {: h+ U( o, v1 C# r0 E( E
  4.         // 使能模块时钟
    ; ]$ L% U& R3 X0 F( Z
  5.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP | RCC_APB1Periph_PWR, ENABLE);$ J3 f. t3 s6 r0 r: G+ J+ R
  6. 7 o, X9 B! s3 O' C- H
  7.         // 使能备份区域访问。将PWR.CR.DBP置1.  e) \) \5 I& H  v
  8.         PWR_BackupAccessCmd(ENABLE);' b, V9 Y! F5 J

  9. & h/ g# x5 w0 E3 s5 _& f
  10.         // 复位备份域(Backup Domain)
    " w+ p- Z, g( w; j4 s
  11.         BKP_DeInit();
    0 w+ b" M/ r; \6 S4 ~/ p
  12. / x) E: p" q8 X+ C' m% k! s/ |
  13.         //启动内部低速晶振
    & c: S8 w" V% m2 D& ^
  14.         RCC_LSICmd(ENABLE);
    ' t0 I8 P9 k! U3 g, g

  15. # h/ z3 D4 e* s: g" K) ?
  16.         //等待外部低速晶振重启  ~1 G- }4 w2 o9 \: @8 m1 @
  17.         while (RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);0 \( ?4 p# V, U8 s0 F# O
  18. # Y* }6 o; ~  N( }" C
  19.         RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);
    . ]) n; J: N5 L2 R: }" B
  20. 2 [0 q  U6 L) `, G
  21.         RCC_RTCCLKCmd(ENABLE); //使能RTC时钟
    * v5 r7 E* Q4 u( p' U: K
  22. 4 q5 W* D$ l8 L! r2 h4 \7 |( E! l
  23.         RTC_WaitForSynchro(); //等待RTC寄存器同步完成3 I: ^$ B! [+ p% o

  24. + [6 U1 r5 x% c7 Z2 f
  25.         RTC_WaitForLastTask(); //等待最后一次对RTC的寄存器写操作完成5 ~3 ?" l8 X: I6 g  v' }
  26. $ @* ?" r# t$ O
  27.         RTC_SetPrescaler(4);        // 4分频后为10KHz
    + A: \' N- K3 w2 R5 e$ |7 s
  28. 4 N/ t- V( }7 k6 K* R5 i
  29.         RTC_WaitForLastTask();6 Z) _0 ~* _( H
  30. 7 x& e/ H; R# p- Z# L
  31. }, O' B% k6 @; _9 n5 }) ^# C

  32. # ?8 G' N2 A/ G* t
  33. /*-----------------------------------------------------------*/
    ) E4 ^/ T) s5 i4 g$ G3 ~, p! c$ g

  34. - P0 F. ^. b2 S3 m5 O5 U6 _
  35. unsigned long ulGetRunTimeCounterValue(void)
    ' e8 ]5 A% z6 W2 D  M
  36. {) G$ R9 x3 x9 {1 D+ N8 P
  37.         return RTC_GetCounter();8 a# w/ c2 k2 Y/ q! ]7 J# s% w
  38. }5 C6 Q; j) w+ l7 Z4 ~. j
  39. </font>
复制代码
3 S* u; X) ]1 C  w! P1 D2 [" l
2 x" y6 N9 B0 y; Q
收藏 评论0 发布时间:2021-8-13 14:27

举报

0个回答

所属标签

相似技术帖

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