Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >STM32时钟系统

STM32时钟系统

作者头像
韦东山
发布于 2022-05-05 10:02:50
发布于 2022-05-05 10:02:50
56400
代码可运行
举报
文章被收录于专栏:韦东山嵌入式韦东山嵌入式
运行总次数:0
代码可运行

9.1 关于时钟

时钟对于一款芯片非常重要,其作用相当于人的心脏,人只有在心率正常稳定的情况下才能健康生活,同样的,芯片只有工作在合法正常的时钟频率下才能保证程序得到正常的运行。

本章就将从时钟树开始分析STM32F103的时钟系统,其中包括内部高速/低速时钟源、外部高速/低速时钟源、PLL(锁相环)和系统滴答定时器。以高屋建瓴的形式让用户对STM32F103的时钟系统有一个整体的认识,并在后续的时钟配置实验中让用户进一步的了解HAL库下的时钟配置流程。

首先读者要学会如何读STM32F103系列的时钟树,如图 9.1.1 所示,左侧的①HSI(内部高速时钟)、 ②HSE(外部高速时钟)、③LSE(外部低速时钟)、④LSI(内部低速时钟)为时钟源,右侧的各种片上外设。图中矩形框内用“/”加数字表示分频器, ,数字表示几分频;矩形框内用“X”加数字表示的为锁相环, ,数字表示几倍频;倒梯形表示选择器,长边表示多个输入,短边表示选择其中一个输出 。

⑥系统时钟SYSCLK最高为72MHz,从图中左侧的选择器SW可以看到来源有三个,分别是:①内部高速时钟HSI(绿色)、⑤锁相环时钟PLLCLK(紫色)和②外部高速时钟HSE(黄色),而锁相环时钟PLLCLK由内部高速时钟HSI和外部高速时钟HSE,经过分频和PLL锁相环倍频而来。

内部高速时钟HSI可直接经过选择器SW给系统时钟SYSCLK,此时系统时钟SYSCLK为8MHz;内部高速时钟HSI先2分频,再经过选择器PLLSRC进入锁相环PLLMUL,最大倍频为16倍,得到64MHz的锁相环时钟PLLCLK给系统时钟SYSCLK;当外部高速时钟HSE(假设外接晶振为8MHz时)直接给选择器SW,则系统时钟SYSCLK为8MHz;当外部高速时钟HSE(假设外接晶振为8MHz时)直接经过选择器PLLXTPRE给 PLLSRC,再经过PLLMUL 9倍频,得到72MHz的PLLCLK给系统时钟SYSCLK。

⑩RTCCLK(实时时钟)的时钟源也有三个,分别是②外部高速时钟HSE的128倍分频(黄色)、③外 部低速时钟LSE的32.768kHz(蓝色)、④内部低速时钟LSI的40kHz(橙色)。

11 IWDGCLK(独立看门狗)的时钟来源于④内部低速时钟LSI的40kHz(橙色)。

理清各个时钟来源后,再来看各总线的时钟。⑦高速接口总线AHB由⑥SYSCLK系统时钟分频得到,最高是系统时钟的72MHz。⑧外设总线APB1和⑨外设总线APB2,来源于⑦高速接口总线AHB,APB1的输出时钟最高是36MHz,APB2的输出时钟最高是72MHz。APB1和APB2下有各种外设,比如GPIO、USART等。

9.2 硬件设计

内部时钟HSI不涉及硬件,外部时钟HSE参考前面最小系统的时钟电路,“5.2.2 时钟电路”。

9.3 软件设计

9.3.1软件设计思路

实验目的:分别使用内部时钟HSI和外部时钟HSE作为系统时钟。

  1. 使用内部时钟HSI配置系统时钟到最大值64Mhz;
  2. 调用库函数读取系统时钟值以验证;
  3. 使用外部时钟HSE配置系统时钟到最大值72Mhz;
  4. 调用库函数读取系统时钟值以验证; 本实验配套代码位于“5_程序源码\3_基础重点—时钟系统”。

