STM32F103系统时钟配置

一.系统时钟原理图

在这里插入图片描述
在 STM32f103 中,有五个时钟源,为 HSI、HSE、LSI、LSE、PLL。从时钟频率来分可以分为高速时钟源和低速时钟源,在这 5 个中 HIS,HSE 以及 PLL 是高速时钟,LSI 和 LSE 是低速时钟。从来源可分为外部时钟源和内部时钟源,外部时钟源就是从外部通过接晶振的方式获取时钟源,其中 HSE 和 LSE 是外部时钟源,其他的是内部时钟源。

二.系统时钟配置方法

1.通过汇编进入系统初始化函数(startup_stm32f10x_hd.s)

//通过汇编进入系统初始化函数
IMPORT  SystemInit       

2.在系统初始化函数SystemInit中调用系统时钟设置函数SetSysClock(system_stm32f10x.c)

//在系统初始化函数SystemInit中调用系统时钟设置函数SetSysClock()
void SystemInit (void)
{
  /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
  /* Configure the Flash Latency cycles and enable prefetch buffer */
  SetSysClock();
}

3.对各时钟进行宏定义(system_stm32f10x.c)

//对各时钟进行宏定义
#define SYSCLK_FREQ_HSE    HSE_VALUE //8000000
//#define SYSCLK_FREQ_16MHz  16000000 
//#define SYSCLK_FREQ_24MHz  24000000 
//#define SYSCLK_FREQ_36MHz  36000000
//#define SYSCLK_FREQ_48MHz  48000000
//#define SYSCLK_FREQ_56MHz  56000000
//#define SYSCLK_FREQ_72MHz  72000000

4.声明各系统时钟配置函数(system_stm32f10x.c)

//声明各系统时钟配置函数
#ifdef SYSCLK_FREQ_HSE
  static void SetSysClockToHSE(void);
#elif defined SYSCLK_FREQ_16MHz
  static void SetSysClockTo16(void);
#elif defined SYSCLK_FREQ_24MHz
  static void SetSysClockTo24(void);
#elif defined SYSCLK_FREQ_36MHz
  static void SetSysClockTo36(void);
#elif defined SYSCLK_FREQ_48MHz
  static void SetSysClockTo48(void);
#elif defined SYSCLK_FREQ_56MHz
  static void SetSysClockTo56(void);  
#elif defined SYSCLK_FREQ_72MHz
  static void SetSysClockTo72(void);
#endif

5.调用各系统时钟配置函数(system_stm32f10x.c)

//调用各系统时钟配置函数
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
  SetSysClockToHSE();                 //8MHz
#elif defined SYSCLK_FREQ_16MHz
  SetSysClockTo16();                  //16MHz
#elif defined SYSCLK_FREQ_24MHz
  SetSysClockTo24();                  //24MHz
#elif defined SYSCLK_FREQ_36MHz
  SetSysClockTo36();                  //36MHz
#elif defined SYSCLK_FREQ_48MHz
  SetSysClockTo48();                  //48MHz
#elif defined SYSCLK_FREQ_56MHz
  SetSysClockTo56();                  //56MHz
#elif defined SYSCLK_FREQ_72MHz
  SetSysClockTo72();                  //72MHz
#endif
 /* If none of the define above is enabled, the HSI is used as System clock
    source (default after reset) */ 
}

6.以设置系统时钟为16MHz为例(system_stm32f10x.c)

//设置系统时钟为16MHz
static void SetSysClockTo16(void)
{
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
  /* Enable HSE */    
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 
  /* Wait till HSE is ready and if Time out is reached exit */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;  
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }  

  if (HSEStatus == (uint32_t)0x01)
  {
#if !defined STM32F10X_LD_VL && !defined STM32F10X_MD_VL && !defined STM32F10X_HD_VL 
    /* Enable Prefetch Buffer */
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* Flash 0 wait state */
    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0;    
#endif
 
    /* HCLK = SYSCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
      
    /* PCLK2 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    
    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1;
		
    /*  PLL configuration:  = (HSE / 2) * 4 = 16 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_HSE_Div2 | RCC_CFGR_PLLMULL4);

    /* Enable PLL */
    RCC->CR |= RCC_CR_PLLON;

    /* Wait till PLL is ready */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }

    /* Select PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    

    /* Wait till PLL is used as system clock source */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    {
    }
  }
  else
  { /* If HSE fails to start-up, the application will have wrong clock 
         configuration. User can add here some code to deal with this error */
  } 
}

