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

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

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

固件库提供的 “检查指定RCC标志位设置与否” 的函数在源文件 “stm32f10x_rcc.c” 里的原型如下:
  1. /**
  2.   * @brief  Checks whether the specified RCC flag is set or not.
  3.   * @param  RCC_FLAG: specifies the flag to check.
  4.   *
  5.   *   For @b other_STM32_devices, this parameter can be one of the following values:        
  6.   *     @arg RCC_FLAG_HSIRDY: HSI oscillator clock ready
  7.   *     @arg RCC_FLAG_HSERDY: HSE oscillator clock ready
  8.   *     @arg RCC_FLAG_PLLRDY: PLL clock ready
  9.   *     @arg RCC_FLAG_LSERDY: LSE oscillator clock ready
  10.   *     @arg RCC_FLAG_LSIRDY: LSI oscillator clock ready
  11.   *     @arg RCC_FLAG_PINRST: Pin reset
  12.   *     @arg RCC_FLAG_PORRST: POR/PDR reset
  13.   *     @arg RCC_FLAG_SFTRST: Software reset
  14.   *     @arg RCC_FLAG_IWDGRST: Independent Watchdog reset
  15.   *     @arg RCC_FLAG_WWDGRST: Window Watchdog reset
  16.   *     @arg RCC_FLAG_LPWRRST: Low Power reset
  17.   *   
  18.   * @retval The new state of RCC_FLAG (SET or RESET).
  19.   */
  20. FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)
  21. {
  22.   uint32_t tmp = 0;
  23.   uint32_t statusreg = 0;
  24.   FlagStatus bitstatus = RESET;
  25.   /* Check the parameters */
  26.   assert_param(IS_RCC_FLAG(RCC_FLAG));

  27.   /* Get the RCC register index */
  28.   tmp = RCC_FLAG >> 5;
  29.   if (tmp == 1)               /* The flag to check is in CR register */
  30.   {
  31.     statusreg = RCC->CR;
  32.   }
  33.   else if (tmp == 2)          /* The flag to check is in BDCR register */
  34.   {
  35.     statusreg = RCC->BDCR;
  36.   }
  37.   else                       /* The flag to check is in CSR register */
  38.   {
  39.     statusreg = RCC->CSR;
  40.   }

  41.   /* Get the flag position */
  42.   tmp = RCC_FLAG & FLAG_Mask;
  43.   if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET)
  44.   {
  45.     bitstatus = SET;
  46.   }
  47.   else
  48.   {
  49.     bitstatus = RESET;
  50.   }

  51.   /* Return the flag status */
  52.   return bitstatus;
  53. }
复制代码
较部分固件库函数,其中多了以下部分——获取RCC寄存器索引,从而得到指定标志所在的位置:
  1. /* Get the RCC register index */
  2.   tmp = RCC_FLAG >> 5;
  3.   if (tmp == 1)               /* The flag to check is in CR register */
  4.   {
  5.     statusreg = RCC->CR;
  6.   }
  7.   else if (tmp == 2)          /* The flag to check is in BDCR register */
  8.   {
  9.     statusreg = RCC->BDCR;
  10.   }
  11.   else                       /* The flag to check is in CSR register */
  12.   {
  13.     statusreg = RCC->CSR;
  14.   }

  15.   /* Get the flag position */
  16.   tmp = RCC_FLAG & FLAG_Mask;
  17.   if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET)
  18.   {
  19.     bitstatus = SET;
  20.   }
  21.   else
  22.   {
  23.     bitstatus = RESET;
  24.   }
复制代码
而在 “stm32f10x_rcc.h” 里对各标志位进行了如下宏定义:
  1. #define RCC_FLAG_HSIRDY                  ((uint8_t)0x21)
  2. #define RCC_FLAG_HSERDY                  ((uint8_t)0x31)
  3. #define RCC_FLAG_PLLRDY                  ((uint8_t)0x39)
  4. #define RCC_FLAG_LSERDY                  ((uint8_t)0x41)
  5. #define RCC_FLAG_LSIRDY                  ((uint8_t)0x61)
  6. #define RCC_FLAG_PINRST                  ((uint8_t)0x7A)
  7. #define RCC_FLAG_PORRST                  ((uint8_t)0x7B)
  8. #define RCC_FLAG_SFTRST                  ((uint8_t)0x7C)
  9. #define RCC_FLAG_IWDGRST                 ((uint8_t)0x7D)
  10. #define RCC_FLAG_WWDGRST                 ((uint8_t)0x7E)
  11. #define RCC_FLAG_LPWRRST                 ((uint8_t)0x7F)
复制代码
研究过库函数的贴友想必注意到过:以上宏定义形式没有以下直接与寄存器32个位相对应的形式容易理解:
  1. #define RCC_SYSCLKSource_HSI             ((uint32_t)0x00000000)
  2. #define RCC_SYSCLKSource_HSE             ((uint32_t)0x00000001)
  3. #define RCC_SYSCLKSource_PLLCLK          ((uint32_t)0x00000002)
复制代码

那么,那8位的数据是怎么来的呢?


其实,也并没有太大的区别。

