Bootstrap

STM32 HAL库 时钟树的配置

在使用HAL库开发的过程中,必不可少的就是时钟的相关配置,通过STM32CubeMx可以看到,对于单片机来说,(至少在我看来)使用较多的为外部的高速时钟,可以让我们单片机内部的相关外设更加快速的运行。

下面开始配置时钟树

在存放驱动程序的文件夹中新建一个名为sys的文件夹,包含一个.c文件和一个.h文件,在工程中添加.c文件

包含所在的文件夹路径

在sys.c 文件中写入#include "sys.h",使其包含进去,编译一定会有错误,无需担心,只要sys.h文件被包含进去就行

在sys.h文件中写入以下代码

stm32f1xx.h是所有的f1系列的顶层头文件,通过条件编译来包含某个芯片的头文件,定义通用的枚举类型,定义通用的宏定义

下面的就是我们要编写的时钟数的函数名称(需要一个变量)

然后我们就在sys.c文件里面编写所需要的代码

先把标准代码放在下面

#include "sys.h"

void stm32_clock_init(uint32_t plln)
{
    HAL_StatusTypeDef ret = HAL_ERROR;
    RCC_OscInitTypeDef rcc_osc_init = {0};
    RCC_ClkInitTypeDef rcc_clk_init = {0};

    rcc_osc_init.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    rcc_osc_init.HSEState = RCC_HSE_ON;
    rcc_osc_init.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    rcc_osc_init.PLL.PLLState = RCC_PLL_ON;
    rcc_osc_init.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    rcc_osc_init.PLL.PLLMUL = plln;
    ret = HAL_RCC_OscConfig(&rcc_osc_init);
    
    if (ret != HAL_OK)
    {
        while(1);
    }
    
    rcc_clk_init.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
    rcc_clk_init.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    rcc_clk_init.AHBCLKDivider = RCC_SYSCLK_DIV1;
    rcc_clk_init.APB1CLKDivider = RCC_HCLK_DIV2;
    rcc_clk_init.APB2CLKDivider = RCC_HCLK_DIV1;
    ret = HAL_RCC_ClockConfig(&rcc_clk_init, FLASH_LATENCY_2);
    if (ret != HAL_OK)
    {
        while(1);
    }
}

 

上面的函数配置的是外部时钟的开始部分

这个配置的是中间部分

第一个函数配置如下:

定义一个函数来接收HAL_RCC_ClockConfig(RCC_ClkInitTypeDef  *RCC_ClkInitStruct, uint32_t FLatency)的返回值

 返回值的取值范围:

再定义一个该变量(结构体)的初始值

RCC_OscInitTypeDef rcc_osc_init = {0};

这个变量是一个结构体

这个结构体的相关注释

typedef struct
{
    // 要配置的振荡器类型,取值参考 @ref RCC_Oscillator_Type
    uint32_t OscillatorType; 

#if defined(STM32F105xC) || defined(STM32F107xC)
    // Prediv1 的源值,取值参考 @ref RCCEx_Prediv1_Source
    uint32_t Prediv1Source; 
#endif /* STM32F105xC || STM32F107xC */

    // 外部高速时钟(HSE)的新状态,取值参考 @ref RCC_HSE_Config
    uint32_t HSEState; 

    // 外部高速时钟的预分频因子值,在参考手册中可能被命名为 PREDIV1 或 PLLXTPRE,取值参考 @ref RCCEx_Prediv1_Factor
    uint32_t HSEPredivValue; 

    // 外部低速时钟(LSE)的新状态,取值参考 @ref RCC_LSE_Config
    uint32_t LSEState; 

    // 内部高速时钟(HSI)的新状态,取值参考 @ref RCC_HSI_Config
    uint32_t HSIState; 

    // 内部高速时钟的校准微调值,默认值可能是 RCC_HSICALIBRATION_DEFAULT,取值范围在 0x00 到 0x1F 之间
    uint32_t HSICalibrationValue; 

    // 内部低速时钟(LSI)的新状态,取值参考 @ref RCC_LSI_Config
    uint32_t LSIState; 

    // 用于配置锁相环(PLL)的相关参数
    RCC_PLLInitTypeDef PLL; 

#if defined(STM32F105xC) || defined(STM32F107xC)
    // 用于配置第二个锁相环(如果存在的话)的参数
    RCC_PLL2InitTypeDef PLL2; 
#endif /* STM32F105xC || STM32F107xC */
} RCC_OscInitTypeDef;

这表我们只给HSE(外部高速时钟)进行相关配置

各个配置的取值:

我就不一一列举了

同样的操作,我们再配置另外一个函数:

再进行相同的配置就行

上面的两个if函数都是if(ret!=HAL_OK),是因为我们上面对HAL_StatusTypeDef ret赋予了HAL_ERROR的初值,所以在这边用!=HAL_OK

这些函数的配置很好理解,都是围绕着配置外部高速时钟来进行的,我们不需要去配置其他的时钟函数

;