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

固件库函数FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)源码分析

[复制链接]
吐息间丶时光中 发布时间:2017-2-19 00:08
【前言】本帖只贴出了函数所需的部分源码,所贴源码并不完整!: [) }4 a4 G2 a/ l" B0 Y

* L# j) A% S7 ^1 g1 C固件库提供的 “检查指定RCC标志位设置与否” 的函数在源文件 “stm32f10x_rcc.c” 里的原型如下:
' p, B1 g& y" t& L& p0 c
  1. /**! ?) [- j: S7 W' W5 i9 I: M) o& R
  2.   * @brief  Checks whether the specified RCC flag is set or not.: X: E+ t9 c! `( w% w5 i* q0 @  n
  3.   * @param  RCC_FLAG: specifies the flag to check.9 R% [0 k4 j  G: }; b& [0 ]8 D( C
  4.   *
      S9 ~! z1 _* D7 B4 Q4 j
  5.   *   For @b other_STM32_devices, this parameter can be one of the following values:        
    4 y7 P3 D) m1 h) q4 q$ K# K/ p: M
  6.   *     @arg RCC_FLAG_HSIRDY: HSI oscillator clock ready
    & \  T$ o) e7 d6 T# N( p! F
  7.   *     @arg RCC_FLAG_HSERDY: HSE oscillator clock ready
    6 u0 E# ?, I+ P
  8.   *     @arg RCC_FLAG_PLLRDY: PLL clock ready
    ) j. N5 @: L9 O8 A% f: q  r
  9.   *     @arg RCC_FLAG_LSERDY: LSE oscillator clock ready
      R; \. i2 J9 X9 y
  10.   *     @arg RCC_FLAG_LSIRDY: LSI oscillator clock ready
    . \7 D3 {8 ]  Z5 Z8 r6 l3 n4 [
  11.   *     @arg RCC_FLAG_PINRST: Pin reset( Z$ L: L$ {- ]0 w  ^# `
  12.   *     @arg RCC_FLAG_PORRST: POR/PDR reset
    - u" R5 y1 h$ V3 ^/ ~; O" V
  13.   *     @arg RCC_FLAG_SFTRST: Software reset3 J: I% Y& G/ v- k
  14.   *     @arg RCC_FLAG_IWDGRST: Independent Watchdog reset# A! Z) J$ @6 u) I: o( \; U5 C' T
  15.   *     @arg RCC_FLAG_WWDGRST: Window Watchdog reset" f$ H# x+ E5 @' \7 p$ q) s3 i) p
  16.   *     @arg RCC_FLAG_LPWRRST: Low Power reset
    ! q$ K5 z0 p2 ?. s* m$ y4 ^
  17.   *   $ f! O+ k/ @7 R2 H9 R: ]* k7 y
  18.   * @retval The new state of RCC_FLAG (SET or RESET).
    ' i- N: G* g6 z, I8 k
  19.   */% v  D( G) d, Q  V0 m
  20. FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)5 _: L0 Y* Z" @
  21. {* e# O3 O: b( b9 n
  22.   uint32_t tmp = 0;/ h0 t( |$ \6 G9 g5 B, ~
  23.   uint32_t statusreg = 0;
    & p; a4 F! s9 W7 H
  24.   FlagStatus bitstatus = RESET;
      ?4 p1 U: [+ y. X7 ?% V' h
  25.   /* Check the parameters */6 Z2 x9 z0 ~" q
  26.   assert_param(IS_RCC_FLAG(RCC_FLAG));, ?" u; [6 d5 c

  27. ) t& U! I, O9 @( c+ M
  28.   /* Get the RCC register index */
    & R, P4 O7 x% d: g
  29.   tmp = RCC_FLAG >> 5;$ {/ S% X" t* Y' }1 ~6 u. N' ?
  30.   if (tmp == 1)               /* The flag to check is in CR register */
    / k8 @5 x) A# a
  31.   {) Q6 X6 ^8 F4 B3 L' J, a0 Z) S1 y
  32.     statusreg = RCC->CR;
    " l$ p- l. T4 R! g; h' J& D
  33.   }
    3 f- D' ~- F8 ^. B& P2 f
  34.   else if (tmp == 2)          /* The flag to check is in BDCR register */
    * S9 f6 F3 Q3 ^+ v8 }8 g" }2 \
  35.   {
    ( u: q& J) p- i. ?9 K( D
  36.     statusreg = RCC->BDCR;6 x4 r6 G* u1 F: a9 q
  37.   }- _5 D% S' z5 H. S+ i/ ^% P
  38.   else                       /* The flag to check is in CSR register */% J- m0 X1 Y* Q6 V: Y$ p3 v) a# Q
  39.   {+ y/ A2 O( D5 ?, O$ t2 W! O
  40.     statusreg = RCC->CSR;
    6 G8 S  d, L3 l" l+ X; a- O
  41.   }7 x: P* R8 x3 ]( T9 ]( I5 Q
  42. ; S; P) O1 S8 G) |
  43.   /* Get the flag position */, x) w2 U" u3 a
  44.   tmp = RCC_FLAG & FLAG_Mask;: e. @6 B+ y( @( G; r5 S
  45.   if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET)
    1 ^+ N7 F. v% C6 P) b
  46.   {
    ! @/ W, ]# d7 C# g
  47.     bitstatus = SET;
    1 M4 ], ]  X5 E
  48.   }
    & \  m2 g/ V( q/ \7 }. v
  49.   else
    # e( I# ?6 t. t/ |; e
  50.   {! E' U5 I! i( I4 Q5 c
  51.     bitstatus = RESET;
    ; S, _' C6 }, H3 t
  52.   }& e) h3 t; g' t" Z

  53.   M" F  R" q! I) j
  54.   /* Return the flag status */
    2 o$ y( W( C$ G* \% x
  55.   return bitstatus;3 D& H  ^$ s% O$ z
  56. }
复制代码
较部分固件库函数,其中多了以下部分——获取RCC寄存器索引,从而得到指定标志所在的位置:7 X1 v& x0 Z9 ?5 X& p* D. ~9 ]
  1. /* Get the RCC register index */+ J/ Y0 e0 T! ~5 |) p4 @
  2.   tmp = RCC_FLAG >> 5;. M% o4 L2 @1 A7 _& h: G
  3.   if (tmp == 1)               /* The flag to check is in CR register */% y- f% E# k2 ~9 u6 o4 Q$ [
  4.   {
    0 b  A$ k! F- Q' O1 A- o
  5.     statusreg = RCC->CR;
    0 ?" u' s3 G' [; M8 A
  6.   }
    * w5 F$ K8 y- w: v
  7.   else if (tmp == 2)          /* The flag to check is in BDCR register */2 S) N* M9 H6 w* j
  8.   {% }" `6 @) w$ a# F$ h0 Y
  9.     statusreg = RCC->BDCR;
    3 c. `2 k* X# y6 X6 t9 E
  10.   }" c( {# E, |- u
  11.   else                       /* The flag to check is in CSR register */
    * X% P! {- I$ G: I3 g$ N
  12.   {
    5 c. g; `  b8 N. R% X" ^" |  f  `
  13.     statusreg = RCC->CSR;
    - K) \6 r; \# R1 u0 h  Z) D
  14.   }
    / e4 `1 Y' H8 m$ Q+ F5 C! p9 n

  15. , R$ l( j+ k8 x. b# u  {
  16.   /* Get the flag position */6 N) L, u$ M/ J1 D1 V
  17.   tmp = RCC_FLAG & FLAG_Mask;
    1 T! {- D7 O" Y/ |# W
  18.   if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET)
    ; k. B9 O+ y2 s  T" N! g) r/ {
  19.   {  R+ m6 f* f" E0 [
  20.     bitstatus = SET;& j4 R$ Q" ]% [1 ^' Y) o7 K
  21.   }& D) a' n- B! p0 l- U1 V
  22.   else
    ; O, F" R, c# L2 S8 c( J5 f
  23.   {+ w! U- g1 j* @) \6 j9 T) u
  24.     bitstatus = RESET;
    1 ~8 o; }, ]3 ]
  25.   }
