STM32HAL(二)外设管理与系统时钟配置
探讨了STM32F4系列微控制器使用HAL库进行系统时钟配置与外设管理的关键步骤与实践策略
目录
如何使用HAL库
基于CMSIS应用程序文件描述
STM32开发文件结构分布
HAL库的用户配置文件(stm32f1xx_hal_conf.h)
裁剪HAL库外设驱动源码(不进行编译)
如果有没有使用的外设可以注释掉,减少编译。
设置外部高速晶振频率(根据开发板实际情况设置
设置外部低速晶振频率(根据开发板实际情况设置)
stm32f1xx_hal.c 文件
HAL_StatusTypeDef HAL_Init(void)
{
__HAL_FLASH_PREFETCH_BUFFER_ENABLE(); /* 使能FLASH预取缓冲 */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2); /* 配置中断优先级分组 */
/* 使用滴答定时器作为时钟基准,配置 1ms 滴答(重置后默认的时钟源为 HSI) */
HAL_InitTick(TICK_INT_PRIORITY);
HAL_MspInit(); /* 初始化其它底层硬件(如果必要) */
return HAL_OK; /* 返回函数状态 */
}
系统时钟配置
初始化HAL库
首先,需要初始化HAL库,这包括滴答定时器中断的配置和NVIC优先级分组设置。这是通过调用HAL_Init()函数实现的,该函数内部会做以下事情:
- 初始化HAL库(包括外设句柄和时钟配置结构体)。
- 调用HAL_InitTick()初始化滴答定时器中断,通常设置为1毫秒中断一次,用于延时函数和时间基准。
- 设置NVIC优先级分组(默认情况下可能是4),决定中断优先级的管理方式。
2. 配置系统时钟
接下来,配置STM32F407的系统时钟到一个更高的频率,比如168MHz。这通常涉及到以下几个步骤:
- 启用外部高速时钟(HSE):使用HAL_RCC_OscConfig()函数配置外部时钟源,如HSE晶体或陶瓷谐振器。此函数接收一个RCC_OscInitTypeDef类型的结构体指针作为参数,其中包含了HSE的使能状态、时钟范围等配置信息。
- 配置PLL(锁相环):使用相同的HAL_RCC_OscConfig()函数或单独的HAL_RCC_PLLConfig()函数来配置PLL。你需要设置PLL的输入时钟源(HSE或HSI)、倍频系数(N)、以及可能的分频系数(P和Q),以达到目标系统时钟频率。
- 选择系统时钟源:使用HAL_RCC_ClockConfig()函数来选择PLL作为系统时钟源并更新系统时钟频率。这个函数需要一个RCC_ClkInitTypeDef类型的结构体指针,用于指定AHB、APB1、APB2的时钟分频设置,以及系统时钟源的选择。
3. 验证时钟配置
配置完成后,可以使用HAL库提供的函数来检查配置是否成功,例如通过读取系统时钟频率并打印出来验证:
uint32_t sysclk_freq = HAL_RCC_GetSysClockFreq();
printf("System Clock Frequency: %lu Hz\n", sysclk_freq);
注意事项
- 在进行时钟配置前,确保了解所使用的STM32型号的具体时钟树特性,包括可用的时钟源、PLL配置限制等。
- 时钟配置应当在程序的早期阶段完成,最好是在主函数的开始,且在任何依赖于时钟速度的外设初始化之前。
- 如果使用STM32CubeMX工具,大部分时钟配置工作可以自动生成,然后手动调整或添加特定的配置代码。
外设时钟使能和失能
我们要使用某个外设,必需先使能该外设时钟!!!
HAL库使能某个外设时钟的方法,如:
__HAL_RCC_GPIOA_CLK_ENABLE(); /* 使能 GPIOA 时钟
系统时钟初始化函数是微控制器启动后用于配置其内部时钟系统的函数。在STM32中,这个过程涉及多个步骤,包括但不限于使能外部或内部振荡器(OSC)、配置锁相环(PLL)、选择系统时钟源,并最终分配给不同的总线(如AHB、APB1、APB2)合适的时钟分频。以下是系统时钟初始化的一般步骤和概念,以STM32 HAL库为例进行说明:
1. HAL_Init()函数
这是HAL库的初始化入口点,它主要负责初始化HAL库的内部数据结构和一些基本设置,如滴答定时器中断和NVIC优先级分组。虽然它间接影响时钟(比如滴答定时器的配置),但不直接参与时钟源的选择和配置。
2. SystemClock_Config()函数
这是一个用户自定义的函数,用来具体实现系统时钟的配置。在这个函数中,你会执行以下操作:
- 配置振荡器(OSC):如果使用外部晶振(HSE)或内部RC振荡器(HSI),需要通过HAL_RCC_OscConfig()函数来配置。这包括使能振荡器、设置其工作模式(如HSE需要外部晶振稳定时间)。
- 配置PLL:使用HAL_RCC_PLLConfig()或在较新版本的HAL库中直接在HAL_RCC_OscConfig()中配置PLL。这包括设置PLL的输入时钟源、倍频系数、以及可能的分频,以达到所需的系统时钟频率。
- 选择系统时钟源:通过HAL_RCC_ClockConfig()函数来选择PLL或其他可用时钟源(如HSE或HSI)作为系统时钟,并设置AHB、APB1、APB2总线的时钟分频。
3. HAL_RCC_OscConfig()和HAL_RCC_ClockConfig()函数
这两个函数是HAL库中用于配置振荡器和时钟树的关键函数。HAL_RCC_OscConfig()用于配置振荡器(HSE/HSI/LSE/LSI等)和PLL,
而HAL_RCC_ClockConfig()则用于选择系统时钟源,并配置各总线的时钟分频,从而确定整个系统的运行频率。
4. 错误处理
在每个配置步骤之后,应当检查函数的返回值以确认操作是否成功。如果配置失败,应当有错误处理逻辑,比如进入无限循环或者调用特定的错误处理函数,如Error_Handler()。
5. 时钟安全机制
在一些高级的STM32系列中,还可能涉及到时钟安全系统(CSS)的配置,用于监测系统时钟源的稳定性,以防振荡器失效导致系统崩溃。
示例代码片段
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
// 配置HSE(外部高速时钟)为系统时钟源
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
// 配置系统时钟源、总线分频等
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
时钟树(STM32F407)
时钟源:
- HSI (High Speed Internal):内部高速时钟,频率约为8MHz,是系统启动时的默认时钟源,用于快速上电运行。它的稳定性不如外部时钟源,但在没有外部晶振的情况下可以作为应急时钟使用。
- HSE (High Speed External):外部高速时钟源,用户可通过接外部晶振(通常为8MHz、12MHz或25MHz)提供,可以是晶体或陶瓷谐振器,通过倍频后可用作系统时钟。
- LSE (Low Speed External):外部低速时钟源,通常用于RTC(实时时钟),频率为32.768kHz。
- LSI (Low Speed Internal):内部低速时钟,约32kHz,用于独立看门狗、RTC和备份域的时钟。
- PLL (Phase Locked Loop):锁相环,可以将HSE或HSI作为输入,通过倍频和分频产生更高的系统时钟频率,STM32F407的PLL可以配置为输出高达170MHz的系统时钟。
系统时钟配置
1. 时钟源启用与配置
HSE(High Speed External)配置
-
使能HSE: 通过设置RCC_CR寄存器中的HSEON位来开启外部高速时钟源。
-
等待稳定: 在开启HSE后,需要通过轮询RCC_CR寄存器中的HSERDY位,直到它被置1,表明HSE已经稳定。
PLL(Phase Locked Loop)配置
-
选择PLL输入源: 通过设置RCC_PLLCFGR寄存器中的相关位来选择HSE或HSI作为PLL的输入时钟源。
-
配置PLL乘法因子和分频因子: 设置RCC_PLLCFGR寄存器中的PLLM、PLLN和PLLP位来确定最终的PLL输出频率。例如,要得到168MHz的系统时钟,可能需要将HSE(假设为8MHz)通过PLL乘以一定的系数,并且考虑分频。
HSI(High Speed Internal)、LSI/LSE(Low Speed Internal/External)配置
-
这些时钟源相对简单,一般仅需开启即可,具体取决于是否使用它们作为PLL的输入或作为系统时钟的备选。
2. 系统时钟选择
-
选择SYSCLK源: 通过设置RCC_CFGR寄存器中的SW[2:0]位来选择系统时钟源(HSI、HSE、PLLCLK)。
-
等待切换完成: 切换系统时钟源后,需要等待相应的就绪标志(如PLLRDY)变为有效。
3. 总线时钟配置
-
AHB(Advanced High-performance Bus)预分频: 通过设置RCC_CFGR寄存器中的HPRE[3:0]位来调整AHB总线时钟。
-
APB1和APB2预分频: 分别通过设置RCC_CFGR寄存器中的PPRE1[2:0]和PPRE2[2:0]位来调整APB1和APB2总线时钟。这一步骤是必要的,因为不同的外设挂载在不同的总线上,对时钟频率有不同的要求。
4. 时钟输出配置(可选)
-
如果需要,可以通过设置RCC_CFGR寄存器中的MCO[2:0]位来配置MCO引脚输出特定的时钟信号。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)