【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位的寄存器,所以如果我们只想要操作寄存器其中的一位,所以我们可以使用位移操作

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

3.第一个寄存器:CR

1.HSION

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

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

2.PLLON

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

4.RCC registers bit mask

Reset:进行位与置0

Set:进行位或置1

/* ---------------------- RCC registers bit mask ------------------------ *//* CR register bit mask */
#define CR_HSEBYP_Reset           ((uint32_t)0xFFFBFFFF)
#define CR_HSEBYP_Set             ((uint32_t)0x00040000)
#define CR_HSEON_Reset            ((uint32_t)0xFFFEFFFF)
#define CR_HSEON_Set              ((uint32_t)0x00010000)
#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

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

3.函数

1.RCC_DeInit

/*** @brief  Resets the RCC clock configuration to the default reset state.* @param  None* @retval None*/
void RCC_DeInit(void)
{/* Set HSION bit */
//将CR这个位写为1RCC->CR |= (uint32_t)0x00000001;/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CLRCC->CFGR &= (uint32_t)0xF8FF0000;
#else//非CL的芯片使用RCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */   /* Reset HSEON, CSSON and PLLON bits */
//HSEON, CSSON and PLLON:将这几位置0RCC->CR &= (uint32_t)0xFEF6FFFF;/* Reset HSEBYP bit */RCC->CR &= (uint32_t)0xFFFBFFFF;/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */RCC->CFGR &= (uint32_t)0xFF80FFFF;#ifdef STM32F10X_CL/* Reset PLL2ON and PLL3ON bits */RCC->CR &= (uint32_t)0xEBFFFFFF;/* Disable all interrupts and clear pending bits  */RCC->CIR = 0x00FF0000;/* Reset CFGR2 register */RCC->CFGR2 = 0x00000000;
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)/* Disable all interrupts and clear pending bits  */RCC->CIR = 0x009F0000;/* Reset CFGR2 register */RCC->CFGR2 = 0x00000000;      
#else/* Disable all interrupts and clear pending bits  */RCC->CIR = 0x009F0000;
#endif /* STM32F10X_CL */}

2.RCC_HSEConfig

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

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

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

1.assert:断言

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

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

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

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

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

3.代码理解

