嵌入式开发九:STM32时钟系统

         时钟对于单片机来说是非常重要的,它为单片机工作提供一个稳定的机器周期从而使系统能够正常运行。时钟系统犹如人的心脏,一旦有问题整个系统就崩溃。我们知道 STM32 属于高级单片机,其内部有很多的外设,但不是所有外设都使用同一时钟频率工作,比如内部看门狗和 RTC,它只需 30 几 KHz 的时钟频率即可工作,所以内部时钟源就有多种选择,不同的时钟源,它们的频率不一样,这样便构成了时钟树。通过前面对于启动过程的分析,我们知道 STM32 系统复位后首先进入 SystemInit 函数进行时钟的设置,将 STM32F407 系统时钟设置为 168MHz,然后进入主函数。那么这个系统时钟大小如何得来,其他外设的时钟又如何划分,这些问题都可以通过一张时钟树图找到答案,只要理解好时钟树,STM32 一切时钟的来龙去脉就会非常清楚。本文详细介绍STM32F407的时钟树,并且知道如何使能外设的时钟。

目录

一、什么是时钟

1.1 时钟对单片机的作用

1.2 为什么要有时钟树

二、时钟树

2.1 时钟源

2.1.1 四个重要的时钟源

(1)外部高速时钟HSE

(2)外部低速时钟LSE

(3)内部高速时钟HSI

(4)内部低速时钟LSI

2.2 锁相环PLL(重要)

2.3 系统时钟 SYSCLK

2.4 AHB 总线时钟 HCLK

2.5 APB2 总线时钟 

2.6 APB1 总线时钟 

2.7 RTC时钟

2.8 独立看门狗时钟

2.9 MCO时钟输出

 2.10 总结    

三、时钟初始化过程及与时钟相关的函数

3.1  STM32F4 时钟初始化配置过程

3.2 STM32F4 时钟使能

3.2.1 时钟使能函数

3.2.1.1 外设时钟使能函数

3.2.1.2 时钟源使能函数

3.2.2 时钟功能函数

3.2.3 外设复位函数


一、什么是时钟

1.1 时钟对单片机的作用

       时钟是由电路产生的具有周期性的脉冲信号,众所周知,时钟系统是 CPU 的脉搏,就像人的心跳一样。所以时钟系统的重要性就不言而喻了。相当于单片机的心脏,要想使用单片机的外设必须开启相应的时钟,因为驱动外设的本质是操作寄存器,而寄存器是由D触发器构成,而触发器需要时钟才能改写值,所以要想操作寄存器必须开启对应外设的时钟。对CPU来说假设CPU在一个时钟周期内执行一条指令(二进制代码),若时钟频率越高,而时钟(周期)等于1/f为频率的倒数,则时钟周期更短代表在相同的时间内,CPU能够执行更多的指令,CPU的运行速度会更快。

1.2 为什么要有时钟树

        一个 MCU 越复杂,时钟系统也会相应地变得复杂,如 STM32F4 的时钟系统比较复杂,不像简单的 51 单片机一个系统时钟就可以解决一切。对于 STM32F4 系列的芯片,正常工作的主频可以达到 168Mhz,但并不是所有外设都需要系统时钟这么高的频率,比如看门狗以及 RTC 只需要几十 Khz 的时钟即可,此外,同一个电路,时钟越快功耗越大,同时抗电磁干扰能力也会越弱,所以对于较为复杂的 MCU 一般都是采取多时钟源的方法来解决这些问题。 STM32 本身非常复杂,外设非常的多,为了保持低功耗工作,STM32 的主控默认不开启这些外设功能。用户可以根据自己的需要决定 STM32 芯片要使用的功能,这个功能开关在 STM32 主控中也就是各个外设的时钟。 

      STM32时钟系统主要的目的就是给相对独立的外设模块提供时钟,主要也是为了降低整个芯片的功耗,所有外设时钟默认都是关闭状态(disable)当我们使用某个外设就要开启这个外设的时钟(enable),不同外设需要的时钟频率不同,没必要所有外设都用高速时钟造成浪费,而且有些外设也接受不了这么高的频率,这也是为什么STM32有四个时钟源的原因,就是兼容不同速度的外设,STM32的四个时钟源分别为:HSE、 LSE、HSI、LSI

