固件库应用之使用HSE / HSI配置时钟

文章目录

1.基础知识

1.1 RCC是什么

RCC : reset clock control 复位和时钟控制器。

1.2 RCC框图分析

固件库应用之使用HSE / HSI配置时钟
以上分析会需要较大篇幅,故此处引用他人的回答(记得给他们点赞噢):RCC简介

2. SetSysClockTo72函数分析

SetSysClockTo72函数分析

3. 编程步骤

  1. 开启 HSE/HSI ,并等待 HSE/HSI 稳定
  2. 设置 AHB、APB2、APB1 的预分频因子
  3. 设置 PLL 的时钟来源,和 PLL 的倍频因子,设置各种频率主要就是在这里设置
  4. 开启 PLL,并等待 PLL 稳定
  5. 把 PLLCK 切换为系统时钟 SYSCLK
  6. 读取时钟切换状态位,确保 PLLCLK 被选为系统时钟

此步骤与SetSysClockTo72函数执行步骤基本一致。

4. 使用的固件库函数

4.1 RCC_HSEConfig函数

配置 HSE

/**
  * @brief  Configures the External High Speed oscillator (HSE).
		简介:  配置 HSE
  * @note   HSE can not be stopped if it is used directly or through the PLL as system clock.
		注意:  如果直接或通过PLL作为系统时钟使用,HSE无法停止。
  * @param  RCC_HSE: specifies the new state of the HSE.
		参数1 :RCC_HSE: 指定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
														 通过外部时钟绕过HSE
  * @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 ------------------*/
	/* 在配置HSE之前,重置HSEON和HSEBYP位 */
	/* 此处可参考时钟控制寄存器(RCC_CR) */
	
  /* 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:
      break;
  }
}

4.2 RCC_WaitForHSEStartUp函数

等待HSE启动完毕

/**
  * @brief  Waits for HSE start-up.
    简介:  等待HSE启动完毕
  * @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.3 RCC_HCLKConfig函数

配置AHB

/**
  * @brief  Configures the AHB clock (HCLK).
		简介:  配置 AHB 时钟
  * @param  RCC_SYSCLK: defines the AHB clock divider. This clock is derived from 
  *   the system clock (SYSCLK).
		参数:  RCC_SYSCLK:定义AHB时钟分频器。该时钟源于系统时钟(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 */
  tmpreg &= CFGR_HPRE_Reset_Mask;
  /* Set HPRE[3:0] bits according to RCC_SYSCLK value */
  tmpreg |= RCC_SYSCLK;
  /* Store the new value */
  RCC->CFGR = tmpreg;
}

4.4 RCC_PCLK2Config函数

配置APB2

/**
  * @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;
}

4.5 RCC_PCLK1Config 函数

配置APB1

/**
  * @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;
}

4.6 RCC_PLLConfig 函数

配置PLL时钟源和乘法因子。

/**
  * @brief  Configures the PLL clock source and multiplication factor.
		简介:  配置PLL时钟源和乘法因子。
  * @note   This function must be used only when the PLL is disabled.
		注意:  只有当PLL失能时,才能使用此功能。
  * @param  RCC_PLLSource: specifies the PLL entry clock source.
		参数1: RCC_PLLSource: 指定PLL输入时钟源。
  *   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
																		(PLL = HSI / 2)
  *     @arg RCC_PLLSource_PREDIV1: PREDIV1 clock selected as PLL clock entry
																		(PLL = HSI / 1)
  *   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 
																		 (PLL = HSI / 2)
  *     @arg RCC_PLLSource_HSE_Div1: HSE oscillator clock selected as PLL clock entry
																		(PLL = HSE / 1)
  *     @arg RCC_PLLSource_HSE_Div2: HSE oscillator clock divided by 2 selected as PLL clock entry
																		(PLL = HSE / 2)
																		
  * @param  RCC_PLLMul: specifies the PLL multiplication factor.
		参数2: RCC_PLLMul: 指定PLL乘法因子。
  *   For @b STM32_Connectivity_line_devices, this parameter can be RCC_PLLMul_x where x:{[4,9], 6_5}
		形参可以为:RCC_PLLMul_x , x:{[4,9], 6_5}
  *   For @b other_STM32_devices, this parameter can be RCC_PLLMul_x where x:[2,16]  
		形参可以为:RCC_PLLMul_x , 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;
  /* Clear PLLSRC, PLLXTPRE and PLLMUL[3:0] bits */
  tmpreg &= CFGR_PLL_Mask;
  /* Set the PLL configuration bits */
  tmpreg |= RCC_PLLSource | RCC_PLLMul;
  /* Store the new value */
  RCC->CFGR = tmpreg;
}

4.7 RCC_PLLCmd 函数

使能或失能PLL