复制代码
而在 “stm32f10x_rcc.h” 里对各标志位进行了如下宏定义:
0 O: e* X( g$ \- j7 d3 o
  1. #define RCC_FLAG_HSIRDY                  ((uint8_t)0x21)
    - `  W2 q5 u9 s' s
  2. #define RCC_FLAG_HSERDY                  ((uint8_t)0x31)
    1 |: @! q4 r0 J: v! A* j
  3. #define RCC_FLAG_PLLRDY                  ((uint8_t)0x39)
    5 N! V: k+ e# r4 a' S
  4. #define RCC_FLAG_LSERDY                  ((uint8_t)0x41)
    : d" g& `" A1 [" b* @" Q. x
  5. #define RCC_FLAG_LSIRDY                  ((uint8_t)0x61)' S' i% A. B3 \5 O3 P
  6. #define RCC_FLAG_PINRST                  ((uint8_t)0x7A)
    / Y4 W! o& ^2 M! L( V8 P
  7. #define RCC_FLAG_PORRST                  ((uint8_t)0x7B); w" S& h/ z* f! r4 E( @
  8. #define RCC_FLAG_SFTRST                  ((uint8_t)0x7C)+ T% q" K: r; j; \! C9 y7 G
  9. #define RCC_FLAG_IWDGRST                 ((uint8_t)0x7D)
    4 X% c; E! ^% k
  10. #define RCC_FLAG_WWDGRST                 ((uint8_t)0x7E)1 o( h- R. B9 m6 {* l9 l) t
  11. #define RCC_FLAG_LPWRRST                 ((uint8_t)0x7F)
复制代码
研究过库函数的贴友想必注意到过:以上宏定义形式没有以下直接与寄存器32个位相对应的形式容易理解:
5 B- F: v8 |# G( x3 z& `; o
  1. #define RCC_SYSCLKSource_HSI             ((uint32_t)0x00000000)
    7 N% d) E, R: K* s- q6 M
  2. #define RCC_SYSCLKSource_HSE             ((uint32_t)0x00000001)
    8 g. y, b) e. H! l+ t& ^
  3. #define RCC_SYSCLKSource_PLLCLK          ((uint32_t)0x00000002)
    * ?: O; S9 S0 k