二、时钟树

      首先让我们来看看 STM32F4 的时钟系统图:

先粗略看一下时钟图,STM32F4 时钟系统图看起来有点多且复杂,但是分开几部分各个理解其实没有那么难了,接下来就是分时钟源一一详细讲解(重点)。

       在 STM32F4 中,有 4个最重要的时钟源,为 HSI、HSE、LSI、LSE。从时钟频率来分可以分为高速时钟源和低速时钟源, HSI,HSE 是高速时钟,LSI 和 LSE 是低速时钟。从来源可分为外部时钟源和内部时钟源,外部时钟源就是从外部通过接石英晶体振荡器的方式获取时钟源,其中 HSE 和 LSE 是外部时钟源,LSE和LSI是内部时钟源,它是通过芯片内部的RC振荡电路实现。

2.1 时钟源

2.1.1 四个重要的时钟源

(1)外部高速时钟HSE

         HSE:High Speed External Clock signal,即高速的外部时钟。图标 3 HSE 是外部高速时钟, STM32ZGT6芯片的 23 和 24 引脚即为外部高速晶振管脚。可通过外接一个频率范围是 4-26MHz 的石英/陶瓷谐振器,我们开发板上接的是一个 8MHz 的外部晶振。

HSE 可以作为系统时钟和 PLL 锁相环输入,还可以经过 2-31分频后输入给 RTC。

(2)外部低速时钟LSE

         LSE :Low Speed External Clock signal), 图标 2 LSE 是外部低速时钟,我们开发板上 STM32 芯片的 PC14 和 PC15 即为外部低速时钟管脚。通常在此管脚上外接一个 32.768KHz 的晶振.

LSE主要作用于 RTC 的时钟源。

      以上2 个外部时钟源都是芯片外部晶振产生的时钟频率,故而都有精度高的优点 。

(3)内部高速时钟HSI

     HSI:High Speed Internal Clock signal),图标 4 HSI 是内部高速时钟,由内部 RC 振荡器产生频率为 16MHz。如果我们使用 HSE 或者 HSE 经过 PLL 倍频之后的时钟作为系统时钟SYSCLK, 当 HSE 故障时候,不仅 HSE 会被关闭,PLL 也会被关闭,此时高速的内部时钟时钟信号 HSI 会作为备用的系统时钟,直到 HSE 恢复正常。HSI RC振荡器能够在不需要任何外部器件的条件下提供系统时钟。它的启动时间比HSE晶体振荡器短。然而,即使在校准之后它的时钟频率精度仍较差,如果HSE晶体振荡器失效,HSI时钟会被作为备用时钟源。

可作为系统时钟或 PLL 锁相环的输入。

(4)内部低速时钟LSI

       LSI: low Speed Internal Clock signal,低速的内部时钟。图标 1 LSI 是内部低速时钟,RC 振荡器,频率大约为 32K,LSI 担当一个低功耗时钟源的角色,它可以在停机和待机模式下保持运行

可供独立看门狗和 RTC 使用

      芯片上电时默认由内部的 HSI 时钟启动,如果用户进行了硬件和软件的配置,芯片才会根据用户配置调试尝试切换到对应的外部时钟源,所以同时了解这几个时钟源信号还是很有必要的。

2.2 锁相环PLL(重要)

      锁相环是自动控制系统中常用的一个反馈电路,在 STM32 主控中,锁相环的作用主要有 两个部分:输入时钟净化和倍频。前者是利用锁相环电路的反馈机制实现,后者我们用于使芯片在更高且频率稳定的时钟下工作。 在 STM32 中,锁相环的输出也可以作为芯片系统的时钟源。PLL 的主要作用是对时钟进行倍频,然后把时钟输出到各个功能部件。图标 5 PLL 是锁相环,用于倍频输出,因为开发板外部高速晶振也只有 8M,而我们这块芯片的最大时钟频率是 168M,因此可通过 PLL 锁相环来倍频。 从图标 5 中可以看到,PLL 分两个,最上面一个称为主 PLL,下面那个称为专用 PLL.

PLL 为锁相环倍频输出。STM32F4 有两个 PLL:

1) 主 PLL(PLL)由 HSE 或者 HSI 提供时钟信号,并具有两个不同的输出时钟。 第一个输出 PLLP 用于生成高速的系统时钟(最高 168MHz) 第二个输出 PLLQ 用于生成 USB OTG FS 的时钟(48MHz),随机数发生器的时钟和 SDIO 时钟。

2)专用 PLL(PLLI2S)用于生成精确时钟,从而在 I2S 接口实现高品质音频性能。

从上面我们可以知道,PLL可以由HSE或者HSI通过倍频,从而产生168MHZ的系统时钟,那么它是怎么倍频产生 168MHz 系统时钟的呢?我们看到在主 PLL 内有倍频器和分频器,如下图所示。

从上图可以看出,它有两种可选择的输入源:一个是内部时钟 HSI 信号,另一个是外部时钟 HSE 信号。主 PLL 时钟源的输入信号要先经过一个分频系数为 M 的分频器,将 HSE 或 HSI 分频 M 值后输入给 VCO,经过一个倍频系数为 N 的倍频器, 再经过分频系数为 P 和 Q 的分频器,最终输出主 PLL 时钟和专用 PLL 时钟。

因此可以推倒出一个 PLL 时钟的计算公式:PLL=(HSE(HSI)/M)*N/P

 因为我们开发板上 HSE 是 8M 的晶振,如果将 M 值设置为 8,N 值为 336,P 值为 2,最后计算就可以得到主 PLL 为 168MHz。如果我们选择 HSE 是 PLL 的时钟源,PLL 是 SYSCLK 的时钟源,即 SYSCLK 为 168MHz,这个也是我们创建库函数模板所配置的最终系统时钟。

2.3 系统时钟 SYSCLK

     STM32 的系统时钟 SYSCLK 为整个芯片提供了时序信号。我们已经大致知道 STM32 主控 是时序电路链接起来的。对于相同的稳定运行的电路,时钟频率越高,指令的执行速度越快, 单位时间能处理的功能越多。STM32 的系统时钟是可通过寄存器配置的,在 STM32F4 系列中,它可以为 HSI、PLLCLK、HSE 中的一个。我们这里设置系统时钟:SYSCLK = PLLCLK = 168M。如果系统时钟是由 HSE 经过 PLL 倍频之后的 PLLCLK 得到的。

2.4 AHB 总线时钟 HCLK

       根据我们开发板的资源,可以把主频通过 PLL 设置为 168MHz。 从上面的时钟树图可知,AHB、APB1、APB2、内核时钟等时钟通过系统时钟分频得到。

  • 作用:为AHB总线的外设提供时钟、为Cortex系统定时器提供时钟(SysTick)、为内核提供时(FCLK)

        系统时钟 SYSCLK 经过 AHB 预分频器分频之后得到时钟叫 AHB 总线时钟,即 HCLK, 分频因子可以是:[1,2,4,8,16,64,128,256,512],具体的由时钟配置寄存器配置,在这里,我们选择不分频,所以 AHB 总线时钟达到最大的 168MHz。经过 8 分频后给 Cortex 系统定时器 Systick 提供时钟。系统定时器(基本定时器)在后面的章节中会介绍。

2.5 APB2 总线时钟 

       通过 AHB 分频器可以分出 AHB、APB1 和 APB2 时钟,它们都是由系统时钟经过分频得来。 APB2 总线时钟,由 HCLK 经过高速 APB2 预分频器得到,分频因子可以选择 1, 2,4,8,16,这里我们选择的是 2 分频,所以 APB2 总线时钟频率为 84M。

2.6 APB1 总线时钟 

       APB1 总线时钟,由 HCLK 经过低速 APB1 预分频器得到,分频因子可以选择 1, 2,4,8,16,这里我们选择的是 4 分频,所以 APB1 总线时钟为 42M。

AHB 时钟频率最大为 168MHz,APB2 时钟频率最大为 AHB 的 2 分频即 84MHz,APB1 时钟频率最大为 AHB 的 4 分频即 42MHz。从时钟频率大小来看,我们也就知道 AHB 的总线速度要比 APB2 快,APB2 的总线速度又比 APB1 快。

2.7 RTC时钟

      RTC 时钟。从图中线的流向可知,RTC 时钟来源可以是内部低速的 LSI 时钟,外部低速 LSE 时钟(32.768K),还可以通过 HSE 分频后得到,分频系数是 2-31。