/*** @brief  Configures the External High Speed oscillator (HSE).* @note   HSE can not be stopped if it is used directly or through the PLL as system clock.* @param  RCC_HSE: specifies the new state of the HSE.*   This parameter can be one of the following values:*     @arg RCC_HSE_OFF: HSE oscillator OFF*     @arg RCC_HSE_ON: HSE oscillator ON*     @arg RCC_HSE_Bypass: HSE oscillator bypassed with external clock* @retval None*/
void RCC_HSEConfig(uint32_t RCC_HSE)
{/* Check the parameters */assert_param(IS_RCC_HSE(RCC_HSE));/* Reset HSEON and HSEBYP bits before configuring the HSE ------------------*//* Reset HSEON bit */RCC->CR &= CR_HSEON_Reset;/* Reset HSEBYP bit */RCC->CR &= CR_HSEBYP_Reset;/* Configure HSE (RCC_HSE_OFF is already covered by the code section above) */switch(RCC_HSE){case RCC_HSE_ON:/* Set HSEON bit */RCC->CR |= CR_HSEON_Set;break;case RCC_HSE_Bypass:/* Set HSEBYP and HSEON bits */RCC->CR |= CR_HSEBYP_Set | CR_HSEON_Set;break;default://RCC_HSE_OFFbreak;}
}

3.RCC_WaitForHSEStartUp(等待HSE)

1.ErrorStatus

判断是否成功

一般:0:表示失败

           1:表示成功

2.计数值加上volatile

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

3.代码理解

/*** @brief  Waits for HSE start-up.* @param  None* @retval An ErrorStatus enumuration value:* - SUCCESS: HSE oscillator is stable and ready to use* - ERROR: HSE oscillator not yet ready*/
ErrorStatus RCC_WaitForHSEStartUp(void)
{__IO uint32_t StartUpCounter = 0;ErrorStatus status = ERROR;FlagStatus HSEStatus = RESET;/* Wait till HSE is ready and if Time out is reached exit */do{//读取寄存器的值HSEStatus = RCC_GetFlagStatus(RCC_FLAG_HSERDY);StartUpCounter++;  //读取是否超时的} while((StartUpCounter != HSE_STARTUP_TIMEOUT) && (HSEStatus == RESET));//这里判断是防止超时if (RCC_GetFlagStatus(RCC_FLAG_HSERDY) != RESET){status = SUCCESS;}else{//超时status = ERROR;}  return (status);
}

4.RCC_GetFlagStatus(获取bit位状态)

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

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

1.返回值进行状态判断

2.输入参数

3.IS_RCC_FLAG

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

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

  /* Get the RCC register index *///将输入的标志位右移5位tmp = RCC_FLAG >> 5;//判断要访问哪一个寄存器if (tmp == 1)               /* The flag to check is in CR register */{statusreg = RCC->CR;}else if (tmp == 2)          /* The flag to check is in BDCR register */{statusreg = RCC->BDCR;}else                       /* The flag to check is in CSR register */{statusreg = RCC->CSR;}

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

  /* Get the flag position *//**FLAG_Mask:0x1f*/tmp = RCC_FLAG & FLAG_Mask;if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET){bitstatus = SET;}else{bitstatus = RESET;}

6.代码理解

/*** @brief  Checks whether the specified RCC flag is set or not.* @param  RCC_FLAG: specifies the flag to check.*   *   For @b STM32_Connectivity_line_devices, this parameter can be one of the*   following values:*     @arg RCC_FLAG_HSIRDY: HSI oscillator clock ready*     @arg RCC_FLAG_HSERDY: HSE oscillator clock ready*     @arg RCC_FLAG_PLLRDY: PLL clock ready*     @arg RCC_FLAG_PLL2RDY: PLL2 clock ready      *     @arg RCC_FLAG_PLL3RDY: PLL3 clock ready                           *     @arg RCC_FLAG_LSERDY: LSE oscillator clock ready*     @arg RCC_FLAG_LSIRDY: LSI oscillator clock ready*     @arg RCC_FLAG_PINRST: Pin reset*     @arg RCC_FLAG_PORRST: POR/PDR reset*     @arg RCC_FLAG_SFTRST: Software reset*     @arg RCC_FLAG_IWDGRST: Independent Watchdog reset*     @arg RCC_FLAG_WWDGRST: Window Watchdog reset*     @arg RCC_FLAG_LPWRRST: Low Power reset* *   For @b other_STM32_devices, this parameter can be one of the following values:        *     @arg RCC_FLAG_HSIRDY: HSI oscillator clock ready*     @arg RCC_FLAG_HSERDY: HSE oscillator clock ready*     @arg RCC_FLAG_PLLRDY: PLL clock ready*     @arg RCC_FLAG_LSERDY: LSE oscillator clock ready*     @arg RCC_FLAG_LSIRDY: LSI oscillator clock ready*     @arg RCC_FLAG_PINRST: Pin reset*     @arg RCC_FLAG_PORRST: POR/PDR reset*     @arg RCC_FLAG_SFTRST: Software reset*     @arg RCC_FLAG_IWDGRST: Independent Watchdog reset*     @arg RCC_FLAG_WWDGRST: Window Watchdog reset*     @arg RCC_FLAG_LPWRRST: Low Power reset*   * @retval The new state of RCC_FLAG (SET or RESET).*/
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)
{uint32_t tmp = 0;uint32_t statusreg = 0;FlagStatus bitstatus = RESET;/* Check the parameters */assert_param(IS_RCC_FLAG(RCC_FLAG));/* Get the RCC register index *///将输入的标志位右移5位tmp = RCC_FLAG >> 5;//判断要访问哪一个寄存器if (tmp == 1)               /* The flag to check is in CR register */{statusreg = RCC->CR;}else if (tmp == 2)          /* The flag to check is in BDCR register */{statusreg = RCC->BDCR;}else                       /* The flag to check is in CSR register */{statusreg = RCC->CSR;}/* Get the flag position *//**FLAG_Mask:0x1f:1 1111*///这里我们可以得出应该将“1”移动几个bit//比如我们此时选中的RCC_FLAG=RCC->CR的HSERDY(此位对应bit17)//则此时tmp=11 0001    & 1 1111=1 0001(对应十进制17) tmp = RCC_FLAG & FLAG_Mask;//RESET表示置位:表示数值“0”if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET){//此时进入,表示该位已经被设置为1bitstatus = SET;}else{bitstatus = RESET;}/* Return the flag status */return bitstatus;
}

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

发送命令的

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

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

