STM32学习笔记(1) —— 系统时钟配置(RCC)
和研究生导师做项目,开始接触STM32。本科也接触过STM32,但是学的不够系统。现在开始系统的学习嵌入式开发,在这分享一些自己的理解和心得。写的东西比较浅显,说的不对的地方希望大家谅解并指正,谢谢!
系统时钟配置(RCC)
我用的芯片是STM32F407ZGT6,这篇文章我主要来说一说对系统时钟的配置。
时钟树
看懂时钟树基本就能知道芯片的时钟该怎么配置了,下图是F407的时钟树
我主要放了和系统时钟配置相关的部分(其他部分我目前还没用到,也就先不讲)。系统时钟主要由三个部分来提供:外部时钟源HSE、内部时钟源HSI和锁相环PLL。
因为F407的主频可以达到168M,所以一般选择用锁相环电路进行倍频后作为系统时钟。由于F407内部机制,由HSE经过PLL倍频后作为系统时钟,当HSE出现故障时,系统会自动切换为HSI。因此一般选择HSE+PLL来提供系统时钟。
配置总线时钟
STM32的一切外设都是挂载在系统总线上。一般来说AHB总线时钟(HCLK)配置为和系统时钟相同168M。系统的外设时钟有HCLK来提供,四分频作为低速外设时钟PCLK1,为42M;二分频作为高速外设时钟PCLK2。
总结
这里放一张我自己总结的脑图
提示:选择HSE作为时钟源时一定要参考自己的系统板所提供的外部晶振的频率来配置,用stm32cubeMX来生成的配置代码默认的外部晶振是25M。若这里没有注意,可能在后期用一些外设的时候会出问题(如USART的波特率配置)。
代码详解
一般用cubeMX来生成时钟配置的程序
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {
0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {
0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
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 = 4;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
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();
}
}
我来稍微讲解一下这段代码
1.首先当然后定义句柄结构体了
RCC_OscInitTypeDef RCC_OscInitStruct = {
0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {
0};
2.然后是对时钟源的选择进行配置
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;
这里选择的是用PLL作为系统时钟源,而PLL由HSE来提供
3.设置PLL参数M、N、P、Q,使系统时钟频率为168M
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
4.配置SYSCLK、HCLK、PCLK1、PCLK2
RCC_ClkInitStruct.ClockTypeRCC_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;
写的东西比较浅,一些深入东西会在进一步学习之后进行补充。希望能对一些像我这种刚入门嵌入式的小白有所帮助,有错误的地方也请大神指出。