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

news2024/11/18 15:31:10

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1949112.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux:传输层(2) -- TCP协议(2)

目录 1. 流量控制 2. 滑动窗口 3. 拥塞控制 4. 延迟应答 5. 捎带应答 6. 面向字节流 7. 粘包问题 8. TCP异常情况 1. 流量控制 接收端处理数据的速度是有限的. 如果发送端发的太快 , 导致接收端的缓冲区被打满 , 这个时候如果发送端继续发送 , 就会造成丢包, 继而引…

享元模式(结构型)

目录 一、前言 二、享元模式 三、总结 一、前言 享元模式(Flyweight Pattern)是一种结构型设计模式,用于减少大量细粒度对象的内存占用。它通过共享尽可能多的相同数据来节约内存空间。 享元模式由以下角色组成: Flyweight&…

【OpenCV C++20 学习笔记】扫描图片数据

扫描图片数据 应用情景图像数据扫描的难点颜色空间缩减(color space reduction)查询表 扫描算法计算查询表统计运算时长连续内存3种扫描方法C风格的扫描方法迭代器方法坐标方法LUT方法 算法效率对比结论 应用情景 图像数据扫描的难点 在上一篇文章《基…

项目一缓存商品

文章目录 概要整体架构流程技术细节小结 概要 因为商品是经常被浏览的,所以数据库的访问量就问大大增加,造成负载过大影响性能,所以我们需要把商品缓存到redis当中,因为redis是存在内存中的,所以效率会比MySQL的快. 整体架构流程 技术细节 我们在缓存时需要保持数据的一致性所…

AHK是让任何软件都支持 Shift + 鼠标滚轮 实现界面水平滚动

目录 基本介绍 详细特点 图解安装 下载失败?缓慢? 创建并运行脚本代码😃 新建空 xxx.ahk文件 vscode/记事本等编辑工具打开 复制并粘贴简易脚本 运行 其他问题 问题一:弹出无法执行此脚本 关闭脚本 基本介绍 AutoHot…

zookeeper开启SASL权限认证

目录 一、SASL介绍 二、使用 SASL 进行身份验证 2.1 服务器到服务器的身份验证 2.2 客户端到服务器身份验证 三、验证功能 一、SASL介绍 默认情况下,ZooKeeper 不使用任何形式的身份验证并允许匿名连接。但是,它支持 Java 身份验证与授权服务(JAAS)…

用户需要什么-软件的工程可用性(第一部分)01

Larry L. Constantine 著,Huang Yin 译 “究竟用户的需要是什么?”如果 Fred 作为一个程序员而不是一个心理学家时他可能会提出这 样一个问题。用户们通常需要更多,而开发人员似乎看上去并不能很好的领会并更好的满足他们。对于我们而言&…

WPF使用TouchSocket实现Tcp client

文章目录 前言1、页面展示2、主页面UI代码2、TCP client的UI代码3、Tcp client后台代码实现4、UI与后台代码的关联 前言 在该篇的Demo中,您可以找到以下内容: 1、TouchSocket的使用; 2、CommunityToolkit.Mvvm的使用; 3、AvalonD…

IF=8.5 MIMIC-IV高阶玩法!中国用新指标SHR+机器学习拿一区top,思路太牛了

‍ MIMIC-IV 发文难?那是你还没遇到对的思路!如今机器学习数据库挖掘的文章层出不穷,今天介绍的这篇文章是在MIMIC-IV数据库的基础上,用了一个新指标—应激性高血糖比(SHR),结合机器学习构建预测…

【iOS】——Block循环引用

循环引用原因 如果在Block中使用附有_ _strong修饰符的对象类型自动变量,那么当Block从栈复制到堆时,该对象为Block所持有,这样容易引起循环引用。 HPPerson *person [[HPPerson alloc] init];person.block ^{NSLog("person.age--- …

Redis使用场景-热点数据缓存

什么是缓存? 为了把一些经常访问的数据放入缓存中已减少对数据库的访问,从而减少数据库的压力,提高程序的性能。【内存中存储】-效率快 缓存的原理 什么样的数据适合放入缓存中? 1.查询频率高且修改频率低 2.数据安全性低 哪些组件…

《python语言程序设计》第6章第7题财务应用程序:计算未来投资,编写函数计算制定年数以给定利率

记住这里增加循环应该是以年为单位。但是添加的数是月为单位 此处需留意其实点不是1,1代表1年,这里月所以其实是12,这里的单位是月,而不是年。 python for i in range(12,monthNum12,12) 如果你把12都换成1呢?&…

本地生活抽佣系统搭建:如何让系统具有竞争优势?

随着本地生活的潜力不断展现,本地生活服务商逐渐成为新兴职业中的一大热门,本地生活抽佣系统搭建的热度也一直保持着飙升的状态。 抖音生活发布的《2023年数据报告》显示,2023年,抖音生活服务平台总交易额增长256%,抖…

监测Nginx访问日志状态码,并做相应动作

文章目录 引言I 监测 Nginx 访问日志情况,并做相应动作1.1 前提准备1.2 访问日志 502 情况,重启 bttomcat9服务1.3 其他案例:访问日志 502 情况,重启 php-fpm 服务II 将Shell 脚本check499.sh包装成systemd服务2.1 创建systemd服务2.2 配置service2.3 开机启动2.4 其他常用…

自监督学习概述(Self-Supervised Learning,SSL)

自监督学习(Self-Supervised Learning,SSL)是一种机器学习方法,旨在利用未标记数据进行训练。这种方法通过从数据本身生成伪标签,来创建监督信号,使得模型能够学习有效的数据表示。自监督学习在深度学习领域…

HTTP传输下载和P2P传输下载的区别?

HTTP传输下载和P2P(Peer-to-Peer)传输下载在多个方面存在显著的区别,以下是详细的分析: 1. 工作原理 HTTP传输下载: HTTP(Hypertext Transfer Protocol)是一种用于在Web上进行数据通信的协议&…

PHP多功能投票系统源码小程序

🎉决策不再难!「多功能投票小程序」一键搞定所有选择困难症✨ 🤔选择困难?「多功能投票小程序」来救场! 每次聚会、团队讨论还是日常小决策,是不是总有那么几个瞬间让你陷入“选哪个好呢?”的…

spine to unity-2.利用边缘框实现实时碰撞检测

主要讲spine的边缘框,在unity中,实现实时碰撞检测。其中使用的素材,是我为独立游戏ink制作的动画。独立游戏ink的开发日志,在小红薯持续更新中。spine工具包的安装,下载请参考spine to unity-1spine BoundingBoxFollow…

【MySQL篇】Percona XtraBackup标准化全库完整备份策略(第三篇,总共五篇)

💫《博主介绍》:✨又是一天没白过,我是奈斯,DBA一名✨ 💫《擅长领域》:✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux,也在扩展大数据方向的知识面✌️…

STM32H7的LPUART基础和唤醒示例

STM32H7的LPUART基础知识 硬件框图低功耗的高级特性低功耗串口的时钟以及波特率低功耗串口发送时序低功耗串口支持的唤醒方式 LPUART 的全称是 Low power universal synchronous asynchronous receiver transmitter,中文意思是低功耗通用异步收发器,简称…