当前位置: 首页 > news >正文

STM32是使用的内部时钟还是外部时钟

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)

#define RCC_CFGR_PLLSRC_HSE ((uint32_t)0x00010000)

//PLLSRC=1选择HSE时钟源

#define  RCC_CFGR_PLLMULL9  ((uint32_t)0x001C0000)

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

#define RCC_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_HSEPLLSRC=1选择HSE时钟源

// RCC_CFGR_PLLMULL9PLLMUL=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、配置后的时钟树

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • ArchLinux部署waydroid
  • leetcode-148. 排序链表
  • 系统架构师考点--系统架构设计(下)
  • 【Vue3】watchEffect
  • 基于Netty服务端快速了解核心组件
  • PHP师生荣誉管理系统—计算机毕业设计源码10079
  • RuntimeError: No CUDA GPUs are available
  • 【Redis 初阶】初识 Redis
  • 设计模式7原则
  • linux练习2
  • magento2 安装win环境和linux环境
  • Hive之扩展函数(UDF)
  • 【设计模式】工厂模式详解
  • 宝塔安装mysql5.7无法通过远程连接
  • 获取手机当前信号强度(dbm/asu值)解决 getGsmSignalStrength()总是返回99问题
  • java多线程
  • Just for fun——迅速写完快速排序
  • Redis提升并发能力 | 从0开始构建SpringCloud微服务(2)
  • select2 取值 遍历 设置默认值
  • SQLServer之创建显式事务
  • SSH 免密登录
  • UMLCHINA 首席专家潘加宇鼎力推荐
  • 初探 Vue 生命周期和钩子函数
  • 分享几个不错的工具
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 前端学习笔记之原型——一张图说明`prototype`和`__proto__`的区别
  • 人脸识别最新开发经验demo
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • 3月27日云栖精选夜读 | 从 “城市大脑”实践,瞭望未来城市源起 ...
  • 大数据全解:定义、价值及挑战
  • ​queue --- 一个同步的队列类​
  • ######## golang各章节终篇索引 ########
  • #FPGA(基础知识)
  • (17)Hive ——MR任务的map与reduce个数由什么决定?
  • (3)(3.2) MAVLink2数据包签名(安全)
  • (js)循环条件满足时终止循环
  • (poj1.2.1)1970(筛选法模拟)
  • (pojstep1.3.1)1017(构造法模拟)
  • (ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY)讲解
  • (Spark3.2.0)Spark SQL 初探: 使用大数据分析2000万KF数据
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (附源码)小程序儿童艺术培训机构教育管理小程序 毕业设计 201740
  • (十六)、把镜像推送到私有化 Docker 仓库
  • (原創) 系統分析和系統設計有什麼差別? (OO)
  • (转)JAVA中的堆栈
  • (自用)learnOpenGL学习总结-高级OpenGL-抗锯齿
  • (自用)仿写程序
  • .NET CORE 第一节 创建基本的 asp.net core
  • .net core使用ef 6
  • .Net MVC4 上传大文件,并保存表单
  • .NET 程序如何获取图片的宽高(框架自带多种方法的不同性能)
  • .Net 访问电子邮箱-LumiSoft.Net,好用
  • .net 简单实现MD5
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • .Net开发笔记(二十)创建一个需要授权的第三方组件