2.8 独立看门狗时钟

     看门狗时钟。从图中线的流向可知,看门狗时钟源只能是低速的 LSI 时钟。

2.9 MCO时钟输出

      STM32 时钟输出管脚。可以把时钟信号输出供外部使用,也可以用示波器检测时钟信号的参数(峰峰值,频率…),这里是 STM32F4 输出时钟 MCO1 和 MCO2。MCO1 是向芯片的 PA8 引脚输出时钟。它有四个时钟来源分别为:HSI,LSE,HSE 和 PLL 时钟。MCO2 是向芯片的PC9 输出时钟,它同样有四个时钟来源分别为:HSE,PLL,SYSCLK 以及 PLLI2S 时钟。MCO 输出时钟频率最大不超过 100MHz。

 2.10 总结    

     

通过以上内容的介绍,我们知道 STM32F407 的时钟设计的比较复杂,各个时钟基本都是可控的,任何外设都有对应的时钟控制开关,这样的设计,对降低功耗是非常有用的,不用的外设不开启时钟,就可以大大降低其功耗。在时钟树图中我们还可以得到一个重要信息,大多数有关时钟输出部分都有 一个使能控制,比如 AHB 总线、APB1 外设、APB2 外设、内核时钟等。当需要使用某个时钟的时候一定要开启它的使能,否则将不工作。比如点亮一个 LED 实验就需要使能 GPIO 的外设时钟,如果不开启,LED 将不工作。

三、时钟初始化过程及与时钟相关的函数

3.1  STM32F4 时钟初始化配置过程

     上一节我们知道,STM32单片机上电,就会执行启动文件(汇编代码编写)中的复位程序。

执行复位程序
1.调用SystemInit系统初始化函数完成系统时钟的配置(配置成168MHZ)
2.调用_main函数初始化堆栈指针,然后再调用C库函数main函数,去到C语言的世界
所以跳转到C语言的main函数时,已经完成了系统时钟(SYSCLK)的配置。

STM32F4 时钟系统初始化是在 system_stm32f4xx.c 中的 SystemInit()函数中完成的。对于系统时钟关键寄存器设置主要是在 SystemInit 函数中调用 SetSysClock()函数来设置的。

      SystemInit 函数开始先进行浮点运算单元设置,然后是复位 PLLCFGR,CFGR 寄存器,同时 通过设置 CR 寄存器的 HSI 时钟使能位来打开 HSI 时钟。默认情况下如果 CFGR 寄存器复位, 那么是选择 HSI 作为系统时钟,这点大家可以查看 RCC->CFGR 寄存器的位描述最低 2 位可以 得知,当低两位配置为 00 的时候(复位之后),会选择 HSI 振荡器为系统时钟。也就是说,调用 SystemInit 函数之后,首先是选择 HSI 作为系统时钟。在设置完相关寄存器后,接下来 SystemInit 函数内部会调用 SetSysClock 函数。先使能外部时钟 HSE,等待 HSE 稳定之后,配置 AHB,APB1,APB2 时钟相关的分频因子,也就是相关外设的时钟。等待这些都配置完成之后, 打开主 PLL 时钟,然后设置主 PLL 作为系统时钟 SYSCLK 时钟源。如果 HSE 不能达到就绪状 态(比如外部晶振不能稳定或者没有外部晶振),那么依然会是 HSI 作为系统时钟。

        在设置主 PLL 时钟的时候,会要设置一系列的分频系数和倍频系数参数。这些参数是通过宏定义标识符的值来设置的。默认的配置在 System_stm32f4xx.c 文件开头的地 方配置。对于我们开发板,我们的设置参数值如下:

这里还有个特别需要注意的地方,就是我们还要同步修改 stm32f4xx.h 中宏定义标识符 HSE_VALUE 的值为我们的外部时钟:

#if !defined (HSE_VALUE) 
#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */#endif /* HSE_VALUE */

        这里默认固件库配置的是 25000000,我们外部时钟为 8MHz,所以我们根据我们硬件情况修改 为 8000000 即可。 

      讲到这里,大家对 SystemInit 函数的流程会有个比较清晰的理解。那么 SystemInit 函数是怎么被系统调用的呢?SystemInit 是整个设置系统时钟的入口函数。这个函数对于我们使用 ST 提供的 STM32F4 固件库的话,会在系统启动之后先执行 main 函数,然后再接着执行 SystemInit 函数实现系统相关时钟的设置。这个过程设置是在启动文件 startup_stm32f40_41xxx.s 中间设置的,我们接下来看看启动文件中这段启动代码:

; Reset handler
Reset_Handler PROCEXPORT Reset_Handler [WEAK]IMPORT SystemInitIMPORT __mainLDR R0, =SystemInitBLX R0LDR R0, =__mainBX R0ENDP

        这段代码的作用是在系统复位之后引导进入 main 函数,同时在进入 main 函数之前,首先 要调用 SystemInit 系统初始化函数完成系统时钟等相关配置。 最后我们总结一下 SystemInit()函数中设置的系统时钟大小:

SYSCLK(系统时钟) =168MHz
AHB 总线时钟(HCLK=SYSCLK) =168MHz
APB1 总线时钟(PCLK1=SYSCLK/4) =42MHz
APB2 总线时钟(PCLK2=SYSCLK/2) =84MHz
PLL 主时钟 =168MHz

3.2 STM32F4 时钟使能

     上小节我们讲解了系统复位之后调用 SystemInit 函数之后相关时钟的默认配置。如果在系统初始化之后,我们还需要修改某些时钟源配置,或者我们要使能相关外设的时钟该怎么设置 呢?这些设置实际是在 RCC 相关寄存器中配置的。因为 RCC 相关寄存器非常多,有兴趣的同学可以直接打开《STM32F4 中文参考手册》查看所有 RCC 相关寄存器的配置。所以这里我们不直接讲解寄存器配置,而是通过 STM32F4 标准固件库配置方法给大家讲解。

        在 STM32F4 标准固件库里,时钟源的选择以及时钟使能等函数都是在 RCC 相关固件库文 件 stm32f4xx_rcc.h 和 stm32f4xx_rcc.c 中声明和定义的。大家打开 stm32f4xx_rcc.h 文件可以看 到文件开头有很多宏定义标识符,然后是一系列时钟配置和时钟使能函数申明。这些函数大致 可以归结为三类,一类是外设时钟使能函数,一类是时钟源和分频因子配置函数,还有一类是外设复位函数。当然还有几个获取时钟源配置的函数。下面我们以几种常见的操作来简要介绍一下这些库函数的使用。

3.2.1 时钟使能函数

     首先是时钟使能函数。时钟使能相关函数包括外设时钟使能和时钟源使能两类。首先我们来看看外设时钟使能相关的函数:

3.2.1.1 外设时钟使能函数
void RCC_AHB1PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState);
void RCC_AHB2PeriphClockCmd(uint32_t RCC_AHB2Periph, FunctionalState NewState);
void RCC_AHB3PeriphClockCmd(uint32_t RCC_AHB3Periph, FunctionalState NewState);
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);

       这里主要有 5 个外设时钟使能函数。5 个函数分别用来使能 5 个总线下面挂载的外设时钟,这些总线分别为:AHB1 总线,AHB2 总线,AHB3 总线,APB1 总线以及 APB2 总线。要使能某个外设,调用对应的总线外设时钟使能函数即可。 这里我们要特别说明一下,STM32F4 的外设在使用之前,必须对时钟进行使能,如果没有使能时钟,那么外设是无法正常工作的。

         对于哪个外设是挂载在哪个总线之下,虽然我们也可以查手册查询到,但是这里如果大家使用的是库函数的话,实际上是没有必要去查询手册的, 这里我们给大家介绍一个小技巧。比如我们要使能 GPIOA,我们只需要在 stm32f4xx_rcc.h 头文件里面搜索 GPIOA,就可以搜索到对应的时钟使能函数的第一个入口参数为 RCC_AHB1Periph_GPIOA,从这个宏定义标识 符一眼就可以看出,GPIOA 是挂载在 AHB1 下面。同理,对于串口 1 我们可以搜索 USART1, 找到标识符为RCC_APB2Periph_USART1,那么很容易知道串口 1 是挂载在 APB2 之下。这个知识在我们后面的快速组织代码技巧也有讲解,这里顺带提一下。 如果我们要使能 GPIOA,那么我们可以在头文件 stm32f4xx_rcc.h 里面查看到宏定义标识 符 RCC_AHB1Periph_GPIOA,顾名思义 GPIOA 是挂载在 AHB1 总线之下,所以,我们调用 AHB1 总线下外设时钟使能函数 RCC_AHB1PeriphClockCmd 即可。具体调用方式入如下:

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//使能 GPIOA 时钟

同理,如果我们要使能串口 1 的时钟,那么我们调用的函数为:

void RCC_AHB2PeriphClockCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState); 
具体的调用方法是: RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
3.2.1.2 时钟源使能函数

      还有一类时钟使能函数是时钟源使能函数,前面我们已经讲解过 STM32F4 有 5 大类时钟 源。这里我们列出来几种重要的时钟源使能函数:

void RCC_HSICmd(FunctionalState NewState);
void RCC_LSICmd(FunctionalState NewState);
void RCC_PLLCmd(FunctionalState NewState);
void RCC_PLLI2SCmd(FunctionalState NewState);
void RCC_PLLSAICmd(FunctionalState NewState);
void RCC_RTCCLKCmd(FunctionalState NewState);

这些函数是用来使能相应的时钟源。比如我们要使能 PLL 时钟,那么调用的函数为:

void RCC_PLLCmd(FunctionalState NewState); 
具体调用方法如下: RCC_PLLCmd(ENABLE); 我们要使能相应的时钟源,调用对应的函数即可。

3.2.2 时钟功能函数

      接下来我们要讲解的是第二类时钟功能函数:时钟源选择和分频因子配置函数这些函数是用来选择相应的时钟源以及配置相应的时钟分频系数。比如我们之前讲解过系统时钟 SYSCLK,我们可以选择 HSI,HSE 以及 PLL 三个中的一个时钟源为系统时钟。那么到底选择哪 一个,这是可以配置的。下面我们列举几种时钟源配置函数:

void RCC_LSEConfig(uint8_t RCC_LSE);
void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource);
void RCC_HCLKConfig(uint32_t RCC_SYSCLK);
void RCC_PCLK1Config(uint32_t RCC_HCLK);
void RCC_PCLK2Config(uint32_t RCC_HCLK);
void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource);
void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t PLLM, 
uint32_t PLLN, uint32_t PLLP, uint32_t PLLQ);

比如我们要设置系统时钟源为 HSI,那么我们可以调用系统时钟源配置函数:

void RCC_HCLKConfig(uint32_t RCC_SYSCLK);
具体配置方法如下:
RCC_HCLKConfig(RCC_SYSCLKSource_HSI);//配置时钟源为 HSI

又如我们要设置 APB1 总线时钟为 HCLK 的 2 分频,也就是设置分频因子为 2 分频,那么 如果我们要使能 HSI,那么调用的函数为:

void RCC_PCLK1Config(uint32_t RCC_HCLK);
具体配置方法如下:
RCC_PCLK1Config(RCC_HCLK_Div2);

3.2.3 外设复位函数

       接下来我们看看第三类外设复位函数,

void RCC_AHB1PeriphResetCmd(uint32_t RCC_AHB1Periph, FunctionalState NewState);
void RCC_AHB2PeriphResetCmd(uint32_t RCC_AHB2Periph, FunctionalState NewState);
void RCC_AHB3PeriphResetCmd(uint32_t RCC_AHB3Periph, FunctionalState NewState);
void RCC_APB1PeriphResetCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);

这类函数跟前面讲解的外设时钟函数使用方法基本一致,不同的是一个是用来使能外设 钟,一个是用来复位对应的外设。这里大家在调用函数的时候一定不要混淆。 对于这些时钟操作函数,我们就不一一列举出来,大家可以打开 RCC 对应的文件仔细了解。

        以上便是STM32时钟系统的全部内容,如有兴趣,感谢点赞、关注、收藏,若有不正地方,还请各位大佬多多指教!

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深圳CPDA|如何利用数据分析改进业务流程,提高效率?

在当今数字化时代&#xff0c;数据已经成为企业决策和优化的关键资源。通过有效地收集、分析和应用数据&#xff0c;企业可以深入了解其业务流程中的瓶颈和问题&#xff0c;从而改进流程&#xff0c;提高效率。本文将探讨如何利用数据分析改进业务流程&#xff0c;并提高效率。…