复制代码

% x% ^' s# _8 e/ @' M7 n那么,那8位的数据是怎么来的呢?
2 B! M3 |% [% T$ ^  w. c
' p# _# T0 C; @( n; r: t
其实,也并没有太大的区别。( K& C  G* P& z2 ^  D6 o" t

6 a8 M" U& I3 R9 O( T4 o
首先,
获取RCC寄存器索引这一步容易理解——那11个标志并不在同一个寄存器里,而是在三个不同寄存器里。语句“RCC_FLAG >> 5” 将宏定义给标志变量的数据左移五位(即数据的低五位被移除)后赋值给变量tmp,所以这里暂时不考虑数据的低五位。, F; S6 A! I$ |- c0 f
  1. /* Get the RCC register index */
    - D1 `5 g/ R3 D4 ~: W" M
  2.   tmp = RCC_FLAG >> 5;
    4 n6 }  r& n' @
  3.   if (tmp == 1)               /* The flag to check is in CR register */8 w5 {9 S$ v. H! U! @' @3 q6 \
  4.   {4 u9 [4 [( d0 b0 P( O- ~' h* A
  5.     statusreg = RCC->CR;8 H. X6 s/ \: |; ~  [
  6.   }; F, G4 t9 o- s% N
  7.   else if (tmp == 2)          /* The flag to check is in BDCR register */4 Q: H8 I- t, C
  8.   {
    / w5 U" R, {( e3 p) Q
  9.     statusreg = RCC->BDCR;1 D9 I7 _( d# s# B# H6 e# f# i! w) j
  10.   }8 [* b$ U# _+ z- [5 r* f
  11.   else                       /* The flag to check is in CSR register */: i0 L0 w. h+ N9 C: w
  12.   {
    8 ^. _5 g3 [% D( {- L0 d" V, o
  13.     statusreg = RCC->CSR;6 ^" h9 w$ b: j7 v
  14.   }
复制代码
因为11个标志分布在三个寄存器里,所以以上代码中有三种判断结果,因此要保证在同一寄存器的标志对应的标志变量的数据的高三位要相同(如下所示),而具体数值则要结合寄存器个数和函数来考量。
3 X" U5 g5 n9 X+ a" h! n1 w
                               标志变量                     数据高三位- M* T+ V8 k' y& s, E
                        RCC_FLAG_HSIRDY                 001* w; w" D" N9 ^' E: b! O$ q
                        RCC_FLAG_HSERDY                001( J2 N9 _& x. _5 w* y$ T- g1 f5 w/ j/ H
                        RCC_FLAG_PLLRDY                 0018 c+ _/ ]2 ?% G. \
                        RCC_FLAG_LSERDY                 010
0 d- L9 H8 }0 B2 f/ Z6 Z6 W
                        RCC_FLAG_LSIRDY                 011
7 U! e8 r& u* H8 k5 M; b. |
                        RCC_FLAG_PINRST                 011
* f, ^! O* P$ b1 y, R' u! {
                        RCC_FLAG_PORRST                011
5 n0 B) V- C8 z& n$ v& j0 V* F
                        RCC_FLAG_SFTRST                 011
5 {( F8 v4 }2 G/ m2 ]" R( z" ^$ l
                        RCC_FLAG_IWDGRST              011: Z% C5 n) }9 T0 ~, O( q$ T
                        RCC_FLAG_WWDGRST             011. J) l7 F9 k( ?& u$ v
                        RCC_FLAG_LPWRRST               011
) E' [$ Y  @: @; R
* `+ m. C+ w% Z- @( U其次,
得到指定标志在所在寄存器的具体位置:
- r' `4 o$ b- r/ Z% z& V
  1. #define FLAG_Mask                 ((uint8_t)0x1F)
复制代码
  1. /* Get the flag position */7 @, s* D& n, V1 Q- J4 A* _/ M+ M
  2.   tmp = RCC_FLAG & FLAG_Mask;
    + U5 a# N6 j$ M4 E% o7 `  U( k% i' N
  3.   if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET)& z7 N, L9 g; p3 h# d
  4.   {6 D+ t' ~, K1 k( s' _9 \
  5.     bitstatus = SET;
    0 b# @. B: r) C) k0 [+ M% J
  6.   }+ k8 G4 B2 X: f
  7.   else
    1 e0 H! O6 v- Y5 X% Q5 r& _% L
  8.   {( r% M4 b' e: h6 l- o. N
  9.     bitstatus = RESET;
    6 K6 W- F3 Z' M* {$ ?; c6 K5 S
  10.   }
复制代码
似乎可以像如下这样理解:
+ t8 R5 h+ f" \: K* a3 M6 r# g
  1. /****** 数据<font color="Red">低五位</font>表示<b><font color="Red">该标志位在所在寄存器的第几位</font></b>。 ******/
    ) l) F7 y0 z6 l% G2 x
  2. /****** 将前面宏定义备注上二进制数据如下 ******/5 ?& s* U/ s! ]/ P
  3. #define RCC_FLAG_HSIRDY                  ((uint8_t)0x21)         // 001 00001        (低五位值:1)& V  C2 L8 z* x5 ]+ M
  4. #define RCC_FLAG_HSERDY                  ((uint8_t)0x31)         // 001 10001        (低五位值:17)
    + S+ R4 X& }8 j6 ~0 ]+ f2 I( l
  5. #define RCC_FLAG_PLLRDY                  ((uint8_t)0x39)         // 001 11001        (低五位值:25)
    9 Q7 I* |6 S" _  m3 H+ l
  6. #define RCC_FLAG_LSERDY                  ((uint8_t)0x41)         // 010 00001        (低五位值:1)- v3 E& S$ l, y7 m* \
  7. #define RCC_FLAG_LSIRDY                  ((uint8_t)0x61)         // 011 00001        (低五位值:1)# |! q. y6 h" D) h
  8. #define RCC_FLAG_PINRST                  ((uint8_t)0x7A)         // 011 11010        (低五位值:26)6 F8 ~) Q/ z& i1 Q$ ~& q
  9. #define RCC_FLAG_PORRST                  ((uint8_t)0x7B)         // 011 11011        (低五位值:27). L7 k3 v, L2 N2 h& N# h/ z
  10. #define RCC_FLAG_SFTRST                  ((uint8_t)0x7C)         // 011 11100        (低五位值:28)
    , i, Q% P5 }7 x/ w4 v7 X
  11. #define RCC_FLAG_IWDGRST                 ((uint8_t)0x7D)         // 011 11101        (低五位值:29): ], b/ @# W8 t" y; N# @1 F
  12. #define RCC_FLAG_WWDGRST                 ((uint8_t)0x7E)         // 011 11110        (低五位值:30)- o; @" d/ E4 j: [( ^# Y! G
  13. #define RCC_FLAG_LPWRRST                 ((uint8_t)0x7F)         // 011 11111        (低五位值:31)