6.RCC_PLLConfig(设置时钟频率)

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

配置PLL的时钟源倍频

1.参数:时钟倍频

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

3.代码理解

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

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

7.RCC_AHBPeriphClockCmd(外设时钟复位)

外设复位


/*** @brief  Enables or disables the AHB peripheral clock.* @param  RCC_AHBPeriph: specifies the AHB peripheral to gates its clock.*   *   For @b STM32_Connectivity_line_devices, this parameter can be any combination*   of the following values:        *     @arg RCC_AHBPeriph_DMA1*     @arg RCC_AHBPeriph_DMA2*     @arg RCC_AHBPeriph_SRAM*     @arg RCC_AHBPeriph_FLITF*     @arg RCC_AHBPeriph_CRC*     @arg RCC_AHBPeriph_OTG_FS    *     @arg RCC_AHBPeriph_ETH_MAC   *     @arg RCC_AHBPeriph_ETH_MAC_Tx*     @arg RCC_AHBPeriph_ETH_MAC_Rx* *   For @b other_STM32_devices, this parameter can be any combination of the *   following values:        *     @arg RCC_AHBPeriph_DMA1*     @arg RCC_AHBPeriph_DMA2*     @arg RCC_AHBPeriph_SRAM*     @arg RCC_AHBPeriph_FLITF*     @arg RCC_AHBPeriph_CRC*     @arg RCC_AHBPeriph_FSMC*     @arg RCC_AHBPeriph_SDIO*   * @note SRAM and FLITF clock can be disabled only during sleep mode.* @param  NewState: new state of the specified peripheral clock.*   This parameter can be: ENABLE or DISABLE.* @retval None*/
void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState)
{/* Check the parameters */assert_param(IS_RCC_AHB_PERIPH(RCC_AHBPeriph));assert_param(IS_FUNCTIONAL_STATE(NewState));if (NewState != DISABLE){RCC->AHBENR |= RCC_AHBPeriph;}else{RCC->AHBENR &= ~RCC_AHBPeriph;}
}

8.RCC_HCLKConfig(AHB频率)

配置AHB clock

/*** @brief  Configures the AHB clock (HCLK).* @param  RCC_SYSCLK: defines the AHB clock divider. This clock is derived from *   the system clock (SYSCLK).*   This parameter can be one of the following values:*     @arg RCC_SYSCLK_Div1: AHB clock = SYSCLK*     @arg RCC_SYSCLK_Div2: AHB clock = SYSCLK/2*     @arg RCC_SYSCLK_Div4: AHB clock = SYSCLK/4*     @arg RCC_SYSCLK_Div8: AHB clock = SYSCLK/8*     @arg RCC_SYSCLK_Div16: AHB clock = SYSCLK/16*     @arg RCC_SYSCLK_Div64: AHB clock = SYSCLK/64*     @arg RCC_SYSCLK_Div128: AHB clock = SYSCLK/128*     @arg RCC_SYSCLK_Div256: AHB clock = SYSCLK/256*     @arg RCC_SYSCLK_Div512: AHB clock = SYSCLK/512* @retval None*/
void RCC_HCLKConfig(uint32_t RCC_SYSCLK)
{uint32_t tmpreg = 0;/* Check the parameters *///判断要进行多少的分频assert_param(IS_RCC_HCLK(RCC_SYSCLK));//选择要进行操纵的寄存器tmpreg = RCC->CFGR;/* Clear HPRE[3:0] bits *//**CFGR_HPRE_Reset_Mask:0xFFFFFF0F==》0000 1111*///表示将CFGR的bit4-bit7位置0tmpreg &= CFGR_HPRE_Reset_Mask;/* Set HPRE[3:0] bits according to RCC_SYSCLK value *///表示将CFGR的bit4-bit7位置1tmpreg |= RCC_SYSCLK;/* Store the new value */RCC->CFGR = tmpreg;
}

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

