1 stm32f4时钟树

1.1 时钟

时钟是具有周期性的脉冲信号,最常用的是占空比50%的方波。我对于时钟的理解是数电里面寄存器的知识,寄存器里数据的刷新也是需要这么一组脉冲信号,所以时钟信号是数字电路的心脏,在驱动着数字电路的数据刷新。因此单片机的运行离不开时钟。 

 1.2 F4的时钟树

1.2.1 时钟树简图分析

下面的简图里的第一个流程图展示了时钟系统的核心。系统时钟最高能达到168MHz,但是HSE和HSI直接作为系统时钟明显达不到最高频率,所以要经过PLL,将HSE或HSI的频率放大,作为系统时钟,而HSE这个外部的时钟源更加稳定,所以如果外部时钟源没有问题就选择外部时钟源。M、N、P、Q的设置要考虑系统时钟和Q对应的外设时钟的要求。

系统时钟经过分频得到HCLK,这个分频系数一般设置为1。这样HCLK的时钟频率就等于系统的时钟频率,而HCLK的时钟频率就是AHB总线的时钟频率,所以AHB总线的最高时钟频率是168MHz,AHB总线的频率经过分频得到APB1和APB2总线的频率。总线APB1和APB2和AHB接了大多数的外设。

第二个流程图是独立看门狗和实时时钟RTC的时钟设置。

1.2.2 时钟树详细图

MCO1和MCO2是外部输出两路时钟

PLL接收的时钟信号经过M分频后,在经过N倍频。之后经过P分频产生PLLP输出,经过Q分频产生PLLQ输出。

                                         AHB、APB1、APB2的时钟

AHB、APB1、APB2的时钟是系统时钟分频得到的,AHB的最大时钟频率等于168MHz,APB2高速时钟最大频率为84MHz,而APB1低速时钟最大频 率为 42MHz。需要注意的是对于定时器时钟,如果所在总线的分频系数(APBx presc)等于1,那APB1的最高速度就是42MHz,如果所在总线的分频系数(APBx presc)不等于1,那APB1的时钟频率会乘2,那么在APB1下的定时器时钟频率最高就是84MHz了,对于APB2下的定时器时钟也是这样。一般情况下APBX PRESC不等于1,而AHBX PRESC一般设置为1。

HCLK到AHB、内核、存储器、和DMA作为它们的时钟。Cortex系统定时器是滴答定时器。FCLK自由运行时钟是用于采样中断和调试模式计时,休眠时仍有效。

其他的外设的时钟配置可以查看手册里的时钟树图片获得。需要注意的是很多时钟输出是带使能控制的,在使用该模块时,要先使能时钟。

1.2.3 Cube MX中F4时钟参数设置

下面是时钟树的参数的常规配置

2 配置系统时钟

2.1系统时钟配置步骤

下面的第一步是设置HSE的晶振频率,第二步是可选的。前两步之前已经学习过了。对于F4只有前四步。

2.2 外设时钟的使能和失能

时钟的功能就好像是一个小开关,你要用什么寄存器就先对应的打开开关,即:使能对应的时钟。比如配置 PWR 寄存器,所以必须先使能 PWR 时钟。

2.3 sys_stm32_clock_init 函数(F4)

正点原子将下面的两个步骤集中在sys.c中的sys_stm32_clock_init 函数里,只要完成这个函数的配置,就完成了下面的两步。

下面的函数是选择要配置的时钟源,并配置PLL,要理解下面的函数,需要结合寄存器映射里利用结构体变量对寄存器映射的知识。下面输入参数表示要输入一个地址,这个地址是结构体变量的首地址,而且将这个地址定义成结构体指针RCC_OscInitStruct,输入参数表示RCC_OscInitTypeDef *RCC_OscInitStruct=输入的地址参数。

下面的函数是选择哪一个时钟源作为系统时钟源,并配置总线分频器,这样就设置好了系统时钟和总线时钟。另外,这个函数含设置了FLASH访问的延时时间,这是因为F4系统时钟比FLASH访问时钟快,所以要设置访问延时。设置延迟访问的长短通过中文手册3.4节的表7和芯片手册67页的表格可以查出来