9.3.2软件设计讲解

  1. 使用内部时钟源HSI作为PLL的时钟源,然后将PLL作为系统时钟源 内部时钟HSI配置如代码段 9.3.1 所示,HAL库定义了两个结构体,只需要设置这两个结构体成员,就 完成对时钟的设置。

代码段 9.3.1 使用 HSI 作为系统时钟(stm32f1xx_clk.c)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
* @brief System Clock Configuration
* The system Clock is configured as follow : * System Clock source = PLL (HSI)
* SYSCLK(Hz) = 64000000
* HCLK(Hz) = 64000000
* AHB Prescaler = 1 * APB1 Prescaler = 2 * APB2 Prescaler = 1 * PLLMUL = 16
* Flash Latency(WS) = 2 * @param None
* @retval None
*/
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSEState = RCC_HSE_OFF;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
while(1);
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
while(1);
} }
  • 17行:定义RCC_OscInitTypeDef结构体变量,该结构体主要是选择时钟源、设置时钟开关状态、PLL倍频;
  • -20行:设置时钟来源为内部高速时钟HSI;
  • 21行:不使用外部高速时钟,则HSE关闭;
  • 22行:设置HSE预分频,这里没用上HSE,默认为1分频即可;
  • 23行:内部高速时钟HSI打开;
  • 24行:锁相环PLL打开;
  • 25行:选择PLL时钟源,为HSI的二分频;
  • 26行:PLL的倍频为16倍频;
  • 27行:使用“HAL_RCC_ClockConfig()”函数设置RCC_OscInitStruct;
  • 18行:定义RCC_ClkInitTypeDef结构体变量,该结构体主要是配置系统时钟、AHB、APB1、APB2的分频;
  • 34-35行:设置哪些时钟将被设置;
  • 36行:设置系统时钟SYSCLK的来源为PLLCLK;
  • 37行:设置HCLK时钟(AHB Clock)为1分频(不能超过最大72MHz);
  • 38行:设置PCLK1时钟(APB1 Clock)为2分频(不能超过最大36MHz);
  • 39行:设置PCLK2时钟(APB2 Clock)为1分频(不能超过最大72MHz);
  • 41行:用“HAL_RCC_ClockConfig()”函数设置RCC_ClkInitStruct;

将代码和时钟树进行对照,如图 9.3.1 所示,红色数字为对应代码行号,蓝色数字为时钟频率,红色线段为时钟走向。内部高速时钟HSI经过二分频为4MHz,再经过PLL 16倍频为64MHz,作为系统时钟SYSCLK, 再1分频给AHB,AHB再2分频给APB1,1分频给APB2。