首先
获取RCC寄存器索引这一步容易理解——那11个标志并不在同一个寄存器里,而是在三个不同寄存器里。语句“RCC_FLAG >> 5” 将宏定义给标志变量的数据左移五位(即数据的低五位被移除)后赋值给变量tmp,所以这里暂时不考虑数据的低五位。
  1. /* Get the RCC register index */
  2.   tmp = RCC_FLAG >> 5;
  3.   if (tmp == 1)               /* The flag to check is in CR register */
  4.   {
  5.     statusreg = RCC->CR;
  6.   }
  7.   else if (tmp == 2)          /* The flag to check is in BDCR register */
  8.   {
  9.     statusreg = RCC->BDCR;
  10.   }
  11.   else                       /* The flag to check is in CSR register */
  12.   {
  13.     statusreg = RCC->CSR;
  14.   }
复制代码
因为11个标志分布在三个寄存器里,所以以上代码中有三种判断结果,因此要保证在同一寄存器的标志对应的标志变量的数据的高三位要相同(如下所示),而具体数值则要结合寄存器个数和函数来考量。
                               标志变量                     数据高三位
                        RCC_FLAG_HSIRDY                 001
                        RCC_FLAG_HSERDY                001
                        RCC_FLAG_PLLRDY                 001
                        RCC_FLAG_LSERDY                 010
                        RCC_FLAG_LSIRDY                 011
                        RCC_FLAG_PINRST                 011
                        RCC_FLAG_PORRST                011
                        RCC_FLAG_SFTRST                 011
                        RCC_FLAG_IWDGRST              011
                        RCC_FLAG_WWDGRST             011
                        RCC_FLAG_LPWRRST               011

其次
得到指定标志在所在寄存器的具体位置:
  1. #define FLAG_Mask                 ((uint8_t)0x1F)
复制代码
  1. /* Get the flag position */
  2.   tmp = RCC_FLAG & FLAG_Mask;
  3.   if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET)
  4.   {
  5.     bitstatus = SET;
  6.   }
  7.   else
  8.   {
  9.     bitstatus = RESET;
  10.   }
复制代码
似乎可以像如下这样理解:
  1. /****** 数据<font color="Red">低五位</font>表示<b><font color="Red">该标志位在所在寄存器的第几位</font></b>。 ******/
  2. /****** 将前面宏定义备注上二进制数据如下 ******/
  3. #define RCC_FLAG_HSIRDY                  ((uint8_t)0x21)         // 001 00001        (低五位值:1)
  4. #define RCC_FLAG_HSERDY                  ((uint8_t)0x31)         // 001 10001        (低五位值:17)
  5. #define RCC_FLAG_PLLRDY                  ((uint8_t)0x39)         // 001 11001        (低五位值:25)
  6. #define RCC_FLAG_LSERDY                  ((uint8_t)0x41)         // 010 00001        (低五位值:1)
  7. #define RCC_FLAG_LSIRDY                  ((uint8_t)0x61)         // 011 00001        (低五位值:1)
  8. #define RCC_FLAG_PINRST                  ((uint8_t)0x7A)         // 011 11010        (低五位值:26)
  9. #define RCC_FLAG_PORRST                  ((uint8_t)0x7B)         // 011 11011        (低五位值:27)
  10. #define RCC_FLAG_SFTRST                  ((uint8_t)0x7C)         // 011 11100        (低五位值:28)
  11. #define RCC_FLAG_IWDGRST                 ((uint8_t)0x7D)         // 011 11101        (低五位值:29)
  12. #define RCC_FLAG_WWDGRST                 ((uint8_t)0x7E)         // 011 11110        (低五位值:30)
  13. #define RCC_FLAG_LPWRRST                 ((uint8_t)0x7F)         // 011 11111        (低五位值:31)
复制代码
比如前三个变量所对应的标志分别在RCC_CR寄存器的第1、17、25位。如下图所示:

RCC_CR寄存器

RCC_CR寄存器

而第四个变量所对应的标志在RCC_BDCR寄存器的第1位

后七个
变量所对应的标志分别在RCC_CSR寄存器的第1、26~31位。

这样,执行以下语句即可判断指定位的状态。
  1. tmp = RCC_FLAG & FLAG_Mask;
  2.   if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET)
  3.   {
  4.    
  5.   }
复制代码
显而易见,固件库函数之所以采用这种编程思路,目的之一就是为了避免当多个同类型标志不在同一寄存器时程序太繁杂。

除了RCC_GetFlagStatus()函数,固件库中还有其它函数也采用了同样的编程思路。

----------------------------------------------------------------------------------------------------------------------------------------------
32初学者,在各论坛没搜到过类似帖,不知自己是否眼盲(或者太无知,就这么一个问题还发帖),也不知自己所理解的是否正确。
若理解有误,还望广大贴友指正,非常感谢!

----------------------------------------------------------------------------------------------------------------------------------------------


评分

参与人数 1 ST金币 +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

谢谢欧巴前辈,学习之路还请多多指教。
tinyisxiaoaxiao 回答时间:2018-5-6 10:43:58
精辟,看懂了,设计这种思路的人很厉害,你也很厉害。

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

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