ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2022-01-26 12:58:05  阅读:256  来源: 互联网

标签:clock HSI FLAG arg HSE 固件 PLL RCC


文章目录

1.基础知识

1.1 RCC是什么

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

1.2 RCC框图分析

在这里插入图片描述
以上分析会需要较大篇幅,故此处引用他人的回答(记得给他们点赞噢):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) { }
				}
}

标签:clock,HSI,FLAG,arg,HSE,固件,PLL,RCC
来源: https://blog.csdn.net/m0_51183870/article/details/122677863

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有