/*** @brief  Configures the Low Speed APB clock (PCLK1).* @param  RCC_HCLK: defines the APB1 clock divider. This clock is derived from *   the AHB clock (HCLK).*   This parameter can be one of the following values:*     @arg RCC_HCLK_Div1: APB1 clock = HCLK*     @arg RCC_HCLK_Div2: APB1 clock = HCLK/2*     @arg RCC_HCLK_Div4: APB1 clock = HCLK/4*     @arg RCC_HCLK_Div8: APB1 clock = HCLK/8*     @arg RCC_HCLK_Div16: APB1 clock = HCLK/16* @retval None*/
void RCC_PCLK1Config(uint32_t RCC_HCLK)
{uint32_t tmpreg = 0;/* Check the parameters */assert_param(IS_RCC_PCLK(RCC_HCLK));tmpreg = RCC->CFGR;/* Clear PPRE1[2:0] bits */tmpreg &= CFGR_PPRE1_Reset_Mask;/* Set PPRE1[2:0] bits according to RCC_HCLK value */tmpreg |= RCC_HCLK;/* Store the new value */RCC->CFGR = tmpreg;
}/*** @brief  Configures the High Speed APB clock (PCLK2).* @param  RCC_HCLK: defines the APB2 clock divider. This clock is derived from *   the AHB clock (HCLK).*   This parameter can be one of the following values:*     @arg RCC_HCLK_Div1: APB2 clock = HCLK*     @arg RCC_HCLK_Div2: APB2 clock = HCLK/2*     @arg RCC_HCLK_Div4: APB2 clock = HCLK/4*     @arg RCC_HCLK_Div8: APB2 clock = HCLK/8*     @arg RCC_HCLK_Div16: APB2 clock = HCLK/16* @retval None*/
void RCC_PCLK2Config(uint32_t RCC_HCLK)
{uint32_t tmpreg = 0;/* Check the parameters */assert_param(IS_RCC_PCLK(RCC_HCLK));tmpreg = RCC->CFGR;/* Clear PPRE2[2:0] bits */tmpreg &= CFGR_PPRE2_Reset_Mask;/* Set PPRE2[2:0] bits according to RCC_HCLK value */tmpreg |= RCC_HCLK << 3;/* Store the new value */RCC->CFGR = tmpreg;
}

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

/*** @brief  Configures the system clock (SYSCLK).* @param  RCC_SYSCLKSource: specifies the clock source used as system clock.*   This parameter can be one of the following values:*     @arg RCC_SYSCLKSource_HSI: HSI selected as system clock*     @arg RCC_SYSCLKSource_HSE: HSE selected as system clock*     @arg RCC_SYSCLKSource_PLLCLK: PLL selected as system clock* @retval None*/
void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource)
{uint32_t tmpreg = 0;/* Check the parameters *///判断用户输入的参数是否正确assert_param(IS_RCC_SYSCLK_SOURCE(RCC_SYSCLKSource));tmpreg = RCC->CFGR;/* Clear SW[1:0] bits */tmpreg &= CFGR_SW_Mask;//置0/* Set SW[1:0] bits according to RCC_SYSCLKSource value */tmpreg |= RCC_SYSCLKSource;//置1/* Store the new value */RCC->CFGR = tmpreg;
}

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

/*** @brief  Forces or releases High Speed APB (APB2) peripheral reset.* @param  RCC_APB2Periph: specifies the APB2 peripheral to reset.*   This parameter can be any combination of the following values:*     @arg RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB,*          RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE,*          RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1,*          RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1,*          RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3,*          RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17,*          RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11  * @param  NewState: new state of the specified peripheral reset.*   This parameter can be: ENABLE or DISABLE.* @retval None*/
void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
{/* Check the parameters */assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));assert_param(IS_FUNCTIONAL_STATE(NewState));if (NewState != DISABLE){RCC->APB2RSTR |= RCC_APB2Periph;}else{RCC->APB2RSTR &= ~RCC_APB2Periph;}
}

4.注意点:

1.进制问题

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

2.位段计算

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

1.原始函数

