STM32是使用的内部时钟还是外部时钟
创始人
2024-11-18 23:06:44
0

STM32是使用的内部时钟还是外部时钟,经常会有人问这个问题。

1、先了解时钟树,见下图:

2、在MDK中,使用的是HSE+PLL作为SYSCLK,因此需要对时钟配置寄存器(RCC_CFGR)进行配置,寄存器内容如下:

根据时钟树,需要对时钟配置寄存器(RCC_CFGR)的PLLXTPRE(bit17),PLLSRC(bit16),PLLMUL[3:0](bit21:18),SW[1:0](bit1:0)进行配置。

#define  RCC_CFGR_PLLXTPRE ((uint32_t)0x00020000) 

// RCC_CFGR)的PLLXTPRE(bit17)

#defineRCC_CFGR_PLLSRC_HSE ((uint32_t)0x00010000)

//令PLLSRC=1选择HSE时钟源

#define  RCC_CFGR_PLLMULL9  ((uint32_t)0x001C0000)

//令PLLMUL=7,设置PLL乘法因子为9

#defineRCC_CFGR_SW_PLL ((uint32_t)0x00000002)  // SW选择PLL作为系统时钟源

static void SetSysClockTo72(void)

{

  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/   

  /* Enable HSE */    

  RCC->CR |= ((uint32_t)RCC_CR_HSEON);  //使能HSE外部时钟

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

  {

    /* Enable Prefetch Buffer */

    FLASH->ACR |= FLASH_ACR_PRFTBE;

    /* Flash 2 wait state */

    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);

    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;   

    /*设置AHB分频器的值为0,则HCLK = SYSCLK=72MHz */

RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;

     

    /*设置APB2分频器的值为0,则 PCLK2 = HCLK= SYSCLK=72MHz */

    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

   

    /*设置APB1分频器的值为2,则PCLK1 = HCLK/2=36MHz */

    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#ifdef STM32F10X_CL

    /* Configure PLLs ------------------------------------------------------*/

    /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */

    /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */

       

    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |

                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);

    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |

                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);

    /* Enable PLL2 */

    RCC->CR |= RCC_CR_PLL2ON;

    /* Wait till PLL2 is ready */

    while((RCC->CR & RCC_CR_PLL2RDY) == 0)

    {

    }

   

    /* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */

    RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);

    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |

                            RCC_CFGR_PLLMULL9);

#else   

    /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */

    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |

                                        RCC_CFGR_PLLMULL));

    //利用RCC_CFGR_PLLXTPRE将PLLXTPRE=0,HSE输入时钟不用分频

RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);

// RCC_CFGR_PLLSRC_HSE令PLLSRC=1选择HSE时钟源

// RCC_CFGR_PLLMULL9令PLLMUL=7,设置PLL乘法因子为9

//至此外部晶振为8MHz,到这里就是72MHz了

#endif /* STM32F10X_CL */

    /* 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;

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

  }

}

3、系统是怎么调用SetSysClockTo72()

STM32默认是使用HSI内部RC 8MHz启动的,上电复位会执行Reset_Handler,见下图:

在Reset_Handler中,有一个SystemInit,就是C语言的SystemInit()函数,复位中断执行结束后则跳转到main(),SystemInit()函数原型如下:

void SystemInit (void)

{

  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */

  /* Set HSION bit */

  RCC->CR |= (uint32_t)0x00000001;

  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */

#ifndef STM32F10X_CL

  RCC->CFGR &= (uint32_t)0xF8FF0000;

#else

  RCC->CFGR &= (uint32_t)0xF0FF0000;

#endif /* STM32F10X_CL */  

  /* Reset HSEON, CSSON and PLLON bits */

  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* Reset HSEBYP bit */

  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */

  RCC->CFGR &= (uint32_t)0xFF80FFFF;

#ifdef STM32F10X_CL

  /* Reset PLL2ON and PLL3ON bits */

  RCC->CR &= (uint32_t)0xEBFFFFFF;

  /* Disable all interrupts and clear pending bits  */

  RCC->CIR = 0x00FF0000;

  /* Reset CFGR2 register */

  RCC->CFGR2 = 0x00000000;

