如何设置STM32的系统时钟(SYSCLK)

目录

数字可视化

1、STM32F407 的时钟来源

CPUProfiler

1.1、HSI 时钟

分页

1.2、HSE 时钟

云计算

1.3、主 PLL 时钟

inputmode

2、时钟树

javac

3、配置系统时钟

Kubectl

3.1、系统时钟有关寄存器

内存管理

3.2、使用系统的默认配置

JIT

3.3、系统时钟配置所用到的相关宏定义

shell入门到精通

3.4、SystemInit( )函数

移动端自动化测试实战

3.5、SetSysClock( )函数

新手教程

3.6、自行配置时钟

vue项目运行出现问题


状态栏

        对于STM32这款单片机,现在是越来越多的人熟悉和使用它了。在很多的项目和产品中都有它的身影,以及现在很多的大学课程都是用STM32开展教学了,已经是应用很广泛了。

百万年薪

        想当初我在大学的时候,上课教的还是51单片机,而且还是老师照着课本念的。当时做的第一个单片机产品还是用51单片机做的流水灯,哈哈!

数据库开发

        那么,在使用STM32单片机进行项目开发的时候,第一步都是要做好时钟的设置的。这个时钟的设置是非常重要的,因为它关系到整个系统的运行。不同的项目都会根据实际的使用需求,采用不同的时钟频率,所以需要对时钟进行设置。

代码管理

        下面分享一下STM32设置时钟的操作方法和步骤。本文以STM32F407为例讲讲时钟配置!

u3d微信小游戏

Designer

1、STM32F407 的时钟来源

        从STM32F4的参考手册上可以看到,STM32F407的时钟可以有三种时钟来源,如下图:

app自动化测试

Java并发编程

 

二层交换机

时间复杂度

这几个时钟区别分别如下:

网络原理

1.1、HSI 时钟

        HSI 时钟信号由STM32内部 16 MHz 的RC 振荡器生成,可直接用作系统时钟,或者用作 PLL 输入。

Go刷题

        因为它是内部的集成RC振荡器,不需要额外的外部晶振和电路,所以使用它的话成本就比较低。但是它的精度相比外部的晶振或者陶瓷谐振器,精度是比不上的,所以一般都不用这个作为系统的主时钟来源。

1.2、HSE 时钟

HSE 时钟指的是来源于外部晶振的时钟源。它一般可以由两个时钟源来提供:

(1)HSE 外部晶振/陶瓷谐振器

(2)HSE 外部时钟(比如:8M、25M)

参见下图:

 

1.3、主 PLL 时钟

STM32F4xx 器件具有两个 PLL:

(1)主 PLL (PLL) 由 HSE 或 HSI 振荡器提供时钟信号,并具有两个不同的输出时钟:

        1)第一个输出用于生成高速系统时钟(最高达 168 MHz)

        2)第二个输出用于生成 USB OTG FS 的时钟 (48 MHz)、随机数发生器的时钟 (48 MHz) 和 SDIO 时钟 (48 MHz)。

(2)专用 PLL (PLLI2S) 用于生成精确时钟,从而在 I2S 接口实现高品质音频性能。

        注意:在系统复位后,默认系统时钟为 HSI。在直接使用 HSI 或者通过 PLL 使用时钟源来作为系统时钟时,该时钟源无法停止。

2、时钟树

STM2F4的时钟树如下图所示:

        从上图中可以看到,系统的时钟来源可以通过选择器选择,然后通过预分频器配置 AHB 频率、高速 APB (APB2) 和低速 APB (APB1)。

        其中,AHB 域的最 大频率为 168 MHz,高速 APB2 域的最大允许频率为 84 MHz,低速 APB1 域的最大允许频 率为 42 MHz。不同的时钟分给不同的外设使用,从而满足整个系统的各个外设的正常工作所需的时钟条件。

3、配置系统时钟

3.1、系统时钟有关寄存器

        由于STM32系统复位之后默认使用的是HSI时钟,所以需要切换为其他时钟的话就需要自己做些配置,也就是需要设置相应的寄存器,从而切换时钟的输入来源。

        STM32F4切换时钟所涉及到的寄存器如下面所示:

(1)RCC 时钟配置寄存器 (RCC_CFGR) 

        通过 RCC_CFGR 的 SW1、SW2两位进行设置,这两位的选项取值如下:

 

(2)RCC 时钟控制寄存器 (RCC_CR)

        通过这三个位的置位可以选择使用的时钟,操作如下:

3.2、使用系统的默认配置

        配置系统的时钟,除了使用相关寄存器进行设置,也可以使用官方提供的固件文件里面的初始化函数进行修改,即可以完成时钟的修改和设置。

        首先,有一个差异我们要知道的:STM32F4 与 STM32F10X 有所不同,STM32F4 的时钟已经默认配置好,上电直接可以正常使用。

        通过查看启动代码文件:startup_stm32f4xx.s,即可以看出。如下:

Reset handler  
Reset_Handler    PROC  
                 EXPORT  Reset_Handler             [WEAK]  
        IMPORT  SystemInit  
        IMPORT  __main  

                 LDR     R0, =SystemInit  
                 BLX     R0  
                 LDR     R0, =__main  
                 BX      R0  
                 ENDP

可以看出:

在进入main函数之前,系统调用了SystemInit函数.

3.3、系统时钟配置所用到的相关宏定义

        system_stm32f4xx.c文件中提供几个宏定义用于设置时钟参数,如下:

/************************* PLL Parameters *************************************/  
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */  
#define PLL_M      25  
#define PLL_N      336  
/* SYSCLK = PLL_VCO / PLL_P */  
#define PLL_P      2  
/* USB OTG FS, SDIO and RNG Clock =  PLL_VCO / PLLQ */  
#define PLL_Q      7  
/******************************************************************************/

        晶振频率设置则是在文件 stm32f4xx.h 中进行设置:

1)外部晶振:

#if !defined  (HSE_VALUE)   
  #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */  

        HSE_VALUE:这个值是设置外部晶振的频率的。比如25000000表示的是外部晶振选择的25M。如果外部晶振是8M,那这个值就是8000000。以此类推!

2)内部晶振:

#if !defined  (HSI_VALUE)     
  #define HSI_VALUE    ((uint32_t)16000000) /*!< Value of the Internal oscillator in Hz*/  
#endif /* HSI_VALUE */ 

        HSI_VALUE:这个值是设置外部晶振的频率的。

综合上面的,可以得出默认配置中:

锁相环压腔振荡器时钟:PLL_VCO = 25 / 25 * 336 = 336MHz
系统时钟:SYSCLK = 336 / 2 = 168MHz
USB,SD卡时钟:CLK = 336 / 7 = 48MHz

3.4、SystemInit( )函数

/** 
  * @brief  Setup the microcontroller system 
  *         Initialize the Embedded Flash Interface, the PLL and update the  
  *         SystemFrequency variable. 
  * @param  None 
  * @retval None 
  */  
void SystemInit(void)  
{  
  /* FPU settings ------------------------------------------------------------*/  
  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)  
    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  /* set CP10 and CP11 Full Access */  
  #endif  

  /* Reset the RCC clock configuration to the default reset state ------------*/  
  /* Set HSION bit */  
  RCC->CR |= (uint32_t)0x00000001;  

  /* Reset CFGR register */  
  RCC->CFGR = 0x00000000;  

  /* Reset HSEON, CSSON and PLLON bits */  
  RCC->CR &= (uint32_t)0xFEF6FFFF;  

  /* Reset PLLCFGR register */  
  RCC->PLLCFGR = 0x24003010;  

  /* Reset HSEBYP bit */  
  RCC->CR &= (uint32_t)0xFFFBFFFF;  

  /* Disable all interrupts */  
  RCC->CIR = 0x00000000;  

#ifdef DATA_IN_ExtSRAM  
  SystemInit_ExtMemCtl();   
#endif /* DATA_IN_ExtSRAM */  

  /* Configure the System clock source, PLL Multiplier and Divider factors,  
     AHB/APBx prescalers and Flash settings ----------------------------------*/  
  SetSysClock();  

  /* Configure the Vector Table location add offset address ------------------*/  