#include "clock.h"
#include "gpio.h"void Set_SysClockTo72M(void){//检测外部晶振是否准备好unsigned int Rcc_CR_HSE_Ready=0;//等待开启PLL开启成功unsigned int Rcc_CR_PLL_Ready=0;//判断切换成PLL是否成功unsigned int RCC_CF_SWS_PLL=0;unsigned int faultTime=0;//判断等待是否超时//一、复位RCC_CR寄存器rRCC_CR = 0x00000083;//二、开启外部时钟(外部晶振)//第一步:先置0【将bit16清零】rRCC_CR &= ~(1<<16);//关闭HSEON//第二步:在置1rRCC_CR |= (1<<16);//打开HSEON,让HSE开始工作//三、检测外部时钟开启是否成功do{//检测HSEREAY(bit17)是否为1,1表示准备好Rcc_CR_HSE_Ready=rRCC_CR&(1<<17);//取出bit17faultTime++;}while((faultTime<0x0fffffff) && (Rcc_CR_HSE_Ready==0));//跳出do-while 1)要么超时2)要么准好了//判断是超时还是准备好//注意点:不能直接使用“Rcc_CR_HSE_Ready”因为rRCC_CR是需要读一次寄存器//但是读出的结果可能还未改变,所以一定不能直接使用if((rRCC_CR&(1<<17))!=0)//rRCC_CR&(1<<17)==1{//这里HSE就ready,下面再去配置PLL并且等待他ready//设置FlashrFLASH_ACR |= 0x10;rFLASH_ACR &= (~0x03);rFLASH_ACR |= (0x02);//四、对其进行预分频//HPRE【AHB】:对应bit4-bit7:不分频(000)//PPRE1【APB1】:对应bit8-bit10:进行二分频(100)//PPRE2【APB2】:对应bit11-bit13:不分频(000)//AHB和APB2未分频,APB1被2分频//所以最终:AHB和APB2都是72MHZ,APB1是36MHZ//第一步:先置0rRCC_CFGR &=(~((0x0f<<4) | (0x07<<8) | (0x07<<11)));//等价于:rRCC_CFGR=(~(0x3ff<<4));//第二步:置1rRCC_CFGR |=((0x0<<4) | (0x04<<8) | (0x0<<11));//五、设置SHE为输入时钟,同时HSE不分频//选择HSE作为PLL输入并且HSE不分频//设置为输入时钟:bit16//设置为不分频:bit17//第一步:先置0rRCC_CFGR &=(~((1<<16) | (1<<17)));//第二步:置1,bit16rRCC_CFGR |= ((1<<16) | (0<<17));//六、设置PLL倍频系数//9分频:0111:0x07rRCC_CFGR &=(~(0x0f<<18));//清零bit18-bit21rRCC_CFGR |= (0x07<<18);//设置为9倍频//七、打开PLL开关rRCC_CR |= (1<<24);//八、等待开启PLL开启成功//因为前面已经使用到,被累加了,使用这里要重新置0faultTime=0;do{led_init();Rcc_CR_PLL_Ready=rRCC_CR & (1<<25);//检测第25位是否为1faultTime++;}while((faultTime<0x0fffffff) && (Rcc_CR_PLL_Ready==0));if((rRCC_CR & (1<<25)) == (1<<25)){//到这里说明PLL已经稳定,可以用了,下面可以切换成外部时钟了//九、切换成PLLrRCC_CFGR &=(~(0x03)<<0);rRCC_CFGR |=(0x02<<0);//十、判断切换成PLL是否成功//因为前面已经使用到,被累加了,使用这里要重新置0faultTime=0;do{RCC_CF_SWS_PLL=rRCC_CFGR & (0x03<<2);//读出bit2-bit3faultTime++;led_init();//0x02<<2:表示此时转换成PLL}while ((faultTime<0x0FFFFFFF) && (RCC_CF_SWS_PLL!=(0x02<<2)));//十一、此时PLL转换成功if((rRCC_CFGR & (0x03<<2))==(0x02<<2)){//到这里我们的时钟整个就设置好了,可以结束了}else{//到这里说明PLL输出作为PLL失败while(1);}}else{//到这里说明PLL启动时出错了,PLL不能稳定工作while(1);}}else{//超时,或者未准备好,此时HSE不可以使用while(1);}}

2.自己封装一个RCC_WaitForPLLStartUp

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

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

