STM32F103时钟配置详解:从基础到实践

       STM32F103是一款广泛应用于嵌入式系统的微控制器,目前在stm32上主流的库函数是HAL库。

大家在stm32学习HAL库上有很多人喜欢用Stm32CobeMX也就是图形化配置去配置。

这就导致有很多人没学习过其他芯片的库函数的朋友不太了解到底每个配置都是干嘛的,就知道这么配就是最高72MHz主频。

什么是时钟?

时钟就相当于人的心跳,没有心跳单片机是不会工作的,所以我们配置的stm32有很多模块化的时钟,我们用到那个片内外设就要第一步打开他们的相对应得时钟。

stm32有五个时钟源:
   

HSI  内部高速时钟
HSE  外部高速时钟
LSI  内部低速时钟
LSE  外部低速时钟
PLL  锁相环倍频输出(这个时钟一般作为倍频来使用,也就是原来如果是4mhz倍频2就是:4*2 = 8)

我们配置时钟源的第一个结构体就是 :RCC_OscInitTypeDef

让我们来看下此结构体的内部成员:

typedef struct{

   uint32_t OscillatorType;         //选择振荡电路

   uint32_t HSEState;               //外部高速时钟状态
                                        

  uint32_t HSEPredivValue;          //外部高速时钟分频值    
                                   

  uint32_t LSEState;                // 外部低速时钟状态   
                                        

  uint32_t HSIState;                // 内部高速时钟状态  
                                        

  uint32_t HSICalibrationValue;     //HSI微调值
                                       

  uint32_t LSIState;                //内部低速时钟状态 
                                       

  RCC_PLLInitTypeDef PLL;           //PLL相关配置结构体


}RCC_OscInitTypeDef;               //配置内外部时钟源的结构体
大家应该发现除了第一个和最后一个外其余的可以分为四部分:

HSE开头的外部高速时钟源一个开关配置一个分频配置

HSI开头的内部高速时钟源一个开关配置一个分频配置

LSE开头的外部低速时钟源一个开关配置

LSI开头的内部低速时钟源一个开关配置

1.结构体的第一个成员 OscillatorType:

此配置的选项一共是五个

#define RCC_OSCILLATORTYPE_NONE            0x00000000U
#define RCC_OSCILLATORTYPE_HSE             0x00000001U
#define RCC_OSCILLATORTYPE_HSI             0x00000002U
#define RCC_OSCILLATORTYPE_LSE             0x00000004U
#define RCC_OSCILLATORTYPE_LSI             0x00000008U

分别是把外部高速时钟源RCC_OSCILLATORTYPE_HSE配置为当前程序的基时钟

又或者把内部高速时钟源RCC_OSCILLATORTYPE_HSI配置为当前程序的基时钟

又或者把外部低速时钟源RCC_OSCILLATORTYPE_LSE配置为当前程序的基时钟

又或者把内部低速时钟源RCC_OSCILLATORTYPE_LSI配置为当前程序的基时钟

又又或者选择RCC_OSCILLATORTYPE_NONE,什么都不配置

2.结构体的成员 HSEState,HSIState,LSEState,LSiState这四个兄弟:

        

大家先记住他们除了第一个都有俩个成员,大家初学就把他们都当成俩个就行哈

一个RCC_LSE_OFF         一个RCC_LSE_ON

        RCC_LSE_OFF                 RCC_LSE_ON

       RCC_HSI_OFF                 RCC_HSI_ON

       RCC_LSI_OFF                 RCC_LSI_ON

      举个例子如果配置内部高速时钟:
      
        
      
大家前边只需配置这三个就可以
反之低速类型的就把上述图片最后一个去除,只需配置头俩个就可以
   
接下来咱们说这个嵌套的结构体PLL
PLL有三个成员
PLLState      PLL状态

PLLSource     PLL输入源

PLLMUL        PLL倍频值

PLLState有三个可选值

RCC_PLL_NONE      RCC_PLL_OFF   RCC_PLL_ON
大家看名字就能看出来第一个不配置PLL,第二个关闭,第三单个打开
PLLSource   有俩个选择:
        RCC_PLLSOURCE_HSI_DIV2       //把HSI2分频配置给PLL
        RCC_PLLSOURCE_HSE               //把HSE不分频配置给PLL
