打印
[应用相关]

STM32F103系统时钟配置

[复制链接]
3378|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
coshi|  楼主 | 2021-7-7 13:21 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
一.系统时钟原理图

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


使用特权

评论回复
沙发
coshi|  楼主 | 2021-7-7 13:21 | 只看该作者
二.系统时钟配置方法

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) */
}


使用特权

评论回复
板凳
coshi|  楼主 | 2021-7-7 13:22 | 只看该作者
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);


使用特权

评论回复
地板
coshi|  楼主 | 2021-7-7 13:24 | 只看该作者
三.获取各系统时钟方法
//在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));


使用特权

评论回复
5
木木guainv| | 2021-8-6 12:36 | 只看该作者
介绍的非常详细啊

使用特权

评论回复
6
xiaoqizi| | 2021-8-6 12:40 | 只看该作者
最大的倍频是多少啊

使用特权

评论回复
7
wowu| | 2021-8-6 12:43 | 只看该作者
获取时钟的函数需要自己写吗

使用特权

评论回复
8
coshi|  楼主 | 2021-9-3 08:02 | 只看该作者
wowu 发表于 2021-8-6 12:43
获取时钟的函数需要自己写吗

不需要自己写啊

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

95

主题

3301

帖子

4

粉丝