其中不同配置需要改的地方:
1)选择FLASH_ACR_LATENCY:
FLASH_ACR_LATENCY_0/FLASH_ACR_LATENCY_1/FLASH_ACR_LATENCY_2
FLASH_ACR_LATENCY的选择:
STM32的FLASH手册上,关于FLASH_ACR寄存器的LATENCY位的说明,上面明确写着:
0 wait state if 0MHz < SYSCLK <= 24MHz
1 wait state if 24MHz < SYSCLK <= 48MHz
2 wait state if 48MHz < SYSCLK <= 72MHz
2)配置PLL时钟:

    /*  PLL configuration:  = (HSE / 2) * 4 = 16 MHz */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_HSE_Div2 | RCC_CFGR_PLLMULL4);

三.获取各系统时钟方法

//在stm32f10x_rcc.h中定义
/*定义枚举类型变量获取时钟类型**/
typedef enum 
{
      SYSCLK_frequency=0u,     /* 获取SYSCLK时钟 */
	  AHB_frequency=1u,        /* 获取AHB时钟 */
	  APB1_frequency=2u,       /* 获取APB1时钟 */
	  APB2_frequency=3u,       /* 获取APB2时钟 */
	  ADCCLK_frequency=4u,     /* 获取APB2时钟 */
}RCC_clock_type;

u32 Get_rcc_clock(RCC_clock_type clock_type);      //声明获取当前时钟函数

//在stm32f10x_rcc.c中定义
u32 Get_rcc_clock(RCC_clock_type clock_type)
{
    u32 RCC_clock;
    RCC_ClocksTypeDef    get_rcc_clock;    //获取系统时钟状态
    RCC_GetClocksFreq(&get_rcc_clock);     //通过结构体get_rcc_clock获取各时钟
    switch (clock_type)
    {
      case SYSCLK_frequency:
        RCC_clock=get_rcc_clock.SYSCLK_Frequency;   //获取SYSCLK时钟
        break;
      case AHB_frequency:
        RCC_clock=get_rcc_clock.HCLK_Frequency;    //获取AHB时钟
        break;
      case APB1_frequency:
        RCC_clock=get_rcc_clock.PCLK1_Frequency;   //获取APB1时钟
        break;
      case APB2_frequency:
        RCC_clock=get_rcc_clock.PCLK2_Frequency;   //获取APB2时钟
        break;
	  case ADCCLK_frequency:
        RCC_clock=get_rcc_clock.ADCCLK_Frequency;   //获取ADCCLK时钟
        break;
      default:
        RCC_clock=0;
        break;
    }
    return RCC_clock;
}
//在main.c中获取当前时钟
	printf("SYSCLK_frequency=%d\r\n",Get_rcc_clock(SYSCLK_frequency));
	printf("AHB_frequency=%d\r\n",Get_rcc_clock(AHB_frequency));
	printf("APB1_frequency=%d\r\n",Get_rcc_clock(APB1_frequency));
	printf("APB2_frequency=%d\r\n",Get_rcc_clock(APB2_frequency));
	printf("ADCCLK_frequency=%d\r\n",Get_rcc_clock(ADCCLK_frequency));

四. 感谢支持

    完结撒花!希望看到这里的小伙伴能点个关注,我后续会持续更新,也欢迎大家广泛交流。
    码字实属不易,如果本文对你有10分帮助,就赏个10分把,感谢各位大佬支持!

在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tutu-hu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值