一、SystemInit函数的作用
SystemInit函数它在芯片完成复位操作且尚未进入main函数之际被调用,主要用于设置系统时钟,从而保障微控制器能以契合需求的频率稳定运行。
1. 与硬件的关联
SystemInit函数直接操控时钟相关寄存器,以此对芯片内部的时钟电路进行精准调控。例如,在进行外部高速时钟(HSE)配置时,函数需要密切监控外部晶振的稳定 状态,这一过程涉及到对时钟就绪标志寄存器的读取与判断操作。
2. 对其他部分的影响
SystemInit函数决定了CPU的运行频率,而且影响外设的时钟频率。由于外设时钟通常是由系统时钟经过分频处理而获得的,因此不同的系统时钟设置方案将直接导致外设以不同的速度运行。
3. 在代码中的位置和调用方式
SystemInit函数通常在启动文件(如startup_stm32xxx.s)中被自动调用,调用时机处于复位之后、main函数之前。在常规的开发实践中,开发人员不用直接调用SystemInit函数。但如果项目对系统时钟设置有特殊需求,例如需要采用非默认的时钟源或调整时钟频率,那么开发人员可能需要在用户代码中对SystemInit函数中的相关部分进行重新配置。或者,也可以借助HAL库提供的更为灵活的时钟配置函数,如HAL_RCC_ClockConfig等,来实现定制化的时钟设置目标。
4. 时钟源选择
在STM32系列中,可供选择的时钟源包括内部高速时钟(HSI)、外部高速时钟(HSE)、内部低速时钟(LSI)以及外部低速时钟(LSE)。
SystemInit函数中的时钟默认配置为内部8MHz的HSI。
以下是一个简单的示例代码,用于展示如何对系统时钟进行初步的配置与输出查看:
#include "stm32f1xx_hal.h"
int main(void)
{
// 初始化HSI
HAL_Init();
// 配置MCO1,将系统时钟作为输出源,分频系数为1
HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_SYSCLK, RCC_MCODIV_1);
}
其中 , HAL_RCC_MCOConfig 函数表示要进行 MCO (Microcontroller Clock Output)的配置操作。MCO引脚可以将内部的时钟信号输出到外部,方便进行时钟信号的监测。
参数说明:
RCC_MCO1:数指定了要配置的 MCO 通道。在这里是选择了 MCO1 通道。在 STM32中, MCO1默认的输出引脚是PA8。
RCC_MCO1SOURCE_SYSCLK:定义了 MCO1 输出的时钟源。在这种情况下,选择的时钟源是系统时钟(SYSCLK)。
RCC_MCODIV_1:确定了 MCO 输出时钟相对于所选时钟源的分频系数。这里设置为 RCC_MCODIV_1,意味着输出的时钟频率与所选的时钟源(在此为系统时钟)频率是相同的,即没有进行分频。如果设置为其他的分频值(比如 RCC_MCODIV_2、RCC_MCODIV_4 等),则输出的时钟频率会是所选时钟源频率按照相应分频系数进行分频后的频率。
在上述代码中,通过调用相关函数对HSI进行初始化,并将系统时钟输出到PA8引脚,开发人员可以借助示波器等工具查看PA8引脚的波形,从而直观地了解系统时钟的输出情况。下面是示波器显示情况(暂时不知道哪里有干扰):
二、使用内部 HSI 时钟源,通过 PLL 倍频
1. 时钟树
2. 代码实现
void RccClock_Init(void){
// 定义一个RCC振荡器初始化结构体
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitTypeDef = {0};
// 配置使用内部高速时钟HSI
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
// 启用HSI时钟
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
// 设置HSI时钟校准值
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
// 启用PLL
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
// 设置PLL时钟源为HSI时钟的二分频
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
// 设置PLL倍频因子为16
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
// 初始化RCC振荡器
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
// 初始化错误处理
}
// 配置系统时钟源为PLL
RCC_ClkInitTypeDef.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
// 系统时钟输入源
RCC_ClkInitTypeDef.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
// AHB 分频因子, 1分频
RCC_ClkInitTypeDef.AHBCLKDivider = RCC_SYSCLK_DIV1;
// APB1 分频因子, 2分频
RCC_ClkInitTypeDef.APB1CLKDivider = RCC_HCLK_DIV2;
// APB2 分频因子, 1分频
RCC_ClkInitTypeDef.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitTypeDef, FLASH_LATENCY_2) != HAL_OK) {
// 初始化错误处理
}
}
输出波形应该是方波,受限于GPIO输出频率50MHz限制,输出波形不准确。
三、使用 HSE外部8M高速晶振配置系统时钟到72MHz
1. 时钟树
2. 代码实现
#include "stm32f1xx_hal.h"
#include "rcc.h"
void RccClock_Init(void){
// 定义一个RCC振荡器初始化结构体
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitTypeDef = {0};
// 配置使用外部高速时钟HSE
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
// 启用HSE时钟
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
// HSE时钟频率为8MHz
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
// 启用PLL
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
// 设置PLL时钟源为HSE时钟
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
// 设置PLL倍频因子为9,使系统时钟达到72MHz (8MHz HSE * 9 = 72MHz)
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
// 初始化RCC振荡器
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
// 初始化错误处理
}
// 配置系统时钟源为PLL
RCC_ClkInitTypeDef.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
// 系统时钟输入源
RCC_ClkInitTypeDef.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
// AHB 分频因子, 1分频
RCC_ClkInitTypeDef.AHBCLKDivider = RCC_SYSCLK_DIV1;
// APB1 分频因子, 2分频
RCC_ClkInitTypeDef.APB1CLKDivider = RCC_HCLK_DIV2;
// APB2 分频因子, 1分频
RCC_ClkInitTypeDef.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitTypeDef, FLASH_LATENCY_2) != HAL_OK) {
// 初始化错误处理
}
}
本文部分学习资源来自B站视频《STM32 HAL库全覆盖手把手入门精讲教程 基础篇238节》
本文代码开源地址: https://gitee.com/xundh/stm32_arm_hal_learn.git
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/xundh/article/details/144096044
|