利用智能私信软件,快速拓展潜在客户群体

在数字化营销的浪潮中&#xff0c;企业如何快速而有效地触及并吸引潜在客户&#xff0c;已成为一个不可忽视的挑战。随着人工智能技术的不断进步&#xff0c;智能私信软件作为一种新型工具&#xff0c;正逐渐改变着企业的市场拓展方式。本文将探讨如何通过这类软件&#xff0c;…

在Ubuntu上安装Anaconda之后,启动失败

为了方便管理Pythonu环境&#xff0c;在Ubuntu的Docker容器中安装了Anaconda&#xff0c;安装完成&#xff0c;启动时出现如下错误&#xff1a; conda activate xxx usage: conda [-h] [--no-plugins] [-V] COMMAND ... conda: error: argument COMMAND: invalid choice: acti…

【iOS】事件传递与响应机制

文章目录 前言事件UIEvent一、事件传递遍历顺序 二、手势识别三、响应机制UIResponder&#xff08;响应者&#xff09;响应者链 四、相关应用扩大button点击范围穿透事件 总结 前言 提到响应者链与事件传递&#xff0c;如果看过其他人的博客&#xff0c;经常能看到这经典的三张…

C++容器之vector类

目录 1.vector的介绍及使用1.1vector的介绍1.2vector的使用1.2.1 vector的定义1.2.2 vector iterator 的使用1.2.3 vector 空间增长问题1.2.4 vector 增删查改1.2.5vector 迭代器失效问题1.2.6 vector 在OJ中的使用。 2.vector深度剖析及模拟实现2.1 std::vector的核心框架接口…

bert-NER 转化成 onnx 模型

保存模型 加载模型 from transformers import AutoTokenizer, AutoModel, AutoConfigNER_MODEL_PATH ./save_model ner_tokenizer AutoTokenizer.from_pretrained(NER_MODEL_PATH) ner_config AutoConfig.from_pretrained(NER_MODEL_PATH) ner_model AutoModelForTokenCl…

5月9(信息差)

&#x1f30d; 可再生能源发电量首次占全球电力供应的三成 &#x1f384;马斯克脑机接口公司 Neuralink 计划将 Link 功能扩展至现实世界&#xff0c;实现控制机械臂、轮椅等 马斯克脑机接口公司 Neuralink 计划将 Link 功能扩展至现实世界&#xff0c;实现控制机械臂、轮椅等…

python代码无法点击进入,如何破???

python代码无法点击进入&#xff0c;如何破&#xff1f;&#xff1f;&#xff1f; 举个栗子&#xff1a; model.chat是无法进入的&#xff0c;这时可以使用如下的命令进行操作&#xff1a; ?model.chat

谷歌CEO最新访谈:AI浪潮仍处于早期阶段,公司未来最大威胁是执行力不足

作为搜索领域无可争议的霸主&#xff0c;谷歌改变了我们生活的方方面面&#xff0c;从日常琐事到工作事务&#xff0c;再到我们的沟通方式。多年来&#xff0c;谷歌一直是互联网的窗口&#xff0c;为我们提供大量知识和信息&#xff0c;但如今&#xff0c;随着其他类似平台的崛…

python面向函数

组织好的&#xff0c;可重复利用的&#xff0c;用来实现单一&#xff0c;或相关联功能的代码段&#xff0c;避免重复造轮子&#xff0c;增加程序复用性。 定义方法为def 函数名 (参数) 参数可动态传参&#xff0c;即使用*args代表元组形式**kwargs代表字典形式&#xff0c;代替…

使用 SSH 连接 GitHub Action 服务器

前言 Github Actions 是 GitHub 推出的持续集成 (Continuous integration&#xff0c;简称 CI) 服务它提供了整套虚拟服务器环境&#xff0c;基于它可以进行构建、测试、打包、部署项目&#xff0c;如果你的项目是开源项目&#xff0c;可以不限时使用服务器硬件规格&#xff1…

QT--4

QT 使用定时器完成闹钟 #include "widget.h" #include "ui_widget.h"void Widget::timestart() {timer.start(1000); }void Widget::timeend() {timer.stop(); }Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(t…