STM32学习系列(一)--- 时钟

本文详细介绍了STM32F103的时钟系统,包括时钟源选择、分频策略、HAL库配置实例,以及如何根据需求调整系统时钟频率。适合学习者理解时钟树结构与实际编程操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

STM32学习系列(一)— 时钟

2022-04-23 15:20

该系列是为了记录自己的学习过程,如有错误和不足,欢迎指出,感谢!

一、简介

时钟就如人体的心脏,管理着全身血液的流速(类比),因此想要驱动STM32F103,时钟的初始化很重要。
这一节就是为了理清STM32F103的时钟源和时钟配置。使用HAL库的方式,进行实现,原因:

  1. 官方已经包装好函数,调用就可以
  2. 学习阶段,需要控制一下变量,第一次学习,了解有哪些资源,怎么用,如何修改成自己想要的效果,个人觉得这样比较合理。
  3. 寄存器的要求比较高,需要对C语言和初始化的配置有一定的了解
  4. 库函数介于寄存器和HAL库中间,且官方更新的态度已经降低,偏向于HAL库和LL库。

二、时钟源

2.1 时钟树

![[Pasted image 20220423154642.png]在这里插入图片描述
这是STM32F103ZE的时钟树(来着韦东山学习手册)
可以看出时钟的来源可以是四个部分,四选一。

  1. HSI:高速内部时钟,8MHz,内部集成,但精度不足。
  2. HSE:高速外部时钟,4MHz~16MHz【主要使用的】
  3. LSI:低速内部时钟,32.768KHz
  4. LSE:低速外部时钟,40KHz

时钟源简称如何解读:
包括三个部分: H/L 表示高速或者低速
S 表示速度(speed)
I/E 表示内部或者外部

2.2 在HAL库中的表示

主函数

		int main(void)
		{
		    HAL_Init();      //初始化HAL库,调用HAL库必须有    
		    Stm32_Clock_Init(RCC_PLL_MUL9);  //设置时钟,72M
			while(1)
			{
			}
		}

Stm32_Clock_Init( )函数

void Stm32_Clock_Init(u32 PLL)
{
    HAL_StatusTypeDef ret = HAL_OK;
    RCC_OscInitTypeDef RCC_OscInitStructure; 
    RCC_ClkInitTypeDef RCC_ClkInitStructure;
    
    RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSE;    	//时钟源为HSE
    RCC_OscInitStructure.HSEState=RCC_HSE_ON;                      	//打开HSE
	RCC_OscInitStructure.HSEPredivValue=RCC_HSE_PREDIV_DIV1;		//HSE预分频
    RCC_OscInitStructure.PLL.PLLState=RCC_PLL_ON;					//打开PLL
    RCC_OscInitStructure.PLL.PLLSource=RCC_PLLSOURCE_HSE;			//PLL时钟源选择HSE
    RCC_OscInitStructure.PLL.PLLMUL=PLL; //传入的参数							//主PLL倍频因子
    ret=HAL_RCC_OscConfig(&RCC_OscInitStructure);//初始化
	
    if(ret!=HAL_OK) while(1);
    
    //选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2
    RCC_ClkInitStructure.ClockType=(RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2);
    RCC_ClkInitStructure.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;		//设置系统时钟时钟源为PLL
    RCC_ClkInitStructure.AHBCLKDivider=RCC_SYSCLK_DIV1;				//AHB分频系数为1
    RCC_ClkInitStructure.APB1CLKDivider=RCC_HCLK_DIV2; 				//APB1分频系数为2
    RCC_ClkInitStructure.APB2CLKDivider=RCC_HCLK_DIV1; 				//APB2分频系数为1
    ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_2);	//同时设置FLASH延时周期为2WS,也就是3个CPU周期。
		
    if(ret!=HAL_OK) while(1);
}

我们可以看出Stm32_Clock_Init中其实是初始化了两个部分。
第一部分:RCC_OscInitTypeDef, 是选择时钟源的结构体

typedef struct
{
  uint32_t OscillatorType;     /*选择时钟源 */  

  uint32_t HSEState;           /*HSE的状态 */      

  uint32_t HSEPredivValue;     /*HSE预分频 */   
                                       
  uint32_t LSEState;           /*LSE的状态 */     

  uint32_t HSIState;           /*HSI的状态 */     

  uint32_t HSICalibrationValue; /*HSI校准微调值 */        

  uint32_t LSIState;            /*LSI的状态 */  

  RCC_PLLInitTypeDef PLL;       /*PLL配置结构体 */

} RCC_OscInitTypeDef;

typedef struct
{
  uint32_t PLLState;       /*PLL状态 */
  uint32_t PLLSource;      /*PLL来源 */
  uint32_t PLLMUL;         /*主PLL倍频因子*/
} RCC_PLLInitTypeDef;

/*调用 HAL_RCC_OscConfig()进行初始化*/

第二部分:RCC_ClkInitTypeDef,具体时钟的配置结构体

typedef struct
{
  uint32_t ClockType;      /*选择要配置的系统时钟 */         

  uint32_t SYSCLKSource;   /*选择系统时钟的来源 */   
     
  uint32_t AHBCLKDivider;  /* AHB分频系数  */       
 
  uint32_t APB1CLKDivider; /* APB1分频系数  */      

  uint32_t APB2CLKDivider; /* APB2分频系数  */     
} RCC_ClkInitTypeDef;