#ifdef VECT_TAB_SRAM  
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */  
#else  
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */  
#endif  
}

3.5、SetSysClock( )函数

在SetSysClock函数中,配置了系统时钟,PLL倍频以及分频系数:

/** 
  * @brief  Configures the System clock source, PLL Multiplier and Divider factors,  
  *         AHB/APBx prescalers and Flash settings 
  * @Note   This function should be called only once the RCC clock configuration   
  *         is reset to the default reset state (done in SystemInit() function).    
  * @param  None 
  * @retval None 
  */  
static void SetSysClock(void)  
{  
/******************************************************************************/  
/*            PLL (clocked by HSE) used as System clock source                */  
/******************************************************************************/  
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;  

  /* Enable HSE */  
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);  

  /* Wait till HSE is ready and if Time out is reached exit */  
  do  
  {  
    HSEStatus = RCC->CR & RCC_CR_HSERDY;  
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));  

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)  
  {  
    HSEStatus = (uint32_t)0x01;  
  }  
  else  
  {  
    HSEStatus = (uint32_t)0x00;  
  }  

  if (HSEStatus == (uint32_t)0x01)  
  {  
    /* Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz */  
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;  
    PWR->CR |= PWR_CR_VOS;  

    /* HCLK = SYSCLK / 1*/  
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;  

    /* PCLK2 = HCLK / 2*/  
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;  

    /* PCLK1 = HCLK / 4*/  
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;  

    /* Configure the main PLL */  
    RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |   (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);  

    /* Enable the main PLL */  
    RCC->CR |= RCC_CR_PLLON;  

    /* Wait till the main PLL is ready */  
    while((RCC->CR & RCC_CR_PLLRDY) == 0)  
    {  
    }  

    /* Configure Flash prefetch, Instruction cache, Data cache and wait state */  
    FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;  

    /* Select the main PLL as system clock source */  
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));  
    RCC->CFGR |= RCC_CFGR_SW_PLL;  

    /* Wait till the main PLL is used as system clock source */  
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);  
    {  
    }  
  }  
  else  
  {
  /* If HSE fails to startup, the application will have wrong clock configuration. User can add here some code to deal with this error */  
  }  

}

     

如果外部时钟启动失败,系统会使用内部时钟默认配置:
HCLK = SYSCLK / 1 = 168MHz
PCLK2 = HCLK / 2 = 84MHz
PCLK1 = HCLK / 4 = 42MHz

        SystemIint 和 SetSysClock都是官方固件文件中提供的,直接调用即可完成时钟的选择和设置。

3.6、自行配置时钟

        除了可以调用官方提供的时钟设置函数接口外,如果想要自己自行设置相关的时钟操作,也是可以的。

        假设外部晶振25MHz,系统时钟要配置为168MHz,则可以根据自己所选用的外部晶振大小和需要进行配置,相关代码如下:

void RCC_Config(void)
{
    RCC_DeInit();    							//RCC寄存器初始化
    RCC_HSEConfig(RCC_HSE_ON);    				//使用外部时钟
    if(RCC_WaitForHseStartUp() == SUCCESS)     //等待外部时钟启动
    {
        RCC_PLLCmd(DISABLE);    				//配置PLL前应先关闭主PLL
        RCC_SYSCLKConfig(RCC_SYSCLKSOURCE_PLLCLK);     //选择PLL时钟为系统时钟
        RCC_HCLKConfig(RCC_SYSCLK_Div1);    			//HCLK(AHB)时钟为系统时钟1分频
        RCC_PCLK1Config(RCC_HCLK_Div4);   				//PCLK(APB1)时钟为HCLK时钟8分频
        RCC_PCLK2Config(RCC_HCLK_Div2);    			//PCLK(APB2)时钟为HCLK时钟2分频
        RCC_PLLConfig(RCC_PLLSource_HSE,25,336,2,7);   //PLL时钟配置,外部晶振为25MHz,系统配置为168MHz
        RCC_PLLCmd(ENABLE);    //PLL时钟开启
        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);    //等待PLL时钟准备好
    }
}

 

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注