#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)

  /* Disable all interrupts and clear pending bits  */

  RCC->CIR = 0x009F0000;

  /* Reset CFGR2 register */

  RCC->CFGR2 = 0x00000000;     

#else

  /* Disable all interrupts and clear pending bits  */

  RCC->CIR = 0x009F0000;

#endif /* STM32F10X_CL */

   

#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)

  #ifdef DATA_IN_ExtSRAM

    SystemInit_ExtMemCtl();

  #endif /* DATA_IN_ExtSRAM */

#endif

  /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */

  /* Configure the Flash Latency cycles and enable prefetch buffer */

  SetSysClock();//设置系统时钟

#ifdef VECT_TAB_SRAM

  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */

#else

  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */

#endif

}

static void SetSysClock(void)

{

#ifdef SYSCLK_FREQ_HSE

  SetSysClockToHSE();

#elif defined SYSCLK_FREQ_24MHz

  SetSysClockTo24();

#elif defined SYSCLK_FREQ_36MHz

  SetSysClockTo36();

#elif defined SYSCLK_FREQ_48MHz

  SetSysClockTo48();

#elif defined SYSCLK_FREQ_56MHz

  SetSysClockTo56(); 

#elif defined SYSCLK_FREQ_72MHz

  SetSysClockTo72();

//由于在“Options for Target 'CAN Slave'”中定义了STM32F10X_MD,所以程序会执行这条语句配置系统时钟

#endif

 /* If none of the define above is enabled, the HSI is used as System clock

    source (default after reset) */

}

程序调用SetSysClockTo72()的说明如下:

在“Options for Target 'CAN Slave'”中定义了STM32F10X_MD,见下图:

因此,在MAK-ARM中,会调用SetSysClockTo72()这个函数,从而实现对系统的配置。

4、HSE,HIS和PLL时钟启动和工作状态

MDK已经写好了,就不要去逐句理解了。我们的目的是会使用,因此,只要重点掌握CPU是从HSI时钟切换到HSE,使用PLL使用作为系统时钟,就可以了。如果你想做低功耗,就需要你自己去深入学习时钟树和内部寄存器的用法。

5、配置后的时钟树

相关内容

热门资讯

透视辅助!AApOKER软件透... 透视辅助!AApOKER软件透明挂,aapoker后台好像是有挂(详细透明挂教程);进入游戏-大厅左...
红龙扑克辅助!红龙扑克都是机器... 红龙扑克辅助!红龙扑克都是机器人吗(红龙扑克)真是有挂(详细辅助器教程)1、不需要AI权限,帮助你快...
黑科技透明挂!德州wepowe... 黑科技透明挂!德州wepower好像真的有挂,Wepoke透明挂总是存在有挂(详细黑科技教程)1、每...
wepoke透视挂!cloud... wepoke透视挂!cloudpoker本来真的有挂,wpk脚本(详细脚本辅助器安装教程)1、wep...
德扑之星开桌(德扑之星有辅)辅... 德扑之星开桌(德扑之星有辅)辅助工具(辅助挂)竟然有挂(详细手牌教程);辅助插件是一个在免局卡环境下...
六分钟了解!德扑之星辅助工具,... 六分钟了解!德扑之星辅助工具,德扑之星有辅真是是真的有挂(详细有作弊教程)1、系统规律教程、辅助透视...
黑科技辅助!wEpoke总是存... 黑科技辅助!wEpoke总是存在有挂,Wepoke后台本来真的是有挂(详细ai代打的胜率教程)1、点...
红龙扑克辅助!哈糖大菠萝一贯有... 红龙扑克辅助!哈糖大菠萝一贯有挂,wepoke有挂 网上(详细透明挂辅助器教程),您好,红龙扑克辅助...
8分钟了解!微扑克辅助器,微扑... 8分钟了解!微扑克辅助器,微扑克规律竟然有挂(详细辅助器ios教程)1、系统规律教程、辅助透视等服务...
aapoker透视辅助(aap... aapoker透视辅助(aapker代理)aa扑克平台(透视)原来有挂(详细有外卦挂教程)1、每一步...