要想进行时钟配置,需要看懂时钟树。从左边的时钟源选择,通过中间部分的分频,到右边总线的时钟配置,是一个完整的流程

三、硬件平台

韦东山STMF103开发板,不需要外部资源

四、编程思维

时钟初始化的一般步骤:

  1. 时钟源选择
  2. 分频系数选择
  3. PLL锁相环配置
  4. AHB分频系数选择
  5. APB1分频系数选择
  6. APB2分频系数选择

五、代码实现

5.1 设置系统时钟为72MHz(HSE_8MHz)

在这里插入图片描述


void Stm32_Clock_Init(u32 PLL)
{
    HAL_StatusTypeDef ret = HAL_OK;
    RCC_OscInitTypeDef RCC_OscInitStructure; 
    RCC_ClkInitTypeDef RCC_ClkInitStructure;
    
    RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSE;    	//时钟源为HSE,8MHz
    RCC_OscInitStructure.HSEState=RCC_HSE_ON;                      	//打开HSE
	RCC_OscInitStructure.HSEPredivValue=RCC_HSE_PREDIV_DIV1;		//HSE预分频,不分频
    RCC_OscInitStructure.PLL.PLLState=RCC_PLL_ON;					//打开PLL
    RCC_OscInitStructure.PLL.PLLSource=RCC_PLLSOURCE_HSE;			//PLL时钟源选择HSE,因为时钟源选择的是HSE
    RCC_OscInitStructure.PLL.PLLMUL=PLL; 							//主PLL倍频因子,输入参数为9倍频,8*9=72MHz
    ret=HAL_RCC_OscConfig(&RCC_OscInitStructure);//初始化
	
    if(ret!=HAL_OK) while(1);
    
    //选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2
    RCC_ClkInitStructure.ClockType=(RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2);
    RCC_ClkInitStructure.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;		//设置系统时钟时钟源为PLL
    RCC_ClkInitStructure.AHBCLKDivider=RCC_SYSCLK_DIV1;				//AHB分频系数为1  72/1=72MHz
    RCC_ClkInitStructure.APB1CLKDivider=RCC_HCLK_DIV2; 				//APB1分频系数为2  72/2=36MHz(最大是36MHz)
    RCC_ClkInitStructure.APB2CLKDivider=RCC_HCLK_DIV1; 				//APB2分频系数为1   72/1=72MHz
    ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_2);	//同时设置FLASH延时周期为2WS,也就是3个CPU周期。
		
    if(ret!=HAL_OK) while(1);
}

5.2 设置系统时钟为36MHZ(HSI_8MHz)

在这里插入图片描述

void Stm32_Clock_Init(u32 PLL)
{
    HAL_StatusTypeDef ret = HAL_OK;
    RCC_OscInitTypeDef RCC_OscInitStructure; 
    RCC_ClkInitTypeDef RCC_ClkInitStructure;
    
    RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSI;    	//时钟源为HSI
    RCC_OscInitStructure.HSEState=RCC_HSE_OFF;                      	//关闭HSE
	RCC_OscInitStructure.HSIState=RCC_HSI_ON;//打开HEI
	RCC_OscInitStructure.HSEPredivValue=RCC_HSE_PREDIV_DIV1;		//HSE预分频
    RCC_OscInitStructure.PLL.PLLState=RCC_PLL_ON;					//打开PLL
    RCC_OscInitStructure.PLL.PLLSource=RCC_PLLSOURCE_HSI_DIV2;		//PLL时钟源选择HSI的2分频, 8/2 =4MHz
    RCC_OscInitStructure.PLL.PLLMUL=PLL; 							//主PLL倍频因子,需要传入9分频,4*9=36MHz
    ret=HAL_RCC_OscConfig(&RCC_OscInitStructure);//初始化
	
    if(ret!=HAL_OK) while(1);
    
    //选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2
    RCC_ClkInitStructure.ClockType=(RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2);
    RCC_ClkInitStructure.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;		//设置系统时钟时钟源为PLL
    RCC_ClkInitStructure.AHBCLKDivider=RCC_SYSCLK_DIV1;				//AHB分频系数为1  36/1=36MHz
    RCC_ClkInitStructure.APB1CLKDivider=RCC_HCLK_DIV2; 				//APB1分频系数为1 36/1=36MHz
    RCC_ClkInitStructure.APB2CLKDivider=RCC_HCLK_DIV1; 				//APB2分频系数为1 36/1=36MHz
    ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_2);	//同时设置FLASH延时周期为2WS,也就是3个CPU周期。
		
    if(ret!=HAL_OK) while(1);
}

六、总结

在模板工程中,一般时钟部分是配置好的,而且我们一般是通过点灯的例程去添加我们的代码,但是如果有其他需求,例如修改系统时钟频率,那么就需要对这一部分的内容,有所了解。
学这章的一个目的:

  1. 能看懂时钟树
  2. 能在官方例程的基础上,修改到我们需要的系统频率和总线频率
  3. 了解HAL库配置的一般过程,参数查找和调用
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值