PLLMUL     有很多个选择:
       
        此成员就是把我们之前分频得到的时钟源或者不分频得到的时钟源倍频
        RCC_PLL_MUL2 ~ RCC_PLL_MUL16             乘以2 ~16
       当我们配置好了把他交给HAL_RCC_OscConfig();传入参数
下边实例是外部高速利用PLL倍频到72
 
下边实例是内部高速利用PLL倍频到64
我们搭建好了第一个结构体了
下边还需要一个结构体  RCC_ClkInitTypeDef  //配置总线时钟配置结构体
此结构体有五个参数
ClockType (需要配置的时钟):
RCC_CLOCKTYPE_SYSCLK   HAL_RCC_ClockConfig函数中会配置SYSCLK 相关的寄存器
RCC_CLOCKTYPE_HCLK        HAL_RCC_ClockConfig函数中会配置 HCLK 相关的寄存器
RCC_CLOCKTYPE_PCLK1      HAL_RCC_ClockConfig函数中会配置PCLK1 相关的寄存器
R CC_CLOCKTYPE_PCLK2      HAL_RCC_ClockConfig函数中会配置 PCLK2 相关的寄存器
一般情况下我们利用或等于是把他们全部配置比如:
ClkInitTypeDef.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
SYSCLKSource (SYSCLK系统时钟输入源):
此参数可以传入三个参数值
R CC_SYSCLKSOURCE_HSI HSI作为系统时钟
RCC_SYSCLKSOURCE_HSE HSE作为系统时钟
RCC_SYSCLKSOURCE_PLLCLK PLL输出作为系统时钟
不过我们一般都前边倍频了肯定选择PLL当时钟
ClkInitTypeDef.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
AHBCLKDivider (AHB分频系数)(HLCK):
此参数可以传入
R CC_SYSCLK_DIV1 SYSCLK的值除以1 的值就是 HCLK 的值
R CC_SYSCLK_DIV2
R CC_SYSCLK_DIV4
R CC_SYSCLK_DIV8
R CC_SYSCLK_DIV16.。。。等等一直到512,他们是乘2得关系别搞错了、、、
APB1CLKDivider (低速APB预分频)(APB1)(PCLK1):
   
RCC_HCLK_DIV1      DIV1 ,2,4,8,16同上述也是乘2  最大16
不过我们APB1外设最大支持36Mhz所以在72Mhz下只能分频最少为2,它连接的是我们得低速外设
APB2CLKDivider (高速APB预分频)(APB2)(PCLK2)
RCC_HCLK_DIV1      DIV1 ,2,4,8,16同上述也是乘2  最大16
APB2外设最大支持72Mhz 属于高速外设
大家可能会好奇AHB是啥
AHB (Advanced High-performance Bus) 是高性能总线,用于连接核心处理单元(CPU)和片上的各种外设
他这里说的外设不是咱们的什么发光二极管、蜂鸣器、温湿度传感器啊,大家要分明白
这里指的是片内外设,说白了就是芯片上的外设,例如iic,spi,uart等等都属于上述所说
在我们stm32中我用大白话给大家说一下
为什么这么麻烦不直接一个时钟搞定,因为在不同的外设中我们可能有的需要低频,有的高频,如果不把他们分散开那么只能选择最高得来应用了这样功耗之类的就变大了,所以分布起来用哪个就打开相应的时钟这样就可以(大家猜猜?)
看中间72Mhz后边AHB在之后就是APB1,2等
好了到此配置就结束了,下边是HSE   HSI配置大家可以参考下
void HSIclock_init(void)
{
	RCC_OscInitTypeDef rcctypedf; //配置内外部时钟源的结构体
	rcctypedf.OscillatorType = RCC_OSCILLATORTYPE_HSI;  //选择内部高速时钟
	rcctypedf.HSIState = RCC_HSI_ON;  //打开内部高速时钟
	rcctypedf.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; //内部频率微调值选则默认
	rcctypedf.PLL.PLLState = RCC_PLL_ON; //打开PLL
	rcctypedf.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2; //HSI内部高速时钟2分频后作为PLL输入源
	rcctypedf.PLL.PLLMUL = RCC_PLL_MUL16; //倍频到16倍 8/2*16 = 64
	
	HAL_RCC_OscConfig(&rcctypedf); //根据 RCC_OscInitTypeDef 结构体参数配置时钟源
	
	RCC_ClkInitTypeDef ClkInitTypeDef; //配置总线时钟配置结构体
	/*配置的时钟有sysclk嵌入式系统的主要时钟,控制整个芯片的时序。配置此类型时钟将影响系统的运 
    行频率。
	HCLK表示高速总线时钟类型。HCLK是由SYSCLK分频得到的时钟,用于控制总线访问和外设的时钟频率。 
    配置此类型时钟将影响外设的工作速度。
	PCLK1和PCLK2表示外设时钟类型。这些时钟用于驱动微控制器的不同外设,例如UART、SPI、I2C等。配 
    置这些类型时钟将影响外设的工作速度。
	*/
	ClkInitTypeDef.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | 
    RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
	ClkInitTypeDef.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; //选择PLLclk作为时钟源
	ClkInitTypeDef.AHBCLKDivider = RCC_SYSCLK_DIV1;  // AHB不分频
	ClkInitTypeDef.APB1CLKDivider = RCC_HCLK_DIV2;   //APB1分频2
	ClkInitTypeDef.APB2CLKDivider = RCC_HCLK_DIV1;	 //APB2不分频
	/*HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef *RCC_ClkInitStruct, 
    uint32_t FLatency)
	第一个参数应传总线配置的结构体,第二个参数FLatency 表示闪存访问延迟
	配置FLatency (可选值3个)
	FLASH_LATENCY_0 0 等待周期(当 0 < SYSCLK < 24MHz)
	FLASH_LATENCY_1 1 等待周期当 24MHz < SYSCLK ≤ 48MHz
	FLASH_LATENCY_2 2 等待周期当 48MHz < SYSCLK ≤ 72MHz*/
	HAL_RCC_ClockConfig(&ClkInitTypeDef,FLASH_LATENCY_2);
};