复制代码
比如前三个变量所对应的标志分别在RCC_CR寄存器的第1、17、25位。如下图所示:* v, r" n+ t( Y: S

RCC_CR寄存器

RCC_CR寄存器

8 ~. ~. q( A* `( n而第四个变量所对应的标志在RCC_BDCR寄存器的第1位。
7 X$ A/ t% y! O* n, ~( C
3 E* k3 ^; [2 j8 }) {/ q8 i后七个
变量所对应的标志分别在RCC_CSR寄存器的第1、26~31位。2 m) e* l/ D. B

8 J, j/ j+ [$ C: W9 A
这样,执行以下语句即可判断指定位的状态。
" J5 \$ D% _& ~: G; a2 E# ]
  1. tmp = RCC_FLAG & FLAG_Mask;
    - N" A. [6 i7 P2 T% F- Y
  2.   if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET)( c& V5 U+ C( t8 f  N+ H  ~" w/ K& p
  3.   {
    * T& z9 B  b+ S
  4.    
    0 F, `" B1 z' j6 g
  5.   }
复制代码
显而易见,固件库函数之所以采用这种编程思路,目的之一就是为了避免当多个同类型标志不在同一寄存器时程序太繁杂。1 }2 V% h1 a" }; u
# x- M; q. z8 y' \
除了RCC_GetFlagStatus()函数,固件库中还有其它函数也采用了同样的编程思路。; W- I# @8 `: M1 I6 C; v+ ^