2) 获取系统时钟的函数 主函数里调用HAL库提供的“HAL_RCC_GetSysClockFreq()”函数获取系统时钟验证。 代码段 9.3.2 获取系统时钟(main.c)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 此处定义全局变量以便在 debug 的时候可以看到这个变量的值
uint32_t sys_clk = 0;
int main(void) {
// 初始化 HAL 库函数必须要调用此函数
HAL_Init();
/*
* 系统时钟即 AHB/APB 时钟配置
* 当使用内部高速时钟 HSI(8MHz)配置系统时钟时,使用 PLL 前会默认先二分频得到 4MHz 的 PLL 分频输入频率
* 然后经过锁相环放大,最大放大倍数为 16,即 4*16=64MHz 是能配置的最大系统频率,F103 的最大系统频率为 72MHz,64MHz 显然是合法
的系统频率
*/
SystemClock_Config();
// 调用库函数来检验自己的配置是否成功配置为系统频率 64MHz
sys_clk = HAL_RCC_GetSysClockFreq();
while(1);
}
  1. 使用外部时钟源HSE作为PLL的时钟源,然后将PLL作为系统时钟源 与前面类似,这里设置外部高速时钟HSE作为系统时钟,仍是设置两个结构体。 代码段 9.3.3 使用 HSE 作为系统时钟(stm32f1xx_clk.c)
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/**
* @brief System Clock Configuration
* The system Clock is configured as follow : * System Clock source = PLL (HSE) * SYSCLK(Hz) = 72000000
* HCLK(Hz) = 72000000
* AHB Prescaler = 1 * APB1 Prescaler = 2 * APB2 Prescaler = 1 * PLLMUL = 9 * Flash Latency(WS) = 2 * @param None
* @retval None
*/
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_OFF;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
while(1);
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK
| RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
while(1);
} }
  • 17行:定义RCC_OscInitTypeDef结构体变量,该结构体主要是选择时钟源、设置时钟开关状态、PLL倍频;
  • 20行:设置时钟来源为外部高速时钟HSE;
  • 21行:内部高速时钟HSE打开;
  • 22行:设置HSE预分频,设置为1分频;
  • 23行:不使用内部高速时钟,则HSI关闭;
  • 24行:锁相环PLL打开;
  • 25行:选择PLL时钟源,为HSE;
  • 26行:PLL的倍频为9倍频;
  • 27行:使用“HAL_RCC_ClockConfig()”函数设置RCC_OscInitStruct;
  • 18行:定义RCC_ClkInitTypeDef结构体变量,该结构体主要是配置系统时钟、AHB、APB1、APB2的分频;
  • 34-35行:设置哪些时钟将被设置;
  • 36行:设置系统时钟SYSCLK的来源为PLLCLK;
  • 37行:设置HCLK时钟(AHB Clock)为1分频(不能超过最大72MHz);
  • 38行:设置PCLK1时钟(APB1 Clock)为2分频(不能超过最大36MHz);
  • 39行:设置PCLK2时钟(APB2 Clock)为1分频(不能超过最大72MHz);
  • 41行:用“HAL_RCC_ClockConfig()”函数设置RCC_ClkInitStruct;

将代码和时钟树进行对照,如图 9.3.2 所示,红色数字为对应代码行号,蓝色数字为时钟频率,红色线段为时钟走向。外部高速时钟HSE不分频,通过选择器PLLXTPRE和选择器PLLRC,再PLL 9倍频为72MHz,作为系统时钟SYSCLK,再1分频给AHB,AHB再2分频给APB1,1分频给APB2。当前状态,为MCU全速工作状态。

4) 获取系统时钟的函数 与前面类似,主函数里调用HAL库提供的“HAL_RCC_GetSysClockFreq()”函数获取系统时钟验证。 代码段 9.3.4 获取系统时钟(main.c)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
uint32_t sys_clk = 0;
int main(void) {
// 初始化 HAL 库函数必须要调用此函数
HAL_Init();
/*
* 系统时钟即 AHB/APB 时钟配置
* 当使用外部高速时钟 HSE(8MHz)配置系统时钟时,使用 PLL 前可以选择不分频或者二分频,我们要配置到最大 72MHz 的系统频率此处当
然是不分频
* 然后经过锁相环放大,最大放大倍数为 16,我们要想得到 72MHz,此处选择 9 倍放大系数,即 8*9=72MHz 即可达到目标
*/
SystemClock_Config();
// 调用库函数来检验自己的配置是否成功配置为系统频率 64MHz
sys_clk = HAL_RCC_GetSysClockFreq();
while(1);
}

9.4 实验效果

本实验对应配套资料的“5_程序源码\3_基础重点—时钟系统\”下的“3.1_HSI配置系统时钟64M”和 “3.2_HSE配置系统时钟72M”。打开工程后,参考前面“4.4 下载程序和调试”进入调试模式,在代码中找到“sys_clk”选中,右键选择“Add ‘sys_clk’ to …”->“Watch 1”,即可在右下角显示该变量查看窗口,可以看到当前“sys_clk”为0,如图 9.4.1 所示。

在“while(1);”处加上断点,运行程序,可以看到“sys_clk”分别为64000000和72000000,如图 9.4.3 和 图 9.4.4 所示,与代码设计吻合。如果显示16进制,可选中该数字,右键去掉勾选“Hexadecimal Dispaly”,如图 9.4.2 所示。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-04-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
stm32时钟配置简介
时钟是单片机非常重要的一部分,它为单片机的系统或是外设提供了时序。这里主要来讲解一下stm32的时钟配置。
飞哥
2020/07/10
1.4K0
stm32时钟配置简介
【STM32】系统时钟RCC详解(超详细,超全面)
时钟是单片机运行的基础,时钟信号推动单片机内各个部分执行相应的指令。时钟系统就是CPU的脉搏,决定cpu速率,像人的心跳一样 只有有了心跳,人才能做其他的事情,而单片机有了时钟,才能够运行执行指令,才能够做其他的处理 (点灯,串口,ADC),时钟的重要性不言而喻。
全栈程序员站长
2022/09/14
2.4K0
【STM32】系统时钟RCC详解(超详细,超全面)
单片机stm32的5个时钟源的详细分析
众所周知STM32有5个时钟源HSI、HSE、LSI、LSE、PLL,其实他只有四个,因为从上图中可以看到PLL都是由HSI或HSE提供的。
用户6754675
2020/05/07
3.6K0
STM32 RTC时钟
STM32 的 RTC 外设是一个掉电后还继续运行的定时器。 这里的掉电是指当主电源断开的时候,可以接上锂电池给RTC供电。RTC时钟具有计时和触发中断的功能,但是它比起其它外设强大在它的掉电可持续运行特性。
AnieaLanie
2021/12/08
1.6K0
【STM32F429】第7章 RL-TCPnet V7.X网络协议栈移植(RTX5)
最新教程下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=95243 第7章   RL-TCPnet网络协议栈移植(RTX5) 本章教程为大家讲
Simon223
2020/09/07
7170
【STM32F429】第7章   RL-TCPnet V7.X网络协议栈移植(RTX5)
【STM32H7教程】第16章 STM32H7必备的HAL库API(重要)
本章教程为大家讲解制作一个STM32H7的例子所需的最基本API函数,对于一些常用的API函数,一定要熟练掌握这些函数都是实现了什么功能,不常用的函数有个了解即可,用到的时候再去学。
Simon223
2019/05/15
2.5K0
【STM32H7教程】第16章       STM32H7必备的HAL库API(重要)
一文精通STM32时钟树-以F401为例
可通过多个预分频器配置 AHB 频率、高速 APB (APB2) 和低速 APB (APB1)。
云深无际
2025/02/06
3760
一文精通STM32时钟树-以F401为例
STM32入门时钟初始化配置函数
在前面推文的介绍中,我们知道STM32系统复位后首先进入SystemInit函数进行时钟的设置,然后进入主函数main。那么我们就来看下SystemInit()函数到底做了哪些操作,首先打开我们前面使用库函数编写的LED程序,在system_stm32f10x.c文件中可以找到SystemInit()函数,SystemInit()代码如下:
用户6754675
2020/05/18
1K0
STM32H743+RTT-Studio
本篇笔记主要介绍,在RT-Thread环境下,如何使用RT-Thread studio开发 STM32应用,以STM32H43为例介绍.
用户1605515
2020/11/06
1.3K0
STM32F4系统时钟树
时钟配置在system_stm32f4xx.c和stm32f4xx.h中,如PLL_M、PLL_N、PLL_P、PLL_Q、HSE_VALUE。 时钟配置函数:SystemInit()
小锋学长生活大爆炸
2020/11/24
1.2K0
STM32F4系统时钟树
STM32F10x从零开始配置时钟
实际上,对于STM32F10x系列的芯片,如果使用库函数方式开发,芯片的时钟初始化函数已经写好,并且在启动文件(例如startup_stm32f10x_hd.s)中被自动调用,在进入main函数之前,系统以及外设时钟均配置完成,main程序中不需要对时钟再进行任何配置,直接编写应用程序即可。但是作为一个底层驱动玩家必须要打破砂锅问到底,看看STM32F10x系列芯片的时钟系统到底是怎么样的以及如何配置时钟,下文将着重分析STM32F10x的时钟系统以及用寄存器方式从零开始一步一步配置时钟。
知否知否应是绿肥红瘦
2025/02/19
1780
STM32F10x从零开始配置时钟
Cubemx与HAL库系列教程|系统时钟配置详解及源码分析
STM32种类繁多,时钟系统也不尽相同,但基本的还是大差不差,今日小飞哥就F1系列的MCU简单聊一聊STM32的时钟系统
用户8913398
2022/03/04
2.9K0
Cubemx与HAL库系列教程|系统时钟配置详解及源码分析
【STM32F429开发板用户手册】第16章 STM32F429必备的HAL库API(重要)
本章教程为大家讲解制作一个STM32F4的例子所需的最基本API函数,对于一些常用的API函数,一定要熟练掌握这些函数都是实现了什么功能,不常用的函数有个了解即可,用到的时候再去学。
Simon223
2020/07/14
9160
【STM32F429开发板用户手册】第16章       STM32F429必备的HAL库API(重要)
【STM32F407】第4章 RTX5操作系统移植(MDK AC5)
论坛原始地址(持续更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=93149 第4章 RTX5操作系统移植(MDK AC5) 本章教程为
Simon223
2021/03/11
6350
【STM32F407】第4章   RTX5操作系统移植(MDK AC5)
【STM32H7教程】第80章 STM32H7的QSPI 总线应用之QSPI Flash的MDK下载算法制作
完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980 第80章 STM32H7的QSPI 总线应用之QSPI F
Simon223
2020/11/24
1.5K0
【STM32H7教程】第80章     STM32H7的QSPI 总线应用之QSPI Flash的MDK下载算法制作
基于STM32的智能粮仓系统设计
随着粮食质量要求的提高和储存方式的改变,对于粮仓环境的监测和控制也愈发重要。在过去的传统管理中,通风、防潮等操作需要定期人工进行,精度和效率都较低。而利用嵌入式技术和智能控制算法进行监测和控制,不仅能够实时掌握环境变化,还可以快速做出响应。
DS小龙哥
2023/07/08
8910
基于STM32的智能粮仓系统设计
【STM32】CubeMX+HAL 点亮LED
【1.2】 在 STM32CubeMX 的主界面中,点击 “New Project” 功能框中的 “ACCESS TO MCU SELECTOR” 功能按钮,从 MCU 开始新的工程。
AXYZdong
2020/11/05
1.2K0
【STM32】HAL库 STM32CubeMX教程六—-定时器中断
今天我们来学习定时器,32的定时器有着非常丰富的功能, 输入捕获/输出比较,PWM,中断等等。是我们学习STM32最频繁使用到的外设之一,所以一定要掌握好,这节我们讲解定时器中断,本系列教程将对应外设原理,HAL库与STM32CubeMX结合在一起讲解,使您可以更快速的学会各个模块的使用
全栈程序员站长
2022/08/11
4.4K0
【STM32】HAL库 STM32CubeMX教程六—-定时器中断
单片机STM32开发中常用库函数分析
注:一共16个优先级,分为抢占式和响应式。两种优先级所占的数量由此代码确定,NVIC_PriorityGroup_x可以是0、1、2、3、4,分别代表抢占优先级有1、2、4、8、16个和响应优先级有16、8、4、2、1个。规定两种优先级的数量后,所有的中断级别必须在其中选择,抢占级别高的会打断其他中断优先执行,而响应级别高的会在其他中断执行完优先执行。
用户6754675
2020/04/21
5720
STM32时钟系统之利用 systick 定时器来实现准确的延时。
  本篇文章带着大家来认识一下 STM32 的时钟系统,以及利用 systick 定时器来实现一个比较准确的延时。
用户6754675
2020/01/02
1K0
相关推荐
stm32时钟配置简介
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档