【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);}}
6.SystmInit注意点:
我们在“startup_stm32f10x_md.s”文件中可以看到在执行main函数之前会先执行一个“SystemInit”函数
所以如果我们想要使用自己的设置72MHZ频率的函数,则应该将SystemInit注释调。
相关文章:

【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…...

WPF中的绑定知识详解(含案例源码分享)
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...

【JVM】类的生命周期
【JVM】类的生命周期 文章目录 【JVM】类的生命周期1. 生命周期概述2. 加载阶段3. 连接阶段3.1 验证3.2 准备3.3 解析 4. 初始化阶段4.1 触发初始化的方式4.2 clinit不存在的情况4.3 多个类的初始化 5. 总结 1. 生命周期概述 类的生命周期分为5/7个阶段: 加载(Loa…...

asp.net网上商城系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio协同过滤设计
一、源码特点 asp.net网上商城系统是一套完善的web设计管理系统系统采用协同过滤算法进行商品推荐,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为vs2010,数据库 为sqlserver2008,使用c#语言开发 ASP…...

APUS入驻百度灵境矩阵,普惠AI大模型插件能力
10月17日,APUS出席百度世界大会2023。会上,百度公布了灵境矩阵业务进展,APUS作为灵境矩阵首批合作伙伴正与百度携手拓展大模型能力边界、构建大模型应用生态。 百度认为,大模型将繁荣AI应用生态,在生态搭建过程中&…...
通过C++调用Com接口
头文件 #include <iostream> #include <Windows.h> #include <comdef.h> #include <rpcdce.h> using namespace std; #pragma comment(lib, "Rpcrt4.lib")72C24DD5-D70A-438B-8A42-98424B88AFB8 通过Wscript.Shell来创建进程: void Wscri…...

完全背包问题
目录 1. 朴素解法 2. 优化 原题链接: 3. 完全背包问题 - AcWing题库 题目描述: 有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。 第 i 种物品的体积是 vi,价值是 wi。 求解将哪些物品装入背包,可使这些…...

J2EE的N层体系结构
J2EE平台采用了多层分布式应用程序模型,实现不同逻辑功能的应用程序被封装到不同的构件中,处于不同层次的构件可被分别部署到不同的机器中。 RMI/IIOP:RMI(Remote Method Invocation,远程方法调用)是Java的…...

Quirks(怪癖)模式是什么?它和 Standards(标准)模式有什么区别?
目录 前言: 用法: 代码: Quirks模式示例: Standards模式示例: 理解: Quirks模式: Standards模式: 高质量讨论: 前言: "Quirks模式"和"Standards模式"是与HTML文档渲染模式相关的两种模式。它们影响着浏览器如何解释和渲染HT…...

自然语言处理---Transformer模型
Transformer概述 相比LSTM和GRU模型,Transformer模型有两个显著的优势: Transformer能够利用分布式GPU进行并行训练,提升模型训练效率。 在分析预测更长的文本时,捕捉间隔较长的语义关联效果更好。 Transformer模型的作用 基于seq…...

动画系统的前世今生(一)
掐指一算,五年没更新过我的CSDN账号啦,方向也从人工智能变成了计算机图形学,当然也依旧会关注AI的发展,之前在知乎上写了一些文章[传送门],后续也会逐渐同步到CSDN上~ 这个系列将包含五篇文章,内…...

11 结构型模式- 代理模式
结构性模式一共包括七种: 代理模式、桥接模式、装饰者模式、适配器模式、门面(外观)模式、组合模式、和享元模式。 1 代理模式介绍 软件开发中的代理: 代理模式中引入了一个新的代理对象,代理对象在客户端对象和目标对象之间起到了中介的作用,它去掉客…...

Unity--用户界面
目录 “使用工具栏”: “层次结构”窗口: 层次结构窗口 制作子GameObject “游戏”视图: “场景视图“: ”项目窗口“: 项目窗口工具栏: "Inspector" 窗口: Inspector 游戏…...

BUUCTF 乌镇峰会种图 1
BUUCTF:https://buuoj.cn/challenges 题目描述: 乌镇互联网大会召开了,各国巨头汇聚一堂,他们的照片里隐藏着什么信息呢?(答案格式:flag{答案},只需提交答案࿰…...

Runner GoUI自动化测试发布
构建自动化测试体系是当下每个项目团队愿意去做的,自动化测试减少重复操作节省人力成本。 RunnerGo UI自动化平台 RunnerGo提供从API管理到API性能再到可视化的API自动化、UI自动化测试功能模块,覆盖了整个产品测试周期。 RunnerGo UI自动化基于Selen…...

【Gensim概念】03/3 NLP玩转 word2vec
第三部分 对象函数 八 word2vec对象函数 该对象本质上包含单词和嵌入之间的映射。训练后,可以直接使用它以各种方式查询这些嵌入。有关示例,请参阅模块级别文档字符串。 类型 KeyedVectors 1) add_lifecycle_event(event_name, log_level2…...

【网络协议】聊聊网络路由相关算法
如何配置路由 路由器是一台网络设备,多张网卡,当一个入口的网络包到达路由器时,会根据本地的信息库决定如何正确的转发流量,通常称为路由表 路由表主要包含如下 核心思想是根据目的 IP 地址来配置路由 目的网络:要去…...

Python 深度学习入门之CNN
CNN 前言一、CNN简介1、简介2、结构 二、CNN简介1、输出层2、卷积层3、池化层4、全连接层5、输出层 前言 1024快乐!1024快乐!今天开新坑,学点深度学习相关的,说下比较火的CNN。 一、CNN简介 1、简介 CNN的全称是Convolutiona…...

国产开发板上打造开源ThingsBoard工业网关--基于米尔芯驰MYD-JD9X开发板
本篇测评由面包板论坛的优秀测评者“JerryZhen”提供。 本文将介绍基于米尔电子MYD-JD9X开发板打造成开源的Thingsboard网关。 Thingsboard网关是一个开源的软件网关,采用python作为开发语言,可以部署在任何支持 python 运行环境的主机上,灵…...

英语——语法——从句——名词性从句——笔记
文章目录 名词性从句一、定义二、分类(一)宾语从句(二)主语从句(三)C同位语从句(四)D表语从句 名词性从句 一、句子成分 简而言之,构成一个句子的成分(或要素…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
Neo4j 集群管理:原理、技术与最佳实践深度解析
Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...

蓝桥杯3498 01串的熵
问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798, 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...

群晖NAS如何在虚拟机创建飞牛NAS
套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...