/**
  * @brief  Enables or disables the PLL.
		简介:  使能或失能PLL
  * @note   The PLL can not be disabled if it is used as system clock.
  * @param  NewState: new state of the PLL. This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void RCC_PLLCmd(FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_FUNCTIONAL_STATE(NewState));

  *(__IO uint32_t *) CR_PLLON_BB = (uint32_t)NewState;
}

4.8 RCC_GetFlagStatus 函数

检查是否设置了指定的RCC标志

/**
  * @brief  Checks whether the specified RCC flag is set or not.
		简介:  检查是否设置了指定的RCC标志。
  * @param  RCC_FLAG: specifies the flag to check.
  * 参数:  RCC_FLAG: 指定要检查的标志。  
  *   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).
		返回值: 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 */
  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 */
  tmp = RCC_FLAG & FLAG_Mask;
  if ((statusreg & ((uint32_t)1 << tmp)) != (uint32_t)RESET)
  {
    bitstatus = SET;
  }
  else
  {
    bitstatus = RESET;
  }

  /* Return the flag status */
  return bitstatus;
}

4.9 RCC_SYSCLKConfig 函数

配置系统时钟

/**
  * @brief  Configures the system clock (SYSCLK).
		简介:  配置系统时钟 (SYSCLK) 。
  * @param  RCC_SYSCLKSource: specifies the clock source used as system clock.
		参数:  RCC_SYSCLKSource: 指定用作系统时钟的时钟源。
  *   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;
  /* Set SW[1:0] bits according to RCC_SYSCLKSource value */
  tmpreg |= RCC_SYSCLKSource;
  /* Store the new value */
  RCC->CFGR = tmpreg;
}

4.10 RCC_GetSYSCLKSource 函数

查看系统时钟的时钟源

/**
  * @brief  Returns the clock source used as system clock.
		简介:  返回用作系统时钟的时钟源。
  * @param  None( 无参数 )
  * @retval The clock source used as system clock. 
		返回用作系统时钟的时钟源
	* The returned value can be one of the following:
				( 返回值示例如下:)
  *     - 0x00: HSI used as system clock
  *     - 0x04: HSE used as system clock
  *     - 0x08: PLL used as system clock
  */
uint8_t RCC_GetSYSCLKSource(void)
{
  return ((uint8_t)(RCC->CFGR & CFGR_SWS_Mask));
}

5. 整体代码解析


#define IS_RCC_HSE(HSE) (((HSE) == RCC_HSE_OFF) || ((HSE) == RCC_HSE_ON) || \
                         ((HSE) == RCC_HSE_Bypass))

/* 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)


#define  RCC_CR_HSERDY                       ((uint32_t)0x00020000)        /*!< External High Speed clock ready flag */
																																						/* 标志HSE启动完成 */
#define HSE_STARTUP_TIMEOUT   ((uint16_t)0x0500) /*!< Time out for HSE start up */
																									/* HSE启动暂停 */


void HSE_SetSysClock(uint32_t pllmul)
 { __IO uint32_t StartUpCounter = 0, HSEStartUpStatus = 0; 45 // 把 RCC 外设初始化成复位状态
 RCC_DeInit();
 //使能 HSE,开启外部晶振,野火 STM32F103 系列开发板用的是 8M
 RCC_HSEConfig(RCC_HSE_ON);

 // 等待 HSE 启动稳定
 HSEStartUpStatus = RCC_WaitForHSEStartUp();

 // 只有 HSE 稳定之后则继续往下执行
 if (HSEStartUpStatus == SUCCESS) {
 //-----------------------------------------------------------------//
 // 这两句是操作 FLASH 闪存用到的,如果不操作 FLASH,这两个注释掉也没影响
 // 使能 FLASH 预存取缓冲区
 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

 // SYSCLK 周期与闪存访问时间的比例设置,这里统一设置成 2
 // 设置成 2 的时候,SYSCLK 低于 48M 也可以工作,如果设置成 0 或者 1 的时候,
// 如果配置的 SYSCLK 超出了范围的话,则会进入硬件错误,程序就死了
// 0:0 < SYSCLK <= 24M
// 1:24< SYSCLK <= 48M
// 2:48< SYSCLK <= 72M
FLASH_SetLatency(FLASH_Latency_2);
//-----------------------------------------------------------------//

// AHB 预分频因子设置为 1 分频,HCLK = SYSCLK
RCC_HCLKConfig(RCC_SYSCLK_Div1);

// APB2 预分频因子设置为 1 分频,PCLK2 = HCLK
RCC_PCLK2Config(RCC_HCLK_Div1);

// APB1 预分频因子设置为 1 分频,PCLK1 = HCLK/2
RCC_PCLK1Config(RCC_HCLK_Div2);

//-----------------设置各种频率主要就是在这里设置-------------------//
// 设置 PLL 时钟来源为 HSE,设置 PLL 倍频因子
// PLLCLK = 8MHz * pllmul
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, pllmul);
//-------------------------------------------------------------//

// 开启 PLL
RCC_PLLCmd(ENABLE);

// 等待 PLL 稳定
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) { }

// 当 PLL 稳定之后,把 PLL 时钟切换为系统时钟 SYSCLK
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
// 读取时钟切换状态位,确保 PLLCLK 被选为系统时钟
while (RCC_GetSYSCLKSource() != 0x08) { }
	} 
 else {
// 如果 HSE 开启失败,那么程序就会来到这里,用户可在这里添加出错的代码处理
// 当 HSE 开启失败或者故障的时候,单片机会自动把 HSI 设置为系统时钟,
// HSI 是内部的高速时钟,8MHZ
while (1) { }
				}
}
上一篇:蒙特卡罗算法


下一篇:大数据时代下的领导力 — 释放人性 毋庸置疑