1 T8 K% o: e6 Q- Q----------------------------------------------------------------------------------------------------------------------------------------------7 ]0 b7 o$ B7 i6 D5 O- y
32初学者,在各论坛没搜到过类似帖,不知自己是否眼盲(或者太无知,就这么一个问题还发帖),也不知自己所理解的是否正确。) y/ T% A3 r8 s& d
若理解有误,还望广大贴友指正,非常感谢!
/ j& o, D4 |6 t4 L' I% Y+ c
----------------------------------------------------------------------------------------------------------------------------------------------

% Y$ C- h5 m6 C$ u- f, v% e
5 ?2 f7 Q0 o5 C% t& }

评分

参与人数 2 ST金币 +2 收起 理由
wxlzy + 1 赞一个!
P.L.F + 1 很给力!

查看全部评分

赞 收藏 2 评论4 发布时间:2017-2-19 00:08

举报

4个回答
吐息间丶时光中 回答时间:2017-2-19 09:14:23
睡一觉醒来,隐约记得以前看到过类似的编程思路。记忆开始混乱了
zero99 回答时间:2017-2-20 10:28:18
支持以下
吐息间丶时光中 回答时间:2017-2-20 23:20:27
zero99 发表于 2017-2-20 10:28
' _) T" K  x; p" \1 |; K6 q( _支持以下
+ ?' Q1 w# r* |6 n
谢谢欧巴前辈,学习之路还请多多指教。
tinyisxiaoaxiao 回答时间:2018-5-6 10:43:58
精辟,看懂了,设计这种思路的人很厉害,你也很厉害。

所属标签

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