void Stm32_Clock_Init(u32 plln,u32 pllm,u32 pllp,u32 pllq)
{
    HAL_StatusTypeDef ret = HAL_OK;
    RCC_OscInitTypeDef RCC_OscInitStructure;
//这里定义了第一个函数所需要的结构体变量 
    RCC_ClkInitTypeDef RCC_ClkInitStructure;
//这里定义了第而个函数所需要的结构体变量
    
    __HAL_RCC_PWR_CLK_ENABLE(); 
//使能PWR时钟
    
    //下面这个设置用来设置调压器输出电压级别,以便在器件未以最大频率工作
    //时使性能与功耗实现平衡。
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
//设置调压器输出电压级别1 ,这样系统始终能达到168MHz
    
    RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSE;    
//时钟源为HSE,其他时钟源如果也要相同配置,则用“|”,
//需要注意的是OscillatorType的参数选择什么应该在结构体的定义里面找,
//结构体变量的定义在下个函数里
    RCC_OscInitStructure.HSEState=RCC_HSE_ON;                      
//打开HSE,因为只配置了HSE,所以打开HSE即可
    RCC_OscInitStructure.PLL.PLLState=RCC_PLL_ON;//打开PLL
    RCC_OscInitStructure.PLL.PLLSource=RCC_PLLSOURCE_HSE;//PLL时钟源选择HSE
    RCC_OscInitStructure.PLL.PLLM=pllm; //主PLL和音频PLL分频系数(PLL之前的分频),取值范围:2~63.
    RCC_OscInitStructure.PLL.PLLN=plln; //主PLL倍频系数(PLL倍频),取值范围:64~432.  
    RCC_OscInitStructure.PLL.PLLP=pllp; //系统时钟的主PLL分频系数(PLL之后的分频),取值范围:2,4,6,8.(仅限这4个值!)
    RCC_OscInitStructure.PLL.PLLQ=pllq; //USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频),取值范围:2~15.
    ret=HAL_RCC_OscConfig(&RCC_OscInitStructure);//初始化,我们调用这个函数给的参数是&RCC_OscInitStructure,结合函数的定义,是RCC_OscInitTypeDef  *RCC_OscInitStruc=&RCC_OscInitStructure,即定义了一个结构体指针指向给定的地址
	
    if(ret!=HAL_OK) while(1);
    
    //选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2
    RCC_ClkInitStructure.ClockType=(RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2);
    RCC_ClkInitStructure.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;//设置系统时钟时钟源为PLL
    RCC_ClkInitStructure.AHBCLKDivider=RCC_SYSCLK_DIV1;//AHB分频系数为1
    RCC_ClkInitStructure.APB1CLKDivider=RCC_HCLK_DIV4; //APB1分频系数为4
    RCC_ClkInitStructure.APB2CLKDivider=RCC_HCLK_DIV2; //APB2分频系数为2
    ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_5);//同时设置FLASH延时周期为5WS,也就是6个CPU周期。
		
    if(ret!=HAL_OK) while(1);

	 //STM32F405x/407x/415x/417x Z版本的器件支持预取功能
	if (HAL_GetREVID() == 0x1001)
	{
		__HAL_FLASH_PREFETCH_BUFFER_ENABLE();  //使能flash预取,能够加快指令读取,提高性能。
	}
}









__weak HAL_StatusTypeDef HAL_RCC_OscConfig(RCC_OscInitTypeDef  *RCC_OscInitStruct)



typedef struct
{
  uint32_t OscillatorType;       /*!< The oscillators to be configured.
                                      This parameter can be a value of @refRCC_Oscillator_Type 我们在结构体的定义里找到这个参数是RCC_Oscillator_Type里的一个值,我们在整个页面搜索RCC_Oscillator_Type                 */

  uint32_t HSEState;             /*!< The new state of the HSE.
                                      This parameter can be a value of @ref RCC_HSE_Config                        */

  uint32_t LSEState;             /*!< The new state of the LSE.
                                      This parameter can be a value of @ref RCC_LSE_Config                        */

  uint32_t HSIState;             /*!< The new state of the HSI.
                                      This parameter can be a value of @ref RCC_HSI_Config                        */

  uint32_t HSICalibrationValue;  /*!< The HSI calibration trimming value (default is RCC_HSICALIBRATION_DEFAULT).
                                       This parameter must be a number between Min_Data = 0x00 and Max_Data = 0x1F */

  uint32_t LSIState;             /*!< The new state of the LSI.
                                      This parameter can be a value of @ref RCC_LSI_Config                        */

  RCC_PLLInitTypeDef PLL;        /*!< PLL structure parameters                                                    */
}RCC_OscInitTypeDef;



搜索到的RCC_Oscillator_Type如下,我们可以将下面的值作为结构体变量里第一个变量的值
/** @defgroup RCC_Oscillator_Type Oscillator Type
  * @{
  */
#define RCC_OSCILLATORTYPE_NONE            0x00000000U
#define RCC_OSCILLATORTYPE_HSE             0x00000001U
#define RCC_OSCILLATORTYPE_HSI             0x00000002U
#define RCC_OSCILLATORTYPE_LSE             0x00000004U
#define RCC_OSCILLATORTYPE_LSI             0x00000008U



Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