固件库应用之使用HSE / HSI配置时钟
作者:互联网
文章目录
1.基础知识
1.1 RCC是什么
RCC : reset clock control 复位和时钟控制器。
1.2 RCC框图分析
以上分析会需要较大篇幅,故此处引用他人的回答(记得给他们点赞噢):RCC简介
2. SetSysClockTo72函数分析
3. 编程步骤
- 开启 HSE/HSI ,并等待 HSE/HSI 稳定
- 设置 AHB、APB2、APB1 的预分频因子
- 设置 PLL 的时钟来源,和 PLL 的倍频因子,设置各种频率主要就是在这里设置
- 开启 PLL,并等待 PLL 稳定
- 把 PLLCK 切换为系统时钟 SYSCLK
- 读取时钟切换状态位,确保 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