#define PLL_STARTUP_TIMEOUT   ((uint16_t)0x0500000)//本函数作用:等待PLL倍频后输出稳定
//返回值:SUCCESS说明未超时,ERROR超时
ErrorStatus RCC_WaitForPLLStartUp(void)
{__IO uint32_t StartUpCounter = 0;ErrorStatus status = ERROR;FlagStatus PLLStatus = RESET;/* Wait till HSE is ready and if Time out is reached exit */do{//读取寄存器的值PLLStatus = RCC_GetFlagStatus(RCC_FLAG_PLLRDY);StartUpCounter++;  //读取是否超时的} while((StartUpCounter != PLL_STARTUP_TIMEOUT) && (PLLStatus == RESET));//这里判断是防止超时if (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) != RESET){status = SUCCESS;}else{//超时status = ERROR;}  return (status);
}

3.完整使用库函数的clock


//这个函数里面包含了全部外设头文件
#include "stm32f10x.h"
//等价于
//#include"stm32f10x_conf.h"#define PLL_STARTUP_TIMEOUT   ((uint16_t)0x0500000)//本函数作用:等待PLL倍频后输出稳定
//返回值:SUCCESS说明未超时,ERROR超时
ErrorStatus RCC_WaitForPLLStartUp(void)
{__IO uint32_t StartUpCounter = 0;ErrorStatus status = ERROR;FlagStatus PLLStatus = RESET;/* Wait till HSE is ready and if Time out is reached exit */do{//读取寄存器的值PLLStatus = RCC_GetFlagStatus(RCC_FLAG_PLLRDY);StartUpCounter++;  //读取是否超时的} while((StartUpCounter != PLL_STARTUP_TIMEOUT) && (PLLStatus == RESET));//这里判断是防止超时if (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) != RESET){status = SUCCESS;}else{//超时status = ERROR;}  return (status);
}void Set_SysClockTo72M(void){//接收判断回来的HSE是否已经稳定ErrorStatus sta=ERROR;//faultTime:用来判断是否超时unsigned int faultTime=0;unsigned int RCC_CF_SWS_PLL=0;//一、先关闭HSEON然后在打开HSEONRCC_HSEConfig(RCC_HSE_ON);/*rRCC_CR = 0x00000083;rRCC_CR &= ~(1<<16);//关闭HSEONrRCC_CR |= (1<<16);//打开HSEON,让HSE开始工作*///二、等到HSE稳定sta=RCC_WaitForHSEStartUp();/*do{//检测HSEREAY(bit17)是否为1,1表示准备好Rcc_CR_HSE_Ready=rRCC_CR&(1<<17);//取出bit17faultTime++;}while((faultTime<0x0fffffff) && (Rcc_CR_HSE_Ready==0));//跳出do-while 1)要么超时2)要么准好了*///三、判断是HSE稳定了还是超时了if(sta==SUCCESS)//if((rRCC_CR&(1<<17))!=0)//rRCC_CR&(1<<17)==1{//这里HSE就ready,下面再去配置PLL并且等待他ready//四、设置FlashFLASH->ACR |= 0x10;FLASH->ACR  &= (~0x03);FLASH->ACR  |= (0x02);/*rFLASH_ACR |= 0x10;rFLASH_ACR &= (~0x03);rFLASH_ACR |= (0x02);*///AHB和APB2未分频,APB1被2分频//所以最终:AHB和APB2都是72MHZ,APB1是36MHZ//五、配置相关的倍频信息//配置HCLK为SYSCLK/1RCC_HCLKConfig(RCC_SYSCLK_Div1);//配置PCLK1为JCLK的2分频RCC_PCLK1Config(RCC_HCLK_Div2);//配置PCLK2为JCLK的1分频RCC_PCLK2Config(RCC_HCLK_Div1);/*rRCC_CFGR &=(~((0x0f<<4) | (0x07<<8) | (0x07<<11)));//等价于:rRCC_CFGR=(~(0x3ff<<4));rRCC_CFGR |=((0x0<<4) | (0x04<<8) | (0x0<<11));*///六、设置HSE/1为PLL时钟源,PLL倍频系数为9RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);/*//设置SHE为输入时钟,同时HSE不分频rRCC_CFGR &=(~((1<<16) | (1<<17)));rRCC_CFGR |= ((1<<16) | (0<<17));//设置PLL倍频系数//9分频:0111:0x07rRCC_CFGR &=(~(0x0f<<18));//清零bit18-bit21rRCC_CFGR |= (0x07<<18);//设置为9倍频*///七、打开PLL开关RCC_PLLCmd(ENABLE);//rRCC_CR |= (1<<24);//因为HAL库中没有等到PLL的函数//此处我们参考【RCC_WaitForHSEStartUp】这个函数来自己写//八、等待开启PLL开启成功sta=RCC_WaitForPLLStartUp();/*//因为前面已经使用到,被累加了,使用这里要重新置0faultTime=0;do{led_init();Rcc_CR_PLL_Ready=rRCC_CR & (1<<25);//检测第25位是否为1faultTime++;}while((faultTime<0x0fffffff) && (Rcc_CR_PLL_Ready==0));*///九、判断PLL稳定还是超时//if((rRCC_CR & (1<<25)) == (1<<25)){if(sta==SUCCESS){//到这里说明PLL已经稳定,可以用了,下面可以切换成外部时钟了//九、切换成PLLRCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);/*rRCC_CFGR &=(~(0x03)<<0);rRCC_CFGR |=(0x02<<0);*/	//十、判断切换成PLL是否成功//因为前面已经使用到,被累加了,使用这里要重新置0faultTime=0;do{RCC_CF_SWS_PLL=RCC->CFGR & (0x03<<2);//读出bit2-bit3faultTime++;//0x02<<2:表示此时转换成PLL}while ((faultTime<0x0FFFFFFF) && (RCC_CF_SWS_PLL!=(0x02<<2)));//十一、此时PLL转换成功if((RCC->CFGR  & (0x03<<2))==(0x02<<2)){//到这里我们的时钟整个就设置好了,可以结束了}else{//到这里说明PLL输出作为PLL失败while(1);}}else{//到这里说明PLL启动时出错了,PLL不能稳定工作while(1);}}else{//超时,或者未准备好,此时HSE不可以使用while(1);}}

 

#include "stm32f10x.h"
#include "clock.h"
/**使用标准库重写RCC模块
*/void delay();
void led_init();
void led_flash(void);void led_init(){//因为RCC部分还没有定义结构体,所以还是按照原来的方式去操作RCC->APB2ENR = 0x00000008;GPIOB->CRH=0x33333333;GPIOB->ODR=0x00000000;
}void delay(){unsigned int i=0,j=0;for(i=0;i<1000;i++){for(j=0;j<2000;j++){}}
}
void led_flash(void){unsigned int i=0;for(i=0;i<3;i++){GPIOB->ODR = 0x00000000;//全亮delay();GPIOB->ODR = 0x0000ff00;//全灭delay();} 
}int main(){led_init();led_flash();Set_SysClockTo72M();led_flash();return 0;
}

6.SystmInit注意点:

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/119042.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Centos使用tomcat部署jenkins

jenkins的最新版本已经不在支持jdk8&#xff0c;支持的jdk环境如下&#xff1a; 安装jdk环境 yum -y install java-11-openjdk.x86_64 java-11-openjdk-devel.x86_64安装tomcat tomcat官网 cd /optwget https://dlcdn.apache.org/tomcat/tomcat-9/v9.0.82/bin/apache-tomcat…

【项目管理】如何开展高质量的团队管理

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

0026Java程序设计-中学走读生信息管理系统设计与实现

文章目录 摘要**目录**系统设计开发环境 摘要 目前&#xff0c;中学走读生信息管理系统已经发展成为学校的学生走读管理工作中必不可少的一个组成部分&#xff0c;没有该系统&#xff0c;学生的日常工作就会变得繁琐、效率低下。在信息化的社会发展下&#xff0c;有必要建立一…

【VPX610】 青翼科技基于6U VPX总线架构的高性能实时信号处理平台

板卡概述 VPX610是一款基于6U VPX架构的高性能实时信号处理平台&#xff0c;该平台采用2片TI的KeyStone系列多核DSP TMS320C6678作为主处理单元&#xff0c;采用1片Xilinx的Virtex-7系列FPGA XC7VX690T作为协处理单元&#xff0c;具有2个FMC子卡接口&#xff0c;各个处理节点之…

成功率高达99%!美国伊利诺伊大学研究人员实现镱量子比特无损测量

研究人员通过无损测量镱-171量子比特实现了实时控制。&#xff08;图片来源&#xff1a;网络&#xff09; 金属镱-171原子可能在自然界中最接近完美量子比特。最近的一项研究展示了如何使用它们来进行重复的量子测量和量子比特自旋&#xff0c;这一研究成果将有助于可扩展量子…

蓝桥云课--1024 第 2 场算法双周赛

2-铺地板【算法赛】&#xff08;找规律&#xff09; 一、题目要求 二、思路 &#xff08;1&#xff09;因为每块地砖都是2*3的规格&#xff1a; 1.n<2或者m<2的时候&#xff0c;则不能使用上述规格的瓷砖 No 2.n<3或者m<3的时候&#xff0c;也不能使用上述规格…

30天精通Nodejs--第二天:模块系统与npm

深入了解Node.js&#xff1a;模块系统与npm Node.js作为一款强大的服务器端JavaScript运行环境&#xff0c;模块系统和npm&#xff08;Node Package Manager&#xff09;是其成功的重要组成部分。为我们平时提供了便捷的工具和资源&#xff0c;使得在Node.js平台上构建应用变得…

现在java和大数据选什么?

现在java和大数据选什么&#xff1f; 到底是选择大数据还是JAVA&#xff1f;”相信这个问题困惑着许多转行待定人士和高校专业待选的学生。 在普通人眼里可能会觉得这两个专业或者行业没啥区别&#xff0c;都是IT里的&#xff0c;能有啥大不同。这是第一层。最近很多小伙伴找我…

【Linux】MAC帧协议 + ARP协议

文章目录 &#x1f4d6; 前言1. 数据链路层2. MAC帧格式3. 再谈局域网4. ARP协议4.1 路由器的转发过程&#xff1a;4.2 ARP协议格式&#xff1a; 5. 如何获得目的MAC地址 &#x1f4d6; 前言 在学完网络层IP协议之后&#xff0c;本章我们将继续向下沉一层&#xff0c;进入到数…

深入浅出排序算法之希尔排序

目录 1. 原理 2. 代码实现 3. 性能分析 1. 原理 希尔排序法又称缩小增量法。希尔排序法的基本思想是&#xff1a;先选定一个整数&#xff0c;把待排序文件中所有记录分成个组&#xff0c;所有距离为的记录分在同一组内&#xff0c;并对每一组内的记录进行排序。然后&#xf…

详解预处理(1)

目录 预定义符号 预处理指令#define #define定义符号 #define定义宏 #define替换规则 #和##&#xff08;C语言预处理操作符&#xff09; # ## 带副作用的宏参数 宏和函数的对比 命名约定 在之前我们学习了一个文本文件.c生成一个可执行程序。今天我们详细讲解其中的…

01 # 手写 new 的原理

new 做了什么? 在构造器内部创建一个新的对象这个对象内部的隐式原型指向该构造函数的显式原型让构造器中的 this 指向这个对象执行构造器中的代码如果构造器中没有返回对象&#xff0c;则返回上面的创建出来的对象 手写 new 的过程 new 是一个运算符&#xff0c;只能通过函…

CSS隐藏元素的N种方法,你知道哪一种最适合你?

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 一、前…

Camtasia2024永久激活码

真的要被录屏软件给搞疯了&#xff0c;本来公司说要给新人做个培训视频&#xff0c;想着把视频录屏一下&#xff0c;然后简单的剪辑一下就可以了。可谁知道录屏软件坑这么多&#xff0c;弄来弄去头都秃了&#xff0c;不过在头秃了几天之后&#xff0c;终于让我发现了一个值得“…

【Linux】gdb调试

目录 进入调试查看代码运行代码断点打断点查断点删断点从一个断点转跳至下一个断点保留断点但不会运行该断点 退出调试逐过程逐语句监视跳转至指定行运行结束当前函数 进入调试 指令&#xff1a;gdb 【可执行文件】&#xff1a; 查看代码 &#xff1a;l 【第几行】如果输入指…

安全设备

一.防火墙 5层应用层 防火墙 4层 udp tcp 协议 华为 厂商 华为 h3 1.区域划分 Dmz 停火区 Untrust 不安全区域 Trust 安全区域 防火墙 默认禁止所有 二.Waf Web 应用防火墙 放到web前面 产品 雷池 绿盟 软件 安…

递归神经网络 (RNN)

弗朗西斯科佛朗哥 一、说明 循环神经网络非常有趣&#xff0c;因为与前馈网络不同&#xff0c;在前馈网络中&#xff0c;数据只能在一个方向上传播&#xff0c;每个神经元可以与连续层的一个或多个神经元连接&#xff0c;在这种类型的网络中&#xff0c;神经元还可以环回自身或…

安卓端GB28181设备接入模块如何实现实时位置订阅(MobilePosition)

技术背景 实时位置&#xff08;MobilePosition&#xff09;订阅和上报&#xff0c;对GB28281设备接入终端尤其重要&#xff0c;如移动单兵设备、执法记录仪、智能安全帽、车载终端等&#xff0c;Android国标接入设备通过获取到实时经纬度信息&#xff0c;按照一定的间隔上报到…

竞赛选题 深度学习卫星遥感图像检测与识别 -opencv python 目标检测

文章目录 0 前言1 课题背景2 实现效果3 Yolov5算法4 数据处理和训练5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **深度学习卫星遥感图像检测与识别 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐…