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

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

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

相关文章

Jacoco 单元测试配置

前言 编写单元测试是开发健壮程序的有效途径,单元测试写的好不好可以从多个指标考量,其中一个就是单元测试的覆盖率。单元测试覆盖率可以看到我们的单元测试覆盖了多少代码行、类、分支等。查看单元测试覆盖率可以使用一些工具帮助我们计算,…

在IDEA中切换分支没有反应

说明:记录一次在IDEA中切换分支没有反应的情况,新建一个分支后,准备暂存代码,切换到其他分支去,发现怎么切都没有反应,也没有切过去; 解决:首先,我想到是不是当前新分支…

如何解决 Nginx 与无服务器架构的集成问题?

🍅关注博主🎗️ 带你畅游技术世界,不错过每一次成长机会! 文章目录 如何解决 Nginx 与无服务器架构的集成问题? 如何解决 Nginx 与无服务器架构的集成问题? 在当今的云计算时代,无服务器架构因…

机器学习驱动的智能化电池管理技术与应用

目录 主要内容 电池管理技术概述 电池的工作原理与关键性能指标 电池管理系统的核心功能 SOC估计 SOH估计 寿命预测 故障诊断 人工智能机器学习 基础 人工智能的发展 机器学习的关键概念 机器学习在电池管理中的应用案例介绍 人工智能在电池荷电状态估计中的…

AttributeError: ‘list‘ object has no attribute ‘text‘

AttributeError: ‘list‘ object has no attribute ‘text‘ 目录 AttributeError: ‘list‘ object has no attribute ‘text‘ 【常见模块错误】 【解决方案】 示例代码 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页,我是博主英…

谷粒商城实战笔记-63-商品服务-API-品牌管理-OSS获取服务端签名

文章目录 一,创建第三方服务模块thrid-party1,创建一个名为gulimall-third-party的模块2,nacos上创建third-party命名空间,用来管理这个服务的所有配置3,配置pom文件4,配置文件5,单元测试6&…

模型剪枝中有哪些经验|mobile-yolov5-pruning-distillation项目中剪枝知识分析

项目地址:https://github.com/Syencil/mobile-yolov5-pruning-distillation 项目时间:2022年 mobile-yolov5-pruning-distillation是一个以yolov5改进为主的开源项目,主要包含3中改进方向:更改backbone、模型剪枝、知识蒸馏。这里…

路由表与IP数据报的转发

前言:本博客仅作记录学习使用,部分图片出自网络,如有侵犯您的权益,请联系删除 一、相关知识 1、路由类型 路由表中有3类路由:直连路由、静态路由、动态路由 直连路由:一般指去往路由器接口直接连接网络的…

JAW:一款针对客户端JavaScript的图形化安全分析框架

关于JAW JAW是一款针对客户端JavaScript的图形化安全分析框架,该工具基于esprima解析器和EsTree SpiderMonkey Spec实现其功能,广大研究人员可以使用该工具分析Web应用程序和基于JavaScript的客户端程序的安全性。 工具特性 1、动态可扩展的框架&#x…

LeetCode 2844.生成特殊数字的最少操作(哈希表 + 贪心)

给你一个下标从 0 开始的字符串 num ,表示一个非负整数。 在一次操作中,您可以选择 num 的任意一位数字并将其删除。请注意,如果你删除 num 中的所有数字,则 num 变为 0。 返回最少需要多少次操作可以使 num 变成特殊数字。 如…

vue接入google map自定义marker教程

需求背景 由于客户需求,原来系统接入的高德地图,他们不接受,需要换成google地图。然后就各种百度,各种Google,却不能实现。----无语,就连google地图官方的api也是一坨S-H-I。所以才出现这篇文章。 google地…

CSS(七)——CSS 列表和CSS Table(表格)

目录 CSS 列表 列表 作为列表项标记的图像 列表 - 简写属性 移除默认设置 所有的CSS列表属性 CSS 表格 表格边框 折叠边框(border-collapse) 表格宽度和高度 表格文字对齐 表格填充 表格颜色 CSS 列表 CSS 列表属性作用如下: 设…

Hello SLAM(在Linux中实现第一个C++程序)

首先需要安装vim编辑器,输入命令 sudo apt install vim 在Ubuntu上安装好vim编辑器后,创建路径(/home/slambook/ch2),在该路径下创建一个cpp文档(touch hello.c),通过vim编辑器进行…

【OpenCV C++20 学习笔记】图片处理基础

OpenCV C20 图片处理基础 VS 2022 C20 标准库导入的问题头文件包含以及命名空间声明main函数读取图片读取检查显式图片写入图片 完整代码bug VS 2022 C20 标准库导入的问题 VS还没有完全兼容C20。C20的import语句不一定能正确导入标准库,所以必须要新建一个头文件专…

【全面介绍Python多线程】

🎥博主:程序员不想YY啊 💫CSDN优质创作者,CSDN实力新星,CSDN博客专家 🤗点赞🎈收藏⭐再看💫养成习惯 ✨希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共同学习、交流进步! 🦇目录 1. 🦇前言2. 🦇threading 模块的基本用法3. 🦇Thre…

.NET 相关概念

.NET 和 .NET SDK .NET 介绍 .NET 是一个由 Microsoft 开发和维护的广泛用于构建各种类型应用程序的开发框架。它是一个跨平台、跨语言的开发平台,提供了丰富的类库、API和开发工具,支持开发者使用多种编程语言(如C#、VB.NET、F#等&#xf…

[C++进阶]多态的概念、定义与实现

多态,顾名思义,即多种形态。具体来说,就是不同对象执行同一行为而产生不同的结果。 一、多态的概念 多态的概念:通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生…

机器学习 | 回归算法原理——随机梯度下降法

Hi,大家好,我是半亩花海。接着上次的多重回归继续更新《白话机器学习的数学》这本书的学习笔记,在此分享随机梯度下降法这一回归算法原理。本章的回归算法原理还是基于《基于广告费预测点击量》项目,欢迎大家交流学习!…

NET8部署Kestrel服务HTTPS深入解读TLS协议之Certificate证书

Certificate证书 Certificate称为数字证书。数字证书是一种证明身份的电子凭证,它包含一个公钥和一些身份信息,用于验证数字签名和加密通信。数字证书在网络通信、电子签名、认证授权等场景中都有广泛应用。其特征如下: 由权威机构颁发&…