• 【STM32】RCC时钟模块(使用HAL库)


    https://gitee.com/linhir-linhir/stm32-f103-c8/blob/master/STM32%E6%9C%80%E6%96%B0%E5%9B%BA%E4%BB%B6%E5%BA%93v3.5/Libraries/STM32F10x_StdPeriph_Driver/inc/stm32f10x_rcc.h

    STM32最新固件库v3.5/Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x/system_stm32f10x.c · 林何/STM32F103C8 - 码云 - 开源中国 (gitee.com)

    1.宏定义

    1.宏定义的位置

    如果这个宏定义只能在.c文件中使用,则应该在.c文件中定义

    如果这个宏定义既可以在.c或者.h文件中使用,则应该在.h中定义

    2.位带:RCC_OFFSET

    因为我们STM32是32位的寄存器,所以如果我们只想要操作寄存器其中的一位,所以我们可以使用位移操作

    1. /* ------------ RCC registers bit address in the alias region ----------- */
    2. /*
    3. RCC_OFFSET:等价于RCC的基地址和外设寄存器之差
    4. */
    5. /*!< PERIPH_BAS--》 Peripheral base address in the alias region */
    6. #define RCC_OFFSET (RCC_BASE - PERIPH_BASE)

    3.第一个寄存器:CR

    1.HSION

    1. /* --- CR Register ---*/
    2. /* Alias word address of HSION bit */
    3. //这个寄存器相对于基地址的位置
    4. #define CR_OFFSET (RCC_OFFSET + 0x00)
    5. //操作HSION这一位相对于整个CR寄存器的偏移量
    6. #define HSION_BitNumber 0x00
    7. //CR寄存器中的HSION中的位带
    8. //PERIPH_BB_BASE:位带访问区的基地址
    9. #define CR_HSION_BB (PERIPH_BB_BASE + (CR_OFFSET * 32) + (HSION_BitNumber * 4))

    如果想要对其进行设置,就直接给CR_HSION_BB赋值

    2.PLLON

    1. /* Alias word address of PLLON bit */
    2. #define PLLON_BitNumber 0x18
    3. #define CR_PLLON_BB (PERIPH_BB_BASE + (CR_OFFSET * 32) + (PLLON_BitNumber * 4))

    4.RCC registers bit mask

    Reset:进行位与置0

    Set:进行位或置1

    1. /* ---------------------- RCC registers bit mask ------------------------ */
    2. /* CR register bit mask */
    3. #define CR_HSEBYP_Reset ((uint32_t)0xFFFBFFFF)
    4. #define CR_HSEBYP_Set ((uint32_t)0x00040000)
    5. #define CR_HSEON_Reset ((uint32_t)0xFFFEFFFF)
    6. #define CR_HSEON_Set ((uint32_t)0x00010000)
    7. #define CR_HSITRIM_Mask ((uint32_t)0xFFFFFF07)

    2.全局变量

    定义了预分配处理器

    1.static

    c语言中static关键字用法详解_static在c语言中的用法-CSDN博客

    2.volatile

    这个变量跟某一个寄存器的值进行绑定,寄存器里面有一个值是硬件可以改动的值

    C语言丨深入理解volatile关键字-腾讯云开发者社区-腾讯云 (tencent.com)

    3.uint

    uint8:表示unsigned short

    uint16:表示unsigned char

    uint32:表示unsigned int

    1. static __I uint8_t APBAHBPrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9};
    2. static __I uint8_t ADCPrescTable[4] = {2, 4, 6, 8};

    3.函数

    1.RCC_DeInit

    1. /**
    2. * @brief Resets the RCC clock configuration to the default reset state.
    3. * @param None
    4. * @retval None
    5. */
    6. void RCC_DeInit(void)
    7. {
    8. /* Set HSION bit */
    9. //将CR这个位写为1
    10. RCC->CR |= (uint32_t)0x00000001;
    11. /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
    12. #ifndef STM32F10X_CL
    13. RCC->CFGR &= (uint32_t)0xF8FF0000;
    14. #else//非CL的芯片使用
    15. RCC->CFGR &= (uint32_t)0xF0FF0000;
    16. #endif /* STM32F10X_CL */
    17. /* Reset HSEON, CSSON and PLLON bits */
    18. //HSEON, CSSON and PLLON:将这几位置0
    19. RCC->CR &= (uint32_t)0xFEF6FFFF;
    20. /* Reset HSEBYP bit */
    21. RCC->CR &= (uint32_t)0xFFFBFFFF;
    22. /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
    23. RCC->CFGR &= (uint32_t)0xFF80FFFF;
    24. #ifdef STM32F10X_CL
    25. /* Reset PLL2ON and PLL3ON bits */
    26. RCC->CR &= (uint32_t)0xEBFFFFFF;
    27. /* Disable all interrupts and clear pending bits */
    28. RCC->CIR = 0x00FF0000;
    29. /* Reset CFGR2 register */
    30. RCC->CFGR2 = 0x00000000;
    31. #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
    32. /* Disable all interrupts and clear pending bits */
    33. RCC->CIR = 0x009F0000;
    34. /* Reset CFGR2 register */
    35. RCC->CFGR2 = 0x00000000;
    36. #else
    37. /* Disable all interrupts and clear pending bits */
    38. RCC->CIR = 0x009F0000;
    39. #endif /* STM32F10X_CL */
    40. }

    2.RCC_HSEConfig

    可以关闭时钟,所以平时我们不操纵它

    这个HSEConfig实际效果:控制CPU是使用

                    外部晶振+内部振动电路        VS        外部时钟

    1.assert:断言

    assert机制是c语言用来判断一个东西是对的还是错的,如果是对的直接忽略过去,如果是错的就以某一种方式告诉我们(warrning error)让我们去修改。

    1. /* Exported macro ------------------------------------------------------------*/
    2. #ifdef USE_FULL_ASSERT
    3. /**
    4. * @brief The assert_param macro is used for function's parameters check.
    5. * @param expr: If expr is false, it calls assert_failed function which reports
    6. * the name of the source file and the source line number of the call
    7. * that failed. If expr is true, it returns no value.
    8. * @retval None
    9. */
    10. #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
    11. /* Exported functions ------------------------------------------------------- */
    12. void assert_failed(uint8_t* file, uint32_t line);
    13. #else
    14. #define assert_param(expr) ((void)0)
    15. #endif /* USE_FULL_ASSERT */

    这个函数要用户自己去实现

    1. void assert_failed(uint8_t* file, uint32_t line)
    2. {
    3. /* User can add his own implementation to report the file name and line number,
    4. ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    5. /* Infinite loop */
    6. //用户用自己的方法去报错一个断言错误
    7. //用户可以用#error灯方法来在编译时报错(前提是断言表达式必须在预处理时就能有结果)
    8. //更常见的方式是用户在运行时报错,用printf打印调试信息
    9. //
    10. while (1)
    11. {
    12. }
    13. }

    2.判断用户输入的参数是否正确

    3.代码理解

    1. /**
    2. * @brief Configures the External High Speed oscillator (HSE).
    3. * @note HSE can not be stopped if it is used directly or through the PLL as system clock.
    4. * @param RCC_HSE: specifies the new state of the HSE.
    5. * This parameter can be one of the following values:
    6. * @arg RCC_HSE_OFF: HSE oscillator OFF
    7. * @arg RCC_HSE_ON: HSE oscillator ON
    8. * @arg RCC_HSE_Bypass: HSE oscillator bypassed with external clock
    9. * @retval None
    10. */
    11. void RCC_HSEConfig(uint32_t RCC_HSE)
    12. {
    13. /* Check the parameters */
    14. assert_param(IS_RCC_HSE(RCC_HSE));
    15. /* Reset HSEON and HSEBYP bits before configuring the HSE ------------------*/
    16. /* Reset HSEON bit */
    17. RCC->CR &= CR_HSEON_Reset;
    18. /* Reset HSEBYP bit */
    19. RCC->CR &= CR_HSEBYP_Reset;
    20. /* Configure HSE (RCC_HSE_OFF is already covered by the code section above) */
    21. switch(RCC_HSE)
    22. {
    23. case RCC_HSE_ON:
    24. /* Set HSEON bit */
    25. RCC->CR |= CR_HSEON_Set;
    26. break;
    27. case RCC_HSE_Bypass:
    28. /* Set HSEBYP and HSEON bits */
    29. RCC->CR |= CR_HSEBYP_Set | CR_HSEON_Set;
    30. break;
    31. default://RCC_HSE_OFF
    32. break;
    33. }
    34. }

    3.RCC_WaitForHSEStartUp(等待HSE)

    1.ErrorStatus

    判断是否成功

    一般:0:表示失败

               1:表示成功

    2.计数值加上volatile

    因为这个变量是我们来进行判断是否超时的局部变量,所以每当我们调用这个函数的时候,应该将这个计数值清0,所以这里才使用

    3.代码理解

    1. /**
    2. * @brief Waits for HSE start-up.
    3. * @param None
    4. * @retval An ErrorStatus enumuration value:
    5. * - SUCCESS: HSE oscillator is stable and ready to use
    6. * - ERROR: HSE oscillator not yet ready
    7. */
    8. ErrorStatus RCC_WaitForHSEStartUp(void)
    9. {
    10. __IO uint32_t StartUpCounter = 0;
    11. ErrorStatus status = ERROR;
    12. FlagStatus HSEStatus = RESET;
    13. /* Wait till HSE is ready and if Time out is reached exit */
    14. do
    15. {
    16. //读取寄存器的值
    17. HSEStatus = RCC_GetFlagStatus(RCC_FLAG_HSERDY);
    18. StartUpCounter++; //读取是否超时的
    19. } while((StartUpCounter != HSE_STARTUP_TIMEOUT) && (HSEStatus == RESET));
    20. //这里判断是防止超时
    21. if (RCC_GetFlagStatus(RCC_FLAG_HSERDY) != RESET)
    22. {
    23. status = SUCCESS;
    24. }
    25. else
    26. {
    27. //超时
    28. status = ERROR;
    29. }
    30. return (status);
    31. }

    4.RCC_GetFlagStatus(获取bit位状态)

    1)确定这个RCC-FLAG在哪一个寄存器上

    2)确定这个RCC_FLAG在寄存器是哪一个位上

    1.返回值进行状态判断

    2.输入参数

    3.IS_RCC_FLAG

    4.判断当前是在哪一个寄存器中

    右移5位是想要判断第5位是1还是2还是3,然后进行判断是哪一个寄存器

    1. /* Get the RCC register index */
    2. //将输入的标志位右移5位
    3. tmp = RCC_FLAG >> 5;
    4. //判断要访问哪一个寄存器
    5. if (tmp == 1) /* The flag to check is in CR register */
    6. {
    7. statusreg = RCC->CR;
    8. }
    9. else if (tmp == 2) /* The flag to check is in BDCR register */
    10. {
    11. statusreg = RCC->BDCR;
    12. }
    13. else /* The flag to check is in CSR register */
    14. {
    15. statusreg = RCC->CSR;
    16. }

    5.判断在寄存器的哪一个位上

    1. /* Get the flag position */
    2. /**
    3. FLAG_Mask:0x1f
    4. */
    5. tmp = RCC_FLAG & FLAG_Mask;
    6. if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET)
    7. {
    8. bitstatus = SET;
    9. }
    10. else
    11. {
    12. bitstatus = RESET;
    13. }

    6.代码理解

    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 STM32_Connectivity_line_devices, this parameter can be one of the
    6. * following values:
    7. * @arg RCC_FLAG_HSIRDY: HSI oscillator clock ready
    8. * @arg RCC_FLAG_HSERDY: HSE oscillator clock ready
    9. * @arg RCC_FLAG_PLLRDY: PLL clock ready
    10. * @arg RCC_FLAG_PLL2RDY: PLL2 clock ready
    11. * @arg RCC_FLAG_PLL3RDY: PLL3 clock ready
    12. * @arg RCC_FLAG_LSERDY: LSE oscillator clock ready
    13. * @arg RCC_FLAG_LSIRDY: LSI oscillator clock ready
    14. * @arg RCC_FLAG_PINRST: Pin reset
    15. * @arg RCC_FLAG_PORRST: POR/PDR reset
    16. * @arg RCC_FLAG_SFTRST: Software reset
    17. * @arg RCC_FLAG_IWDGRST: Independent Watchdog reset
    18. * @arg RCC_FLAG_WWDGRST: Window Watchdog reset
    19. * @arg RCC_FLAG_LPWRRST: Low Power reset
    20. *
    21. * For @b other_STM32_devices, this parameter can be one of the following values:
    22. * @arg RCC_FLAG_HSIRDY: HSI oscillator clock ready
    23. * @arg RCC_FLAG_HSERDY: HSE oscillator clock ready
    24. * @arg RCC_FLAG_PLLRDY: PLL clock ready
    25. * @arg RCC_FLAG_LSERDY: LSE oscillator clock ready
    26. * @arg RCC_FLAG_LSIRDY: LSI oscillator clock ready
    27. * @arg RCC_FLAG_PINRST: Pin reset
    28. * @arg RCC_FLAG_PORRST: POR/PDR reset
    29. * @arg RCC_FLAG_SFTRST: Software reset
    30. * @arg RCC_FLAG_IWDGRST: Independent Watchdog reset
    31. * @arg RCC_FLAG_WWDGRST: Window Watchdog reset
    32. * @arg RCC_FLAG_LPWRRST: Low Power reset
    33. *
    34. * @retval The new state of RCC_FLAG (SET or RESET).
    35. */
    36. FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)
    37. {
    38. uint32_t tmp = 0;
    39. uint32_t statusreg = 0;
    40. FlagStatus bitstatus = RESET;
    41. /* Check the parameters */
    42. assert_param(IS_RCC_FLAG(RCC_FLAG));
    43. /* Get the RCC register index */
    44. //将输入的标志位右移5位
    45. tmp = RCC_FLAG >> 5;
    46. //判断要访问哪一个寄存器
    47. if (tmp == 1) /* The flag to check is in CR register */
    48. {
    49. statusreg = RCC->CR;
    50. }
    51. else if (tmp == 2) /* The flag to check is in BDCR register */
    52. {
    53. statusreg = RCC->BDCR;
    54. }
    55. else /* The flag to check is in CSR register */
    56. {
    57. statusreg = RCC->CSR;
    58. }
    59. /* Get the flag position */
    60. /**
    61. FLAG_Mask:0x1f:1 1111
    62. */
    63. //这里我们可以得出应该将“1”移动几个bit
    64. //比如我们此时选中的RCC_FLAG=RCC->CR的HSERDY(此位对应bit17)
    65. //则此时tmp=11 0001 & 1 1111=1 0001(对应十进制17)
    66. tmp = RCC_FLAG & FLAG_Mask;
    67. //RESET表示置位:表示数值“0”
    68. if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET)
    69. {
    70. //此时进入,表示该位已经被设置为1
    71. bitstatus = SET;
    72. }
    73. else
    74. {
    75. bitstatus = RESET;
    76. }
    77. /* Return the flag status */
    78. return bitstatus;
    79. }

    5.RCC_HSICmd(设置内部晶振状态)

    发送命令的

    1. /**
    2. * @brief Enables or disables the Internal High Speed oscillator (HSI).
    3. * @note HSI can not be stopped if it is used directly or through the PLL as system clock.
    4. * @param NewState: new state of the HSI. This parameter can be: ENABLE or DISABLE.
    5. * @retval None
    6. */
    7. void RCC_HSICmd(FunctionalState NewState)
    8. {
    9. /* Check the parameters */
    10. assert_param(IS_FUNCTIONAL_STATE(NewState));
    11. *(__IO uint32_t *) CR_HSION_BB = (uint32_t)NewState;
    12. }

    这里使用解引用的方式,因为我们这里只需要操纵一位

    6.RCC_PLLConfig(设置时钟频率)

    在使用这个PLL之前一定一定是没有使用PLL,才可以调用这个函数

    配置PLL的时钟源倍频

    1.参数:时钟倍频

    2.参数:时钟PLL倍频系数

    3.代码理解

    1. /**
    2. * @brief Configures the PLL clock source and multiplication factor.
    3. * @note This function must be used only when the PLL is disabled.
    4. * @param RCC_PLLSource: specifies the PLL entry clock source.
    5. * For @b STM32_Connectivity_line_devices or @b STM32_Value_line_devices,
    6. * this parameter can be one of the following values:
    7. * @arg RCC_PLLSource_HSI_Div2: HSI oscillator clock divided by 2 selected as PLL clock entry
    8. * @arg RCC_PLLSource_PREDIV1: PREDIV1 clock selected as PLL clock entry
    9. * For @b other_STM32_devices, this parameter can be one of the following values:
    10. * @arg RCC_PLLSource_HSI_Div2: HSI oscillator clock divided by 2 selected as PLL clock entry
    11. * @arg RCC_PLLSource_HSE_Div1: HSE oscillator clock selected as PLL clock entry
    12. * @arg RCC_PLLSource_HSE_Div2: HSE oscillator clock divided by 2 selected as PLL clock entry
    13. * @param RCC_PLLMul: specifies the PLL multiplication factor.
    14. * For @b STM32_Connectivity_line_devices, this parameter can be RCC_PLLMul_x where x:{[4,9], 6_5}
    15. * For @b other_STM32_devices, this parameter can be RCC_PLLMul_x where x:[2,16]
    16. * @retval None
    17. */
    18. void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul)
    19. {
    20. uint32_t tmpreg = 0;
    21. /* Check the parameters */
    22. assert_param(IS_RCC_PLL_SOURCE(RCC_PLLSource));
    23. assert_param(IS_RCC_PLL_MUL(RCC_PLLMul));
    24. tmpreg = RCC->CFGR;//我们要操纵的2个参数都在CFGR
    25. /* Clear PLLSRC, PLLXTPRE and PLLMUL[3:0] bits */
    26. tmpreg &= CFGR_PLL_Mask;//清零
    27. /* Set the PLL configuration bits */
    28. tmpreg |= RCC_PLLSource | RCC_PLLMul;//置1
    29. /* Store the new value */
    30. RCC->CFGR = tmpreg;
    31. }

    7.RCC_PREDIV1Config(与F1无关,此处不看)

    7.RCC_AHBPeriphClockCmd(外设时钟复位)

    外设复位

    1. /**
    2. * @brief Enables or disables the AHB peripheral clock.
    3. * @param RCC_AHBPeriph: specifies the AHB peripheral to gates its clock.
    4. *
    5. * For @b STM32_Connectivity_line_devices, this parameter can be any combination
    6. * of the following values:
    7. * @arg RCC_AHBPeriph_DMA1
    8. * @arg RCC_AHBPeriph_DMA2
    9. * @arg RCC_AHBPeriph_SRAM
    10. * @arg RCC_AHBPeriph_FLITF
    11. * @arg RCC_AHBPeriph_CRC
    12. * @arg RCC_AHBPeriph_OTG_FS
    13. * @arg RCC_AHBPeriph_ETH_MAC
    14. * @arg RCC_AHBPeriph_ETH_MAC_Tx
    15. * @arg RCC_AHBPeriph_ETH_MAC_Rx
    16. *
    17. * For @b other_STM32_devices, this parameter can be any combination of the
    18. * following values:
    19. * @arg RCC_AHBPeriph_DMA1
    20. * @arg RCC_AHBPeriph_DMA2
    21. * @arg RCC_AHBPeriph_SRAM
    22. * @arg RCC_AHBPeriph_FLITF
    23. * @arg RCC_AHBPeriph_CRC
    24. * @arg RCC_AHBPeriph_FSMC
    25. * @arg RCC_AHBPeriph_SDIO
    26. *
    27. * @note SRAM and FLITF clock can be disabled only during sleep mode.
    28. * @param NewState: new state of the specified peripheral clock.
    29. * This parameter can be: ENABLE or DISABLE.
    30. * @retval None
    31. */
    32. void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState)
    33. {
    34. /* Check the parameters */
    35. assert_param(IS_RCC_AHB_PERIPH(RCC_AHBPeriph));
    36. assert_param(IS_FUNCTIONAL_STATE(NewState));
    37. if (NewState != DISABLE)
    38. {
    39. RCC->AHBENR |= RCC_AHBPeriph;
    40. }
    41. else
    42. {
    43. RCC->AHBENR &= ~RCC_AHBPeriph;
    44. }
    45. }

    8.RCC_HCLKConfig(AHB频率)

    配置AHB clock

    1. /**
    2. * @brief Configures the AHB clock (HCLK).
    3. * @param RCC_SYSCLK: defines the AHB clock divider. This clock is derived from
    4. * the system clock (SYSCLK).
    5. * This parameter can be one of the following values:
    6. * @arg RCC_SYSCLK_Div1: AHB clock = SYSCLK
    7. * @arg RCC_SYSCLK_Div2: AHB clock = SYSCLK/2
    8. * @arg RCC_SYSCLK_Div4: AHB clock = SYSCLK/4
    9. * @arg RCC_SYSCLK_Div8: AHB clock = SYSCLK/8
    10. * @arg RCC_SYSCLK_Div16: AHB clock = SYSCLK/16
    11. * @arg RCC_SYSCLK_Div64: AHB clock = SYSCLK/64
    12. * @arg RCC_SYSCLK_Div128: AHB clock = SYSCLK/128
    13. * @arg RCC_SYSCLK_Div256: AHB clock = SYSCLK/256
    14. * @arg RCC_SYSCLK_Div512: AHB clock = SYSCLK/512
    15. * @retval None
    16. */
    17. void RCC_HCLKConfig(uint32_t RCC_SYSCLK)
    18. {
    19. uint32_t tmpreg = 0;
    20. /* Check the parameters */
    21. //判断要进行多少的分频
    22. assert_param(IS_RCC_HCLK(RCC_SYSCLK));
    23. //选择要进行操纵的寄存器
    24. tmpreg = RCC->CFGR;
    25. /* Clear HPRE[3:0] bits */
    26. /**
    27. CFGR_HPRE_Reset_Mask:0xFFFFFF0F==》0000 1111
    28. */
    29. //表示将CFGR的bit4-bit7位置0
    30. tmpreg &= CFGR_HPRE_Reset_Mask;
    31. /* Set HPRE[3:0] bits according to RCC_SYSCLK value */
    32. //表示将CFGR的bit4-bit7位置1
    33. tmpreg |= RCC_SYSCLK;
    34. /* Store the new value */
    35. RCC->CFGR = tmpreg;
    36. }

    9.RCC_PCLK1Config(APB1频率)/RCC_PCLK2Config(APB2频率)

    1. /**
    2. * @brief Configures the Low Speed APB clock (PCLK1).
    3. * @param RCC_HCLK: defines the APB1 clock divider. This clock is derived from
    4. * the AHB clock (HCLK).
    5. * This parameter can be one of the following values:
    6. * @arg RCC_HCLK_Div1: APB1 clock = HCLK
    7. * @arg RCC_HCLK_Div2: APB1 clock = HCLK/2
    8. * @arg RCC_HCLK_Div4: APB1 clock = HCLK/4
    9. * @arg RCC_HCLK_Div8: APB1 clock = HCLK/8
    10. * @arg RCC_HCLK_Div16: APB1 clock = HCLK/16
    11. * @retval None
    12. */
    13. void RCC_PCLK1Config(uint32_t RCC_HCLK)
    14. {
    15. uint32_t tmpreg = 0;
    16. /* Check the parameters */
    17. assert_param(IS_RCC_PCLK(RCC_HCLK));
    18. tmpreg = RCC->CFGR;
    19. /* Clear PPRE1[2:0] bits */
    20. tmpreg &= CFGR_PPRE1_Reset_Mask;
    21. /* Set PPRE1[2:0] bits according to RCC_HCLK value */
    22. tmpreg |= RCC_HCLK;
    23. /* Store the new value */
    24. RCC->CFGR = tmpreg;
    25. }
    26. /**
    27. * @brief Configures the High Speed APB clock (PCLK2).
    28. * @param RCC_HCLK: defines the APB2 clock divider. This clock is derived from
    29. * the AHB clock (HCLK).
    30. * This parameter can be one of the following values:
    31. * @arg RCC_HCLK_Div1: APB2 clock = HCLK
    32. * @arg RCC_HCLK_Div2: APB2 clock = HCLK/2
    33. * @arg RCC_HCLK_Div4: APB2 clock = HCLK/4
    34. * @arg RCC_HCLK_Div8: APB2 clock = HCLK/8
    35. * @arg RCC_HCLK_Div16: APB2 clock = HCLK/16
    36. * @retval None
    37. */
    38. void RCC_PCLK2Config(uint32_t RCC_HCLK)
    39. {
    40. uint32_t tmpreg = 0;
    41. /* Check the parameters */
    42. assert_param(IS_RCC_PCLK(RCC_HCLK));
    43. tmpreg = RCC->CFGR;
    44. /* Clear PPRE2[2:0] bits */
    45. tmpreg &= CFGR_PPRE2_Reset_Mask;
    46. /* Set PPRE2[2:0] bits according to RCC_HCLK value */
    47. tmpreg |= RCC_HCLK << 3;
    48. /* Store the new value */
    49. RCC->CFGR = tmpreg;
    50. }

    10.RCC_SYSCLKConfig(选择使用哪一个作为系统时钟HSI/HSE/SYS)

    1. /**
    2. * @brief Configures the system clock (SYSCLK).
    3. * @param RCC_SYSCLKSource: specifies the clock source used as system clock.
    4. * This parameter can be one of the following values:
    5. * @arg RCC_SYSCLKSource_HSI: HSI selected as system clock
    6. * @arg RCC_SYSCLKSource_HSE: HSE selected as system clock
    7. * @arg RCC_SYSCLKSource_PLLCLK: PLL selected as system clock
    8. * @retval None
    9. */
    10. void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource)
    11. {
    12. uint32_t tmpreg = 0;
    13. /* Check the parameters */
    14. //判断用户输入的参数是否正确
    15. assert_param(IS_RCC_SYSCLK_SOURCE(RCC_SYSCLKSource));
    16. tmpreg = RCC->CFGR;
    17. /* Clear SW[1:0] bits */
    18. tmpreg &= CFGR_SW_Mask;//置0
    19. /* Set SW[1:0] bits according to RCC_SYSCLKSource value */
    20. tmpreg |= RCC_SYSCLKSource;//置1
    21. /* Store the new value */
    22. RCC->CFGR = tmpreg;
    23. }

    11.RCC_APB2PeriphResetCmd(外设的重新复位)

    1. /**
    2. * @brief Forces or releases High Speed APB (APB2) peripheral reset.
    3. * @param RCC_APB2Periph: specifies the APB2 peripheral to reset.
    4. * This parameter can be any combination of the following values:
    5. * @arg RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB,
    6. * RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE,
    7. * RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1,
    8. * RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1,
    9. * RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3,
    10. * RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17,
    11. * RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11
    12. * @param NewState: new state of the specified peripheral reset.
    13. * This parameter can be: ENABLE or DISABLE.
    14. * @retval None
    15. */
    16. void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
    17. {
    18. /* Check the parameters */
    19. assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));
    20. assert_param(IS_FUNCTIONAL_STATE(NewState));
    21. if (NewState != DISABLE)
    22. {
    23. RCC->APB2RSTR |= RCC_APB2Periph;
    24. }
    25. else
    26. {
    27. RCC->APB2RSTR &= ~RCC_APB2Periph;
    28. }
    29. }

    4.注意点:

    1.进制问题

    我们在寄存器中的偏移量都是以十进制进行设置的,如果想要将其定义在宏定义中,记得将其转换为十六进制

    2.位段计算

    5.使用库重写时钟设置函数

    1.原始函数

    1. #include "clock.h"
    2. #include "gpio.h"
    3. void Set_SysClockTo72M(void){
    4. //检测外部晶振是否准备好
    5. unsigned int Rcc_CR_HSE_Ready=0;
    6. //等待开启PLL开启成功
    7. unsigned int Rcc_CR_PLL_Ready=0;
    8. //判断切换成PLL是否成功
    9. unsigned int RCC_CF_SWS_PLL=0;
    10. unsigned int faultTime=0;//判断等待是否超时
    11. //一、复位RCC_CR寄存器
    12. rRCC_CR = 0x00000083;
    13. //二、开启外部时钟(外部晶振)
    14. //第一步:先置0【将bit16清零】
    15. rRCC_CR &= ~(1<<16);//关闭HSEON
    16. //第二步:在置1
    17. rRCC_CR |= (1<<16);//打开HSEON,让HSE开始工作
    18. //三、检测外部时钟开启是否成功
    19. do{
    20. //检测HSEREAY(bit17)是否为1,1表示准备好
    21. Rcc_CR_HSE_Ready=rRCC_CR&(1<<17);//取出bit17
    22. faultTime++;
    23. }while((faultTime<0x0fffffff) && (Rcc_CR_HSE_Ready==0));
    24. //跳出do-while 1)要么超时2)要么准好了
    25. //判断是超时还是准备好
    26. //注意点:不能直接使用“Rcc_CR_HSE_Ready”因为rRCC_CR是需要读一次寄存器
    27. //但是读出的结果可能还未改变,所以一定不能直接使用
    28. if((rRCC_CR&(1<<17))!=0)//rRCC_CR&(1<<17)==1
    29. {//这里HSE就ready,下面再去配置PLL并且等待他ready
    30. //设置Flash
    31. rFLASH_ACR |= 0x10;
    32. rFLASH_ACR &= (~0x03);
    33. rFLASH_ACR |= (0x02);
    34. //四、对其进行预分频
    35. //HPRE【AHB】:对应bit4-bit7:不分频(000)
    36. //PPRE1【APB1】:对应bit8-bit10:进行二分频(100)
    37. //PPRE2【APB2】:对应bit11-bit13:不分频(000)
    38. //AHB和APB2未分频,APB1被2分频
    39. //所以最终:AHB和APB2都是72MHZ,APB1是36MHZ
    40. //第一步:先置0
    41. rRCC_CFGR &=(~((0x0f<<4) | (0x07<<8) | (0x07<<11)));
    42. //等价于:rRCC_CFGR=(~(0x3ff<<4));
    43. //第二步:置1
    44. rRCC_CFGR |=((0x0<<4) | (0x04<<8) | (0x0<<11));
    45. //五、设置SHE为输入时钟,同时HSE不分频
    46. //选择HSE作为PLL输入并且HSE不分频
    47. //设置为输入时钟:bit16
    48. //设置为不分频:bit17
    49. //第一步:先置0
    50. rRCC_CFGR &=(~((1<<16) | (1<<17)));
    51. //第二步:置1,bit16
    52. rRCC_CFGR |= ((1<<16) | (0<<17));
    53. //六、设置PLL倍频系数
    54. //9分频:0111:0x07
    55. rRCC_CFGR &=(~(0x0f<<18));//清零bit18-bit21
    56. rRCC_CFGR |= (0x07<<18);//设置为9倍频
    57. //七、打开PLL开关
    58. rRCC_CR |= (1<<24);
    59. //八、等待开启PLL开启成功
    60. //因为前面已经使用到,被累加了,使用这里要重新置0
    61. faultTime=0;
    62. do{
    63. led_init();
    64. Rcc_CR_PLL_Ready=rRCC_CR & (1<<25);//检测第25位是否为1
    65. faultTime++;
    66. }while((faultTime<0x0fffffff) && (Rcc_CR_PLL_Ready==0));
    67. if((rRCC_CR & (1<<25)) == (1<<25)){
    68. //到这里说明PLL已经稳定,可以用了,下面可以切换成外部时钟了
    69. //九、切换成PLL
    70. rRCC_CFGR &=(~(0x03)<<0);
    71. rRCC_CFGR |=(0x02<<0);
    72. //十、判断切换成PLL是否成功
    73. //因为前面已经使用到,被累加了,使用这里要重新置0
    74. faultTime=0;
    75. do{
    76. RCC_CF_SWS_PLL=rRCC_CFGR & (0x03<<2);//读出bit2-bit3
    77. faultTime++;
    78. led_init();
    79. //0x02<<2:表示此时转换成PLL
    80. }
    81. while ((faultTime<0x0FFFFFFF) && (RCC_CF_SWS_PLL!=(0x02<<2)));
    82. //十一、此时PLL转换成功
    83. if((rRCC_CFGR & (0x03<<2))==(0x02<<2)){
    84. //到这里我们的时钟整个就设置好了,可以结束了
    85. }else{
    86. //到这里说明PLL输出作为PLL失败
    87. while(1);
    88. }
    89. }
    90. else{
    91. //到这里说明PLL启动时出错了,PLL不能稳定工作
    92. while(1);
    93. }
    94. }else{//超时,或者未准备好,此时HSE不可以使用
    95. while(1);
    96. }
    97. }

    2.自己封装一个RCC_WaitForPLLStartUp

    此处我们参考【RCC_WaitForHSEStartUp】这个函数来自己写

    由源文件中没有定义【PLL_STARTUP_TIMEOUT】所以我们要自定义

    1. #define PLL_STARTUP_TIMEOUT ((uint16_t)0x0500000)
    2. //本函数作用:等待PLL倍频后输出稳定
    3. //返回值:SUCCESS说明未超时,ERROR超时
    4. ErrorStatus RCC_WaitForPLLStartUp(void)
    5. {
    6. __IO uint32_t StartUpCounter = 0;
    7. ErrorStatus status = ERROR;
    8. FlagStatus PLLStatus = RESET;
    9. /* Wait till HSE is ready and if Time out is reached exit */
    10. do
    11. {
    12. //读取寄存器的值
    13. PLLStatus = RCC_GetFlagStatus(RCC_FLAG_PLLRDY);
    14. StartUpCounter++; //读取是否超时的
    15. } while((StartUpCounter != PLL_STARTUP_TIMEOUT) && (PLLStatus == RESET));
    16. //这里判断是防止超时
    17. if (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) != RESET)
    18. {
    19. status = SUCCESS;
    20. }
    21. else
    22. {
    23. //超时
    24. status = ERROR;
    25. }
    26. return (status);
    27. }

    3.完整使用库函数的clock

    1. //这个函数里面包含了全部外设头文件
    2. #include "stm32f10x.h"
    3. //等价于
    4. //#include"stm32f10x_conf.h"
    5. #define PLL_STARTUP_TIMEOUT ((uint16_t)0x0500000)
    6. //本函数作用:等待PLL倍频后输出稳定
    7. //返回值:SUCCESS说明未超时,ERROR超时
    8. ErrorStatus RCC_WaitForPLLStartUp(void)
    9. {
    10. __IO uint32_t StartUpCounter = 0;
    11. ErrorStatus status = ERROR;
    12. FlagStatus PLLStatus = RESET;
    13. /* Wait till HSE is ready and if Time out is reached exit */
    14. do
    15. {
    16. //读取寄存器的值
    17. PLLStatus = RCC_GetFlagStatus(RCC_FLAG_PLLRDY);
    18. StartUpCounter++; //读取是否超时的
    19. } while((StartUpCounter != PLL_STARTUP_TIMEOUT) && (PLLStatus == RESET));
    20. //这里判断是防止超时
    21. if (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) != RESET)
    22. {
    23. status = SUCCESS;
    24. }
    25. else
    26. {
    27. //超时
    28. status = ERROR;
    29. }
    30. return (status);
    31. }
    32. void Set_SysClockTo72M(void){
    33. //接收判断回来的HSE是否已经稳定
    34. ErrorStatus sta=ERROR;
    35. //faultTime:用来判断是否超时
    36. unsigned int faultTime=0;
    37. unsigned int RCC_CF_SWS_PLL=0;
    38. //一、先关闭HSEON然后在打开HSEON
    39. RCC_HSEConfig(RCC_HSE_ON);
    40. /*
    41. rRCC_CR = 0x00000083;
    42. rRCC_CR &= ~(1<<16);//关闭HSEON
    43. rRCC_CR |= (1<<16);//打开HSEON,让HSE开始工作
    44. */
    45. //二、等到HSE稳定
    46. sta=RCC_WaitForHSEStartUp();
    47. /*
    48. do{
    49. //检测HSEREAY(bit17)是否为1,1表示准备好
    50. Rcc_CR_HSE_Ready=rRCC_CR&(1<<17);//取出bit17
    51. faultTime++;
    52. }while((faultTime<0x0fffffff) && (Rcc_CR_HSE_Ready==0));
    53. //跳出do-while 1)要么超时2)要么准好了
    54. */
    55. //三、判断是HSE稳定了还是超时了
    56. if(sta==SUCCESS)
    57. //if((rRCC_CR&(1<<17))!=0)//rRCC_CR&(1<<17)==1
    58. {//这里HSE就ready,下面再去配置PLL并且等待他ready
    59. //四、设置Flash
    60. FLASH->ACR |= 0x10;
    61. FLASH->ACR &= (~0x03);
    62. FLASH->ACR |= (0x02);
    63. /*
    64. rFLASH_ACR |= 0x10;
    65. rFLASH_ACR &= (~0x03);
    66. rFLASH_ACR |= (0x02);
    67. */
    68. //AHB和APB2未分频,APB1被2分频
    69. //所以最终:AHB和APB2都是72MHZ,APB1是36MHZ
    70. //五、配置相关的倍频信息
    71. //配置HCLK为SYSCLK/1
    72. RCC_HCLKConfig(RCC_SYSCLK_Div1);
    73. //配置PCLK1为JCLK的2分频
    74. RCC_PCLK1Config(RCC_HCLK_Div2);
    75. //配置PCLK2为JCLK的1分频
    76. RCC_PCLK2Config(RCC_HCLK_Div1);
    77. /*
    78. rRCC_CFGR &=(~((0x0f<<4) | (0x07<<8) | (0x07<<11)));
    79. //等价于:rRCC_CFGR=(~(0x3ff<<4));
    80. rRCC_CFGR |=((0x0<<4) | (0x04<<8) | (0x0<<11));
    81. */
    82. //六、设置HSE/1为PLL时钟源,PLL倍频系数为9
    83. RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);
    84. /*
    85. //设置SHE为输入时钟,同时HSE不分频
    86. rRCC_CFGR &=(~((1<<16) | (1<<17)));
    87. rRCC_CFGR |= ((1<<16) | (0<<17));
    88. //设置PLL倍频系数
    89. //9分频:0111:0x07
    90. rRCC_CFGR &=(~(0x0f<<18));//清零bit18-bit21
    91. rRCC_CFGR |= (0x07<<18);//设置为9倍频
    92. */
    93. //七、打开PLL开关
    94. RCC_PLLCmd(ENABLE);
    95. //rRCC_CR |= (1<<24);
    96. //因为HAL库中没有等到PLL的函数
    97. //此处我们参考【RCC_WaitForHSEStartUp】这个函数来自己写
    98. //八、等待开启PLL开启成功
    99. sta=RCC_WaitForPLLStartUp();
    100. /*
    101. //因为前面已经使用到,被累加了,使用这里要重新置0
    102. faultTime=0;
    103. do{
    104. led_init();
    105. Rcc_CR_PLL_Ready=rRCC_CR & (1<<25);//检测第25位是否为1
    106. faultTime++;
    107. }while((faultTime<0x0fffffff) && (Rcc_CR_PLL_Ready==0));
    108. */
    109. //九、判断PLL稳定还是超时
    110. //if((rRCC_CR & (1<<25)) == (1<<25)){
    111. if(sta==SUCCESS){
    112. //到这里说明PLL已经稳定,可以用了,下面可以切换成外部时钟了
    113. //九、切换成PLL
    114. RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    115. /*
    116. rRCC_CFGR &=(~(0x03)<<0);
    117. rRCC_CFGR |=(0x02<<0);
    118. */
    119. //十、判断切换成PLL是否成功
    120. //因为前面已经使用到,被累加了,使用这里要重新置0
    121. faultTime=0;
    122. do{
    123. RCC_CF_SWS_PLL=RCC->CFGR & (0x03<<2);//读出bit2-bit3
    124. faultTime++;
    125. //0x02<<2:表示此时转换成PLL
    126. }
    127. while ((faultTime<0x0FFFFFFF) && (RCC_CF_SWS_PLL!=(0x02<<2)));
    128. //十一、此时PLL转换成功
    129. if((RCC->CFGR & (0x03<<2))==(0x02<<2)){
    130. //到这里我们的时钟整个就设置好了,可以结束了
    131. }else{
    132. //到这里说明PLL输出作为PLL失败
    133. while(1);
    134. }
    135. }
    136. else{
    137. //到这里说明PLL启动时出错了,PLL不能稳定工作
    138. while(1);
    139. }
    140. }else{//超时,或者未准备好,此时HSE不可以使用
    141. while(1);
    142. }
    143. }

     

    1. #include "stm32f10x.h"
    2. #include "clock.h"
    3. /**
    4. 使用标准库重写RCC模块
    5. */
    6. void delay();
    7. void led_init();
    8. void led_flash(void);
    9. void led_init(){
    10. //因为RCC部分还没有定义结构体,所以还是按照原来的方式去操作
    11. RCC->APB2ENR = 0x00000008;
    12. GPIOB->CRH=0x33333333;
    13. GPIOB->ODR=0x00000000;
    14. }
    15. void delay(){
    16. unsigned int i=0,j=0;
    17. for(i=0;i<1000;i++){
    18. for(j=0;j<2000;j++){
    19. }
    20. }
    21. }
    22. void led_flash(void){
    23. unsigned int i=0;
    24. for(i=0;i<3;i++){
    25. GPIOB->ODR = 0x00000000;//全亮
    26. delay();
    27. GPIOB->ODR = 0x0000ff00;//全灭
    28. delay();
    29. }
    30. }
    31. int main(){
    32. led_init();
    33. led_flash();
    34. Set_SysClockTo72M();
    35. led_flash();
    36. return 0;
    37. }

    6.SystmInit注意点:

    我们在“startup_stm32f10x_md.s”文件中可以看到在执行main函数之前会先执行一个“SystemInit”函数

    所以如果我们想要使用自己的设置72MHZ频率的函数,则应该将SystemInit注释调。

  • 相关阅读:
    【数学建模绘图系列教程】绘图模板总结
    TS类型断言
    给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
    上周热点回顾(6.17-6.23)
    Linux内核驱动开发的步骤
    指针之野指针系列(2):如何规避野指针
    用Auth Analyzer插件批量测试接口越权,安全测试快人一步!
    【算法分析与设计】分支限界法(下)
    私有化部署的即时通讯平台,为企业移动业务安全保驾护航
    VUE必知必会
  • 原文地址:https://blog.csdn.net/m0_63077733/article/details/134005772