时钟是具有周期性的脉冲信号,最常用的是占空比50%的方波,时钟是单片机的脉搏,搞懂时钟走向及关系,对单片机使用至关重要!
时钟树
F1系列
时钟来源主要有四个:高速外部振荡器(HSE)、低速外部振荡器(LSE)、高速内部振荡器(HSI)、低速内部振荡器(LSI)
时钟源名称 | 频率 | 材料 | 用途 |
---|---|---|---|
高速外部振荡器(HSE) | 4~16MHz | 晶体/陶瓷 | SYSCLK/RTC |
低速外部振荡器(LSE) | 32.768KHz | 晶体/陶瓷 | RTC |
高速内部振荡器(HSI) | 8MHz | RC | SYSCLK |
低速内部振荡器(LSI) | 40KHz | RC | RTC/IWDG |
时钟树
F1系统时钟最大为72MHz。上面的时钟树图看起来比较混乱,可以看下面的简图。
H7系列
时钟源名称 | 频率 | 材料 | 用途 |
---|---|---|---|
高速外部振荡器(HSE) | 4~48MHz | 晶体/陶瓷 | SYSCLK/RTC |
低速外部振荡器(LSE) | 32.768KHz | 晶体/陶瓷 | IWDG/RTC/AWU |
高速内部振荡器(HSI) | 64MHz | RC | SYSCLK |
低速内部振荡器(LSI) | 32KHz | RC | RTC/IWDG/RTC/AWU |
高速内部振荡器(HSI48) | 48MHz | RC | USB |
时钟树
低频部分:
CubeMX时钟树
根据STM32CubeMX进行时钟配置,以H7系列为例:
H7系列系统时钟最高为480MHz,系统时钟来源可以为HSE、HSI、CSI。
1、当高速外部振荡器(HSE)为8MHz时,要想使系统时钟达到480MHz,CubeMX时钟树图应设置为:
2、当高速外部振荡器(HSE)为25MHz时,要想使系统时钟达到480MHz,CubeMX时钟树图应设置为:
3、当高速内部振荡器(HSI)为系统时钟来源时,系统时钟频率是达不到480MHz的,CubeMX时钟树图应设置为:
时钟配置
时钟配置的代码可以使用STM32CubeMX设置好时钟图后直接生成代码,不过是初步代码。
配置步骤:
1, HAL_RCC_OscConfig()函数,配置需要配置的时钟源等参数
配置时钟源结构体:
锁相环配置结构体:
2, HAL_RCC_ClockConfig()函数,配置时钟来源
通过时钟树或则时钟简图可以看出,系统时钟来源有多个,可以是直接来自HSE、HSI、CSI,也可以是它们经过锁相环后的时钟频率,这里就是配置是哪个来源,并且配置APB1234时钟的预分频系数。
以HSE为例代码如下(H7):
void Stm32_Clock_Init(u32 plln,u32 pllm,u32 pllp,u32 pllq)
{
HAL_StatusTypeDef ret=HAL_OK;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
MODIFY_REG(PWR->CR3,PWR_CR3_SCUEN, 0);
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
while ((PWR->D3CR & (PWR_D3CR_VOSRDY)) != PWR_D3CR_VOSRDY) {}
RCC_OscInitStruct.OscillatorType=RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState=RCC_HSE_ON;
RCC_OscInitStruct.HSIState=RCC_HSI_OFF;
RCC_OscInitStruct.CSIState=RCC_CSI_OFF;
RCC_OscInitStruct.PLL.PLLState=RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource=RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLN=plln;
RCC_OscInitStruct.PLL.PLLM=pllm;
RCC_OscInitStruct.PLL.PLLP=pllp;
RCC_OscInitStruct.PLL.PLLQ=pllq;
RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2;
ret=HAL_RCC_OscConfig(&RCC_OscInitStruct);
if(ret!=HAL_OK) while(1);
RCC_ClkInitStruct.ClockType=(RCC_CLOCKTYPE_SYSCLK|\
RCC_CLOCKTYPE_HCLK |\
RCC_CLOCKTYPE_D1PCLK1 |\
RCC_CLOCKTYPE_PCLK1 |\
RCC_CLOCKTYPE_PCLK2 |\
RCC_CLOCKTYPE_D3PCLK1);
RCC_ClkInitStruct.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.SYSCLKDivider=RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider=RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB1CLKDivider=RCC_APB1_DIV2;
RCC_ClkInitStruct.APB2CLKDivider=RCC_APB2_DIV2;
RCC_ClkInitStruct.APB3CLKDivider=RCC_APB3_DIV2;
RCC_ClkInitStruct.APB4CLKDivider=RCC_APB4_DIV4;
ret=HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
if(ret!=HAL_OK) while(1);
__HAL_RCC_CSI_ENABLE() ;
__HAL_RCC_SYSCFG_CLK_ENABLE() ;
HAL_EnableCompensationCell();
}
如果是HSE是8MHz,那么传入参数可以为:Stm32_Clock_Init(240,2,2,4);
如果是HSE是25MHz,那么传入参数可以为:Stm32_Clock_Init(192,5,2,4);
以HSI为例代码如下(H7):
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Supply configuration update enable
*/
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
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_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV1;
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
}