void HSEclock_init(void)
{
	RCC_OscInitTypeDef rcctypedf; //配置内外部时钟源的结构体
	rcctypedf.OscillatorType = RCC_OSCILLATORTYPE_HSE;  //选择外部高速时钟
	rcctypedf.HSEState = RCC_HSE_ON;  //打开外部高速时钟
	rcctypedf.HSEPredivValue = RCC_HSE_PREDIV_DIV1; //HSE不分频
	rcctypedf.PLL.PLLState = RCC_PLL_ON; //打开PLL
	rcctypedf.PLL.PLLSource = RCC_PLLSOURCE_HSE; //HSE内部高速时钟2分频后作为PLL输入源
	rcctypedf.PLL.PLLMUL = RCC_PLL_MUL9; //倍频到9倍 8*9 = 72
	
	HAL_RCC_OscConfig(&rcctypedf); //根据 RCC_OscInitTypeDef 结构体参数配置时钟源
	
	RCC_ClkInitTypeDef ClkInitTypeDef; //配置总线时钟配置结构体
	/*配置的时钟有sysclk嵌入式系统的主要时钟,控制整个芯片的时序。配置此类型时钟将影响系统的运 
    行频率。
	HCLK表示高速总线时钟类型。HCLK是由SYSCLK分频得到的时钟,用于控制总线访问和外设的时钟频率。 
    配置此类型时钟将影响外设的工作速度。
	PCLK1和PCLK2表示外设时钟类型。这些时钟用于驱动微控制器的不同外设,例如UART、SPI、I2C等。配 
    置这些类型时钟将影响外设的工作速度。
	*/
	ClkInitTypeDef.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | 
    RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
	ClkInitTypeDef.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;  //选择PLLclk作为时钟源
	ClkInitTypeDef.AHBCLKDivider = RCC_SYSCLK_DIV1;  // AHB不分频
	ClkInitTypeDef.APB1CLKDivider = RCC_HCLK_DIV2;  //APB1分频2
	ClkInitTypeDef.APB2CLKDivider = RCC_HCLK_DIV1;  //APB2不分频
	/*HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef *RCC_ClkInitStruct, 
    uint32_t FLatency)
	第一个参数应传总线配置的结构体,第二个参数FLatency 表示闪存访问延迟
	配置FLatency (可选值3个)
	FLASH_LATENCY_0 0 等待周期(当 0 < SYSCLK < 24MHz)
	FLASH_LATENCY_1 1 等待周期当 24MHz < SYSCLK ≤ 48MHz
	FLASH_LATENCY_2 2 等待周期当 48MHz < SYSCLK ≤ 72MHz*/
	HAL_RCC_ClockConfig(&ClkInitTypeDef,FLASH_LATENCY_2);
}

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值