第15章 RCC—使用HSE/HSI配置时钟—零死角玩转STM32-F429系列

STM32使用HSE/HSI配置时钟 STM32时钟树 系统时钟 ①HSE 高速外部时钟信号 HSE 是高速外部时钟信号,可以由有源晶振或者无源晶振提供,频率为4~16MHz。当使用有源晶振时,时钟从OSC_IN引脚进入,OSC_OUT引脚悬空;当使用无源晶振时,时钟从OSC_IN和OSC_OUT进入,并且要配谐振电容。 HSE最常使用的是8MHz的无源晶振。当确定PLL时钟来源的时候,HSE 可以不分频或者2分频,这个由时钟配置寄存器CFGR的位17,即PLLXTRE设置。 ②PLL时钟源 PLL时钟来源可以有两个:一个是HSE, 阅读详情
第15章     RCC—使用HSE/HSI配置时钟

全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn

野火视频教程优酷观看网址:http://i.youku.com/firege

 

 

 

本章参考资料:《STM32F4xx中文参考手册》RCC章节。

学习本章时,配合《STM32F4xx中文参考手册》RCC章节一起阅读,效果会更佳,特别是涉及到寄存器说明的部分。

RCC :reset clock control  复位和时钟控制器。本章我们主要讲解时钟部分,特别是要着重理解时钟树,理解了时钟树,F429的一切时钟的来龙去脉都会了如指掌。

1.1 RCC主要作用—时钟部分

设置系统时钟SYSCLK、设置AHB分频因子(决定HCLK等于多少)、设置APB2分频因子(决定PCLK2等于多少)、设置APB1分频因子(决定PCLK1等于多少)、设置各个外设的分频因子;控制AHB、APB2和APB1这三条总线时钟的开启、控制每个外设的时钟的开启。对于SYSCLK、HCLK、PCLK2、PCLK1这四个时钟的配置一般是:HCLK = SYSCLK=PLLCLK = 180M,PCLK2=HCLK/2 = 90M,PCLK1=HCLK/4 = 45M。这个时钟配置也是库函数的标准配置,我们用的最多的就是这个。

1.2 RCC框图剖析—时钟树

时钟树单纯讲理论的话会比较枯燥,如果选取一条主线,并辅以代码,先主后次讲解的话会很容易,而且记忆还更深刻。我们这里选取库函数时钟系统时钟函数:SetSysClock(); 以这个函数的编写流程来讲解时钟树,这个函数也是我们用库的时候默认的系统时钟设置函数。该函数的功能是利用HSE把时钟设置为:HCLK = SYSCLK=PLLCLK = 180M,PCLK1=HCLK/2 = 90M,PCLK1=HCLK/4 = 45M下面我们就以这个代码的流程为主线,来分析时钟树,对应的是图中的黄色部分,代码流程在时钟树中以数字的大小顺序标识。

图 151 STM32F429时钟树

1.2.1 系统时钟
1.    ①HSE高速外部时钟信号

HSE是高速的外部时钟信号,可以由有源晶振或者无源晶振提供,频率从4-26MHZ不等。当使用有源晶振时,时钟从OSC_IN引脚进入,OSC_OUT引脚悬空,当选用无源晶振时,时钟从OSC_IN和OSC_OUT进入,并且要配谐振电容。HSE我们使用25M的无源晶振。如果我们使用HSE或者HSE经过PLL倍频之后的时钟作为系统时钟SYSCLK,当HSE故障时候,不仅HSE会被关闭,PLL也会被关闭,此时高速的内部时钟时钟信号HSI会作为备用的系统时钟,直到HSE恢复正常,HSI=16M。

2.    ②锁相环PLL

PLL的主要作用是对时钟进行倍频,然后把时钟输出到各个功能部件。PLL有两个,一个是主PLL,另外一个是专用的PLLI2S,他们均由HSE或者HSI提供时钟输入信号。

主PLL有两路的时钟输出,第一个输出时钟PLLCLK用于系统时钟,F429里面最高是180M,第二个输出用于USB OTG FS的时钟(48M)、RNG和SDIO时钟(<=48M)。专用的PLLI2S用于生成精确时钟,给I2S提供时钟。

HSE或者HSI经过PLL时钟输入分频因子M(2~63)分频后,成为VCO的时钟输入,VCO的时钟必须在1~2M之间,我们选择HSE=25M作为PLL的时钟输入,M设置为25,那么VCO输入时钟就等于1M。

VCO输入时钟经过VCO倍频因子N倍频之后,成为VCO时钟输出,VCO时钟必须在192~432M之间。我们配置N为360,则VCO的输出时钟等于360M。如果要把系统时钟超频,就得在VCO倍频系数N这里做手脚。PLLCLK_OUTMAX = VCOCLK_OUTMAX/P_MIN = 432/2=216M,即F429最高可超频到216M。

VCO输出时钟之后有三个分频因子:PLLCLK分频因子p,USB OTG FS/RNG/SDIO时钟分频因子Q,分频因子R(F446才有,F429没有)。p可以取值2、4、6、8,我们配置为2,则得到PLLCLK=180M。Q可以取值4~15,但是USB OTG FS必须使用48M,Q=VCO输出时钟360/48=7.5,出现了小数这明显是错误,权衡之策是是重新配置VCO的倍频因子N=336,VCOCLK=1M*336=336M,PLLCLK=VCOCLK/2=168M,USBCLK=336/7=48M,细心的读者应该发现了,在使用USB的时候,PLLCLK被降低到了168M,不能使用180M,这实乃ST的一个奇葩设计。有关PLL的配置有一个专门的RCC PLL配置寄存器RCC_PLLCFGR,具体描述看手册即可。

PLL的时钟配置经过,稍微整理下可由如下公式表达:

VCOCLK_IN = PLLCLK_IN / M = HSE / 25 = 1M

VCOCLK_OUT = VCOCLK_IN * N = 1M * 360 = 360M

PLLCLK_OUT=VCOCLK_OUT/P=360/2=180M

USBCLK = VCOCLK_OUT/Q=360/7=51.7。暂时这样配置,到真正使用USB的时候会重新配置。

3.    ③系统时钟SYSCLK

系统时钟来源可以是:HSI、PLLCLK、HSE,具体的由时钟配置寄存器RCC_CFGR的SW位配置。我们这里设置系统时钟:SYSCLK = PLLCLK = 180M。如果系统时钟是由HSE经过PLL倍频之后的PLLCLK得到,当HSE出现故障的时候,系统时钟会切换为HSI=16M,直到HSE恢复正常为止。

4.    ④AHB总线时钟HCLK

系统时钟SYSCLK经过AHB预分频器分频之后得到时钟叫APB总线时钟,即HCLK,分频因子可以是:[1,2,4,8,16,64,128,256,512],具体的由时钟配置寄存器RCC_CFGR的HPRE位设置。片上大部分外设的时钟都是经过HCLK分频得到,至于AHB总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好APB的时钟即可。我们这里设置为1分频,即HCLK=SYSCLK=180M。功能框图中的最高168M指的是F407,F429最高应该是180M,是官方中文翻译文档的一个疏忽。

5.    ⑤APB2总线时钟HCLK2

APB2总线时钟PCLK2由HCLK经过高速APB2预分频器得到,分频因子可以是:[1,2,4,8,16],具体由时钟配置寄存器RCC_CFGR的PPRE2位设置。HCLK2属于高速的总线时钟,片上高速的外设就挂载到这条总线上,比如全部的GPIO、USART1、SPI1等。至于APB2总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好APB2的时钟即可。我们这里设置为2分频,即PCLK2 = HCLK /2= 90M。

6.    ⑥APB1总线时钟HCLK1

APB1总线时钟PCLK1由HCLK经过低速APB预分频器得到,分频因子可以是:[1,2,4,8,16],具体由时钟配置寄存器RCC_CFGR的PPRE1位设置。
HCLK1属于低速的总线时钟,最高为45M,片上低速的外设就挂载到这条总线上,比如USART2/3/4/5、SPI2/3,I2C1/2等。至于APB1总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好APB1的时钟即可。我们这里设置为4分频,即PCLK1 = HCLK/4 = 45M。

7.    设置系统时钟库函数

上面的6个步骤对应的设置系统时钟库函数如下,为了方便阅读,已经把跟429不相关的代码删掉,把英文注释翻译成了中文,并把代码标上了序号,总共6个步骤。该函数是直接操作寄存器的,有关寄存器部分请参考数据手册的RCC的寄存器描述部分。

代码 13 设置系统时钟库函数

 1 /*
				
 2  * 使用HSE时,设置系统时钟的步骤
				
 3  * 1、开启HSE ,并等待 HSE 稳定
				
 4  * 2、设置 AHB、APB2、APB1的预分频因子
				
 5  * 3、设置PLL的时钟来源
				
 6  *    设置VCO输入时钟分频因子        m
				
 7  *    设置VCO输出时钟倍频因子        n
				
 8  *    设置PLLCLK时钟分频因子          p
				
 9  *    设置OTG FS,SDIO,RNG时钟分频因子 q
				
10  * 4、开启PLL,并等待PLL稳定
				
11  * 5、把PLLCK切换为系统时钟SYSCLK
				
12  * 6、读取时钟切换状态位,确保PLLCLK被选为系统时钟
				
13  */
				
14 
			
15 #define PLL_M 25
				
16 #define PLL_N 360
				
17 #define PLL_P 2
				
18 #define PLL_Q 7
					

如果要超频的话,修改PLL_N这个宏即可,取值范围为:192~432。

1 void SetSysClock(void)

 2 {
				
 3 
			
 4     __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
				
 5 
			
 6 
								// ①使能HSE
				
 7     RCC->CR |= ((uint32_t)RCC_CR_HSEON);
				
 8 
			
 9 
								// 等待HSE启动稳定
				
10 
							do {
				
11         HSEStatus = RCC->CR & RCC_CR_HSERDY;
				
12         StartUpCounter++;
				
13     } while ((HSEStatus==0)&&(StartUpCounter
				
14                               !=HSE_STARTUP_TIMEOUT));
				
15 
			
16 
							if ((RCC->CR & RCC_CR_HSERDY) != RESET) {
				
17         HSEStatus = (uint32_t)0x01;
				
18     } else {
				
19         HSEStatus = (uint32_t)0x00;
				
20     }
				
21 
			
22 
							// HSE 启动成功
			
23 
							if (HSEStatus == (uint32_t)0x01) {
				
24 
								// 调压器电压输出级别配置为1,以便在器件为最大频率
				
25 
							// 工作时使性能和功耗实现平衡
			
26         RCC->APB1ENR |= RCC_APB1ENR_PWREN;
				
27         PWR->CR |= PWR_CR_VOS;
				
28 
			
29 
								// ②设置AHB/APB2/APB1的分频因子
				
30 
							// HCLK = SYSCLK / 1
				
31         RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
				
32 
							// PCLK2 = HCLK / 2
				
33         RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
				
34 
							// PCLK1 = HCLK / 4
				
35         RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
				
36 
			
37 
								// ③配置主PLL的时钟来源,设置M,N,P,Q
				
38 
							// Configure the main PLL
				
39         RCC->PLLCFGR = PLL_M|(PLL_N<<6)|
				
40                        (((PLL_P >> 1) -1) << 16) |
				
41                        (RCC_PLLCFGR_PLLSRC_HSE) |
				
42                        (PLL_Q << 24);
				
43 
			
44 
								// ④使能主PLL
				
45         RCC->CR |= RCC_CR_PLLON;
				
46 
			
47 
								// 等待PLL稳定
				
48 
							while ((RCC->CR & RCC_CR_PLLRDY) == 0) {
				
49         }
				
50 
							/*----------------------------------------------------*/
				
51 
								// 开启 OVER-RIDE模式,以能达到更改频率
				
52         PWR->CR |= PWR_CR_ODEN;
				
53 
							while ((PWR->CSR & PWR_CSR_ODRDY) == 0) {
				
54         }
				
55         PWR->CR |= PWR_CR_ODSWEN;
				
56 
							while ((PWR->CSR & PWR_CSR_ODSWRDY) == 0) {
				
57         }
				
58 
								// 配置FLASH预取指,指令缓存,数据缓存和等待状态
				
59         FLASH->ACR = FLASH_ACR_PRFTEN
				
60                      |FLASH_ACR_ICEN
				
61                      |FLASH_ACR_DCEN
				
62                      |FLASH_ACR_LATENCY_5WS;
				
63 
							/*---------------------------------------------------*/
				
64 
			
65 
								// ⑤选择主PLLCLK作为系统时钟源
				
66         RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
				
67         RCC->CFGR |= RCC_CFGR_SW_PLL;
				
68 
			
69 
								// ⑥读取时钟切换状态位,确保PLLCLK选为系统时钟
				
70 
							while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS )
				
71                != RCC_CFGR_SWS_PLL);
				
72         {
				
73         }
				
74     } else {
				
75 
							// HSE 启动出错处理
			
76     }
				
77 }
				
			
1.2.2 其他时钟

通过对系统时钟设置的讲解,整个时钟树我们已经把握的有六七成,剩下的时钟部分我们讲解几个重要的。

1.    A、RTC时钟

RTCCLK 时钟源可以是 HSE 1 MHz( HSE 由一个可编程的预分频器分频)、 LSE 或者 LSI时钟。选择方式是编程 RCC 备份域控制寄存器 (RCC_BDCR) 中的 RTCSEL[1:0] 位和 RCC时钟配置寄存器 (RCC_CFGR) 中的 RTCPRE[4:0] 位。所做的选择只能通过复位备份域的方式修改。我们通常的做法是由LSE给RTC提供时钟,大小为32.768KHZ。LSE由外接的晶体谐振器产生,所配的谐振电容精度要求高,不然很容易不起震。

2.    B、独立看门狗时钟

独立看门狗时钟由内部的低速时钟LSI提供,大小为32KHZ。

3.    C、I2S时钟

I2S时钟可由外部的时钟引脚I2S_CKIN输入,也可由专用的PLLI2SCLK提供,具体的由RCC 时钟配置寄存器 (RCC_CFGR)的I2SSCR位配置。我们在使用I2S外设驱动W8978的时候,使用的时钟是PLLI2SCLK,这样就可以省掉一个有源晶振。

4.    D、PHY以太网时钟

F429要想实现以太网功能,除了有本身内置的MAC之外,还需要外接一个PHY芯片,常见的PHY芯片有DP83848和LAN8720,其中DP83848支持MII和RMII接口,LAN8720只支持RMII接口。秉火F429开发板用的是RMII接口,选择的PHY芯片是LAB8720。使用RMII接口的好处是使用的IO减少了一半,速度还是跟MII接口一样。当使用RMII接口时,PHY芯片只需输出一路时钟给MCU即可,如果是MII接口,PHY芯片则需要提供两路时钟给MCU。

5.    E、USB PHY 时钟

F429的USB没有集成PHY,要想实现USB高速传输的话,必须外置USB PHY芯片,常用的芯片是USB3300。当外接USB PHY芯片时,PHY芯片需要给MCU提供一个时钟。

外扩USB3300会占用非常多的IO,跟SDRAM和RGB888的IO会复用的很厉害,鉴于USB高速传输用的比较少,秉火429就没有外扩这个芯片。

6.    F、MCO时钟输出

MCO是microcontroller clock output的缩写,是微控制器时钟输出引脚,主要作用是可以对外提供时钟,相当于一个有源晶振。F429中有两个MCO,由PA8/PC9复用所得。MCO1所需的时钟源通过 RCC 时钟配置寄存器 (RCC_CFGR) 中的 MCO1PRE[2:0] 和 MCO1[1:0]位选择。MCO2所需的时钟源通过 RCC 时钟配置寄存器 (RCC_CFGR) 中的 MCO2PRE[2:0] 和 MCO2位选择。有关MCO的IO、时钟选择和输出速率的具体信息如下表所示:

时钟输出

IO

时钟来源

最大输出速率

MCO1

PA8

HSI、LSE、HSE、PLLCLK

100M

MCO2

PC9

HSE、PLLCLK、SYSCLK、PLLI2SCLK

100M

1.3 配置系统时钟实验

1.3.1 使用HSE

一般情况下,我们都是使用HSE,然后HSE经过PLL倍频之后作为系统时钟。F429系统时钟最高为180M,这个是官方推荐的最高的稳定时钟,如果你想铤而走险,也可以超频,超频最高能到216M。

如果我们使用库函数编程,当程序来到main函数之前,启动文件:startup_stm32f429_439xx.s已经调用SystemInit()函数把系统时钟初始化成180MHZ,SystemInit()在库文件:system_stm32f4xx.c中定义。如果我们想把系统时钟设置低一点或者超频的话,可以修改底层的库文件,但是为了维持库的完整性,我们可以根据时钟树的流程自行写一个。

1.3.2 使用HSI

当HSE直接或者间接(HSE经过PLL倍频)的作为系统时钟的时候,如果HSE发生故障,不仅HSE会被关闭,连PLL也会被关闭,这个时候系统会自动切换HSI作为系统时钟,此时SYSCLK=HSI=16M,如果没有开启CSS和CSS中断的话,那么整个系统就只能在低速率运行,这是系统跟瘫痪没什么两样。

如果开启了CSS功能的话,那么可以当HSE故障时,在CSS中断里面采取补救措施,使用HSI,重新设置系统频率为180M,让系统恢复正常使用。但这只是权宜之计,并非万全之策,最好的方法还是要采取相应的补救措施并报警,然后修复HSE。临时使用HSI只是为了把损失降低到最小,毕竟HSI较于HSE精度还是要低点。

F103系列中,使用HSI最大只能把系统设置为64M,并不能跟使用HSE一样把系统时钟设置为72M,究其原因是HSI在进入PLL倍频的时候必须2分频,导致PLL倍频因子调到最大也只能到64M,而HSE进入PLL倍频的时候则不用2分频。

在F429中,无论是使用HSI还是HSE都可以把系统时钟设置为180M,因为HSE或者HSI在进入PLL倍频的时候都会被分频为1M之后再倍频。

还有一种情况是,有些用户不想用HSE,想用HSI,但是又不知道怎么用HSI来设置系统时钟,因为调用库函数都是使用HSE,下面我们给出个使用HSI配置系统时钟例子,起个抛砖引玉的作用。

1.3.3 硬件设计

1、RCC

2、LED一个

RCC是单片机内部资源,不需要外部电路。通过LED闪烁的频率来直观的判断不同系统时钟频率对软件延时的效果。

1.3.4 软件设计

我们编写两个RCC驱动文件,bsp_clkconfig.h和bsp_clkconfig.c,用来存放RCC系统时钟配置函数。

1.    编程要点

1、开启HSE/HSI ,并等待 HSE/HSI 稳定

2、设置 AHB、APB2、APB1的预分频因子

3、设置PLL的时钟来源,设置VCO输入时钟 分频因子PLL_M,设置VCO输出时钟

倍频因子PLL_N,设置PLLCLK时钟分频因子PLL_P,设置OTG FS,SDIO,RNG

时钟分频因子 PLL_Q

4、开启PLL,并等待PLL稳定

5、把PLLCK切换为系统时钟SYSCLK

6、读取时钟切换状态位,确保PLLCLK被选为系统时钟

2.    代码分析

这里只讲解核心的部分代码,有些变量的设置,头文件的包含等并没有涉及到,完整的代码请参考本章配套的工程。

使用HSE配置系统时钟

代码 14 HSE作为系统时钟来源

1 /*

 2  * m: VCO输入时钟分频因子,取值2~63
				
 3  * n: VCO输出时钟倍频因子,取值192~432
				
 4  * p: SYSCLK时钟分频因子,取值2,4,6,8
				
 5  * q: OTG FS,SDIO,RNG时钟分频因子,取值4~15
				
 6  * 函数调用举例,使用HSE设置时钟
				
 7  * SYSCLK=HCLK=180M,PCLK2=HCLK/2=90M,PCLK1=HCLK/4=45M
				
 8  * HSE_SetSysClock(25, 360, 2, 7);
				
 9  * HSE作为时钟来源,经过PLL倍频作为系统时钟,这是通常的做法
				
10 
			
11  * 系统时钟超频到216M爽一下
				
12  * HSE_SetSysClock(25, 432, 2, 9);
				
13  */
				
14 void HSE_SetSysClock(uint32_t m, uint32_t n, uint32_t p, uint32_t q)
				
15 {
				
16     __IO uint32_t HSEStartUpStatus = 0;
				
17 
			
18 
								// 使能HSE,开启外部晶振,秉火F429使用 HSE=25M
				
19     RCC_HSEConfig(RCC_HSE_ON);
				
20 
			
21 
								// 等待HSE启动稳定
				
22     HSEStartUpStatus = RCC_WaitForHSEStartUp();
				
23 
			
24 
							if (HSEStartUpStatus == SUCCESS) {
				
25 
								// 调压器电压输出级别配置为1,以便在器件为最大频率
				
26 
							// 工作时使性能和功耗实现平衡
			
27         RCC->APB1ENR |= RCC_APB1ENR_PWREN;
				
28         PWR->CR |= PWR_CR_VOS;
				
29 
			
30 
							// HCLK = SYSCLK / 1
				
31         RCC_HCLKConfig(RCC_SYSCLK_Div1);
				
32 
			
33 
							// PCLK2 = HCLK / 2
				
34         RCC_PCLK2Config(RCC_HCLK_Div2);
				
35 
			
36 
							// PCLK1 = HCLK / 4
				
37         RCC_PCLK1Config(RCC_HCLK_Div4);
				
38 
			
39 
							// 如果要超频就得在这里下手啦
			
40 
								// 设置PLL来源时钟,设置VCO分频因子m,设置VCO倍频因子n,
				
41 
								// 设置系统时钟分频因子p,设置OTG FS,SDIO,RNG分频因子q
				
42         RCC_PLLConfig(RCC_PLLSource_HSE, m, n, p, q);
				
43 
			
44 
								// 使能PLL
				
45         RCC_PLLCmd(ENABLE);
				
46 
			
47 
								// 等待 PLL稳定
				
48 
							while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {
				
49         }
				
50 
			
51 
							/*-----------------------------------------------------*/
				
52 
								//开启 OVER-RIDE模式,以能达到更高频率
				
53         PWR->CR |= PWR_CR_ODEN;
				
54 
							while ((PWR->CSR & PWR_CSR_ODRDY) == 0) {
				
55         }
				
56         PWR->CR |= PWR_CR_ODSWEN;
				
57 
							while ((PWR->CSR & PWR_CSR_ODSWRDY) == 0) {
				
58         }
				
59 
								// 配置FLASH预取指,指令缓存,数据缓存和等待状态
				
60         FLASH->ACR = FLASH_ACR_PRFTEN
				
61                      | FLASH_ACR_ICEN
				
62                      | FLASH_ACR_DCEN
				
63                      | FLASH_ACR_LATENCY_5WS;
				
64 
							/*-----------------------------------------------------*/
				
65 
			
66 
								// 当PLL稳定之后,把PLL时钟切换为系统时钟SYSCLK
				
67         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
				
68 
			
69 
								// 读取时钟切换状态位,确保PLLCLK被选为系统时钟
				
70 
							while (RCC_GetSYSCLKSource() != 0x08) {
				
71         }
				
72     } else {
				
73 
							// HSE启动出错处理
			
74 
			
75 
							while (1) {
				
76         }
				
77     }
				
78 }
				
			

这个函数采用库函数编写, 代码理解参考注释即可。函数有4个形参m、n、p、q,具体说明如下:

形参

形参说明

取值范围

m

VCO输入时钟 分频因子

2~63

n

VCO输出时钟 倍频因子

192~432

p

PLLCLK时钟分频因子

2/4/6/8

q

OTG FS,SDIO,RNG时钟分频因子

4~15

HSE我们使用25M,参数m我们一般也设置为25,所以我们需要修改系统时钟的时候只需要修改参数n和p即可,SYSCLK=PLLCLK=HSE/m*n/p。

函数调用举例:HSE_SetSysClock(25, 360, 2, 7) 把系统时钟设置为180M,这个跟库里面的系统时钟配置是一样的。HSE_SetSysClock(25, 432, 2, 9)把系统时钟设置为216M,这个是超频,要慎用。

使用HSI配置系统时钟

1 /*

 2  * m: VCO输入时钟分频因子,取值2~63
				
 3  * n: VCO输出时钟倍频因子,取值192~432
				
 4  * p: PLLCLK时钟分频因子,取值2,4,6,8
				
 5  * q: OTG FS,SDIO,RNG时钟分频因子,取值4~15
			
 6  * 函数调用举例,使用HSI设置时钟
				
 7  * SYSCLK=HCLK=180M,PCLK2=HCLK/2=90M,PCLK1=HCLK/4=45M
				
 8  * HSI_SetSysClock(16, 360, 2, 7);
				
 9  * HSE作为时钟来源,经过PLL倍频作为系统时钟,这是通常的做法
				
10 
			
11  * 系统时钟超频到216M爽一下
				
12  * HSI_SetSysClock(16, 432, 2, 9);
				
13  */
				
14 
			
15 void HSI_SetSysClock(uint32_t m, uint32_t n, uint32_t p, uint32_t q)
				
16 {
				
17     __IO uint32_t HSIStartUpStatus = 0;
				
18 
			
19 
								// 把RCC外设初始化成复位状态
				
20     RCC_DeInit();
				
21 
			
22 
								//使能HSI, HSI=16M
				
23     RCC_HSICmd(ENABLE);
				
24 
			
25 
								// 等待 HSI 就绪
				
26     HSIStartUpStatus = RCC->CR & RCC_CR_HSIRDY;
				
27 
			
28 
								// 只有 HSI就绪之后则继续往下执行
				
29 
							if (HSIStartUpStatus == RCC_CR_HSIRDY) {
				
30 
								// 调压器电压输出级别配置为1,以便在器件为最大频率
				
31 
							// 工作时使性能和功耗实现平衡
			
32         RCC->APB1ENR |= RCC_APB1ENR_PWREN;
				
33         PWR->CR |= PWR_CR_VOS;
				
34 
			
35 
							// HCLK = SYSCLK / 1
				
36         RCC_HCLKConfig(RCC_SYSCLK_Div1);
				
37 
			
38 
							// PCLK2 = HCLK / 2
				
39         RCC_PCLK2Config(RCC_HCLK_Div2);
				
40 
			
41 
							// PCLK1 = HCLK / 4
				
42         RCC_PCLK1Config(RCC_HCLK_Div4);
				
43 
			
44 
							// 如果要超频就得在这里下手啦
			
45 
								// 设置PLL来源时钟,设置VCO分频因子m,设置VCO倍频因子n,
				
46 
								// 设置系统时钟分频因子p,设置OTG FS,SDIO,RNG分频因子q
				
47         RCC_PLLConfig(RCC_PLLSource_HSI, m, n, p, q);
				
48 
			
49 
								// 使能PLL
				
50         RCC_PLLCmd(ENABLE);
				
51 
			
52 
								// 等待 PLL稳定
				
53 
							while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {
				
54         }
				
55 
			
56 
							/*-----------------------------------------------------*/
				
57 
								//开启 OVER-RIDE模式,以能达到更高频率
				
58         PWR->CR |= PWR_CR_ODEN;
				
59 
							while ((PWR->CSR & PWR_CSR_ODRDY) == 0) {
				
60         }
				
61         PWR->CR |= PWR_CR_ODSWEN;
				
62 
							while ((PWR->CSR & PWR_CSR_ODSWRDY) == 0) {
				
63         }
				
64 
								// 配置FLASH预取指,指令缓存,数据缓存和等待状态
				
65         FLASH->ACR = FLASH_ACR_PRFTEN
				
66                      | FLASH_ACR_ICEN
				
67                      |FLASH_ACR_DCEN
				
68                      |FLASH_ACR_LATENCY_5WS;
				
69 
							/*-----------------------------------------------------*/
				
70 
			
71 
								// 当PLL稳定之后,把PLL时钟切换为系统时钟SYSCLK
				
72         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
				
73 
			
74 
								// 读取时钟切换状态位,确保PLLCLK被选为系统时钟
				
75 
							while (RCC_GetSYSCLKSource() != 0x08) {
				
76         }
				
77     } else {
				
78 
							// HSI启动出错处理
			
79 
							while (1) {
				
80         }
				
81     }
				
82 }
				
			

这个函数采用库函数编写, 代码理解参考注释即可。函数有4个形参m、n、p、q,具体说明如下:

形参

形参说明

取值范围

m

VCO输入时钟分频因子

2~63

n

VCO输出时钟倍频因子

192~432

p

PLLCLK时钟分频因子

2/4/6/8

q

OTG FS,SDIO,RNG时钟分频因子

4~15

HSI为16M,参数m我们一般也设置为16,所以我们需要修改系统时钟的时候只需要修改参数n和p即可,SYSCLK=PLLCLK=HSI/m*n/p。

函数调用举例:HSI_SetSysClock(16, 360, 2, 7) 把系统时钟设置为180M,这个跟库里面的系统时钟配置是一样的。HSI_SetSysClock(16, 432, 2, 9)把系统时钟设置为216M,这个是超频,要慎用。

软件延时
 1 void Delay(__IO uint32_t nCount)
				
 2 {
				
 3 
							for (; nCount != 0; nCount--);
				
 4 }
				
			

软件延时函数,使用不同的系统时钟,延时时间不一样,可以通过LED闪烁的频率来判断。

MCO输出

在F429中,PA8/PC9可以复用为MCO1/2引脚,对外提供时钟输出,我们也可以用示波器监控该引脚的输出来判断我们的系统时钟是否设置正确。

代码 15 MCO GPIO初始化

 1 // MCO1 PA8 GPIO 初始化
			
 2 void MCO1_GPIO_Config(void)
				
 3 {
				
 4     GPIO_InitTypeDef GPIO_InitStructure;
				
 5     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
				
 6 
			
 7 
							// MCO1 GPIO 配置
			
 8     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
				
 9     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
				
10     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
				
11     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
				
12     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
				
13     GPIO_Init(GPIOA, &GPIO_InitStructure);
				
14 }
				
15 
			
16 // MCO2 PC9 GPIO 初始化
			
17 void MCO2_GPIO_Config(void)
				
18 {
				
19     GPIO_InitTypeDef GPIO_InitStructure;
				
20     RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
				
21 
			
22 
							// MCO2 GPIO 配置
			
23     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
				
24     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
				
25     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
				
26     GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
				
27     GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
				
28     GPIO_Init(GPIOC, &GPIO_InitStructure);
				
29 }
				

秉火F429中PA8并没有引出,只引出了PC9,如果要用示波器监控MCO,只能用 PC9。

代码 16 MCO输出时钟选择

 1 // MCO1 输出PLLCLK
				
 2 RCC_MCO1Config(RCC_MCO1Source_PLLCLK, RCC_MCO1Div_1);
				
 3 
			
 4 // MCO1 输出SYSCLK
				
 5 RCC_MCO2Config(RCC_MCO2Source_SYSCLK, RCC_MCO1Div_1);
				
			

我们初始化MCO引脚之后,可以直接调用库函数RCC_MCOxConfig()来选择MCO时钟来源,同时还可以分频,这两个参数的取值参考库函数说明即可。

主函数

在主函数中,可以调用HSE_SetSysClock()或者HSI_SetSysClock()这两个函数把系统时钟设置成各种常用的时钟,然后通过MCO引脚监控,或者通过LED闪烁的快慢体验不同的系统时钟对同一个软件延时函数的影响。

1 int main(void)

 2 {
				
 3 
								// 程序来到main函数之前,启动文件:statup_stm32f10x_hd.s已经调用
				
 4 
								// SystemInit()函数把系统时钟初始化成72MHZ
				
 5 
								// SystemInit()在system_stm32f10x.c中定义
				
 6 
							// 如果用户想修改系统时钟,可自行编写程序修改
			
 7 
								// 重新设置系统时钟,这时候可以选择使用HSE还是HSI
				
 8 
			
 9 
								// 使用HSE,配置系统时钟为180M
				
10     HSE_SetSysClock(25, 360, 2, 7);
				
11 
			
12 
								//系统时钟超频到216M爽一下,最高是216M,别往死里整
				
13 
							//HSE_SetSysClock(25, 432, 2, 9);
				
14 
			
15 
								// 使用HSI,配置系统时钟为180M
				
16 
							//HSI_SetSysClock(16, 360, 2, 7);
				
17 
			
18 
							// LED 端口初始化
			
19     LED_GPIO_Config();
				
20 
			
21 
							// MCO GPIO  初始化
			
22     MCO1_GPIO_Config();
				
23     MCO2_GPIO_Config();
				
24 
			
25 
								// MCO1 输出PLLCLK
				
26     RCC_MCO1Config(RCC_MCO1Source_PLLCLK, RCC_MCO1Div_1);
				
27 
			
28 
								// MCO2 输出SYSCLK
				
29     RCC_MCO2Config(RCC_MCO2Source_SYSCLK, RCC_MCO1Div_1);
				
30 
			
31 
							while (1) {
				
32         LED1( ON );      // 亮
			
33         Delay(0x0FFFFF);
				
34         LED1( OFF );      // 灭
			
35         Delay(0x0FFFFF);
				
36     }
				
37 }
				
			
1.3.5 下载验证

把编译好的程序下载到开发板,可以看到设置不同的系统时钟时,LED闪烁的快慢不一样。更精确的数据我们可以用示波器监控MCO引脚看到。

1.4 每课一问

1、简述系统时钟的配置过程

2、F429系统时钟最    高稳定运行是多少M

3.STM32F429时钟系统配置方法 目录时钟系统时钟源三级目录 在前几篇文章中我想把一些基础的部分简单总结一下:首先是前两篇文章,学习一个mcu就要先对它的外设有初步的理解,还有要使用的HAL库,它相当于我们的代码与硬件之间连接的桥梁;这篇博客会总结一下429时钟树的一些知识,还有时钟配置函数;再之后可能还会总结基于SysTick的延时函数、程序执行流程、中断、DMA等。 时钟系统 时钟源 F429有5个时钟源,HSI,HSE,LS... 阅读详情

相关推荐

flash_acr_latency

关于flash_acr_latency的理解 这个问题网上查了很多资料,但是我感觉都写的不是很清楚。下面我就结合我个人搜集到的资料,再结合个人的理解来认识一下这个参数,但是可能我所的完全是错的,如果说有更多的看法,欢迎指出,我的目的就是为了引出最正确的理解,对这个参数。 首先来看看关于内部flash所涉及的时钟树部分: 在官方手册中有关latency的理解如下: 在配置系统时钟之前,通常需要先调整latency,然后再改变系统时钟,不然可能会出现flash读写问题。 个人想到一个问题是: 如果在改变系

xiaoqa11的博客 2888

STM32学习笔记——十一、RCC使用HSE/HSI配置时钟

是microcontroller clock output 的缩写,是微控制器时钟输出引脚。软件延时函数,使用不同的系统时钟,延时时间不一样,可以通过LED 闪烁的频率来判断。(APB总线时钟):系统时钟SYSCLK经过AHB预分频器分频后得到的时钟。,不仅HSE 不能使用,连PLL 也会被关闭,这个时候系统会。控制AHB、APB2、APB1三条总线时钟的开启。由HCLK经过告诉APB2经过预分频器得到。由HCLK(AHB总线时钟) 8 分频得到。如果PLL 的时钟来源是HSE,那么当。

weixin_45029825的博客 2222

STM32第15章 RCC-使用HSE/HSI配置时钟

总结及要求时间:2024.10.21-10.23参考资料:《零死角玩转STM32》“RCC-使用HSE/HIS配置时钟”章节TIPS:从前面的历程中我们知道,程序在启动的时候会执行汇编文件,汇编文件里会调用System_Init(固件库编程的函数),它里面会把时钟初始化成72M,因此前面我们在用固件库写程序的时候,有关时钟这一部分就忽略了。

2201_75297369的博客 1957

STM32F407ZGT6嵌入式开发实战:引脚规划、性能边界与外设组合

在嵌入式系统开发中,MCU选型与资源分配是核心环节。STM32F407ZGT6基于Cortex-M4内核,主频168MHz,集成FPU、1MB Flash和192KB SRAM,外设资源丰富。其144引脚LQFP封装提供114个GPIO,但需注意复用冲突与DMA访问限制。合理规划引脚、利用CCM RAM和FPU可显著提升实时性。该芯片适用于工业控制、数据采集、HMI等场景,是兼顾性能与成本的通用型选择。

weixin_34396103的博客 360

STM32F429 RTC时间不动、不准问题的解决

硬件:阿波罗STM32F429IGTx开发板 软件:keil5,c语言 一、问题描述 在使用正点原子RTC时间时,遇到以下两个问题: 1.将RTC时间精确到亚秒,打印发现:只有亚秒在动,时,分,秒皆不动。 2.打印出来的亚秒是倒计时,循环的从255到0。 二、问题解决 而我想实现时间正常走动且毫秒能从0-999正计时。经查阅相关资料找到解决方法: 1.时间不走动的原因在于: 为了保障读取时间的一致性,读取日历操作要求先读时分秒然后还得读日期,这样做才为一个完整的操作。所以在读取TIME【时分秒】后,硬件会将

qq_32216815的博客 9625

STM32F429标准例程-HAL库版本2.rar

STM32F429标准例程-HAL库版本1.rar

RCC—使用 HSE/HSI 配置时钟(stm32f429)

Q 可以取值 4~15,但是 USB OTG FS 必须使用 48M,Q=VCO 输出时钟 360/48=7.5,出现了小 数这明显是错误,权衡之策是是重新配置 VCO 的倍频因子 N=336,VCOCLK=1M*336=336M, PLLCLK=VCOCLK/2=168M,USBCLK=336/7=48M。片上大部分外设的时钟都是经过 HCLK 分频得到,至于 AHB 总线上的外设的时钟设置为多 少,得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好 APB 的时钟即可。

qq_62946734的博客 1758

银河麒麟v10离线安装docker二进制包

因为工作需要在银河麒麟v10系统上离线部署k8s集群,k8s部署的前提是具有docker环境,因此离线安装docker成为必然。 1.下载docker包:Index of linux/static/stable/x86_64/ 选择自己合适的版本,我下载的是20.10.7 选择自己放置docker包的路径进行解压: cd /home/huawei/zq tar -zxvf docker-20.10.7.tgz 2. 给docker包解压出来的docker文件夹下的二进制文件赋..

q_hsolucky的博客 7684

STM32学习笔记1----STM32F429系统时钟

FreeRTOS任务基本知识 1.任务堆栈大小 pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */ 可以看出 StackType_t 类型的变量为 4 个字节,那么任务的实际堆栈大小就应该是我们所定

qq_44881094的博客 6367

单片机控制双向可控硅的5种实用触发电路设计(附完整电路图)

本文深入解析了单片机控制双向可控硅的5种实用触发电路设计,涵盖从基础隔离到复杂负载驱动的实战方案。重点探讨了光电耦合器选型、过零检测同步、RC吸收电路精密计算以及应对感性负载和高噪声环境的加固策略,并提供了完整的电路图与调试避坑指南,旨在帮助开发者实现安全可靠的交流负载控制。

joy55的博客 2210

Delphi 13 Beta初体验:手把手教你安装RAD Studio Ganymede,并实测新条件运算符

本文详细介绍了Delphi 13 Beta(代号Ganymede)的安装步骤和新特性,重点解析了新增的条件运算符语法。通过实测对比,展示了64位IDE的性能提升和新语法在代码简洁性上的优势,为开发者提供了从安装到实战的完整指南。

weixin_30399821的博客 205

(六)STM32时钟系统RCC——使用HSE/HSI配置时钟

STM32 时钟系统、端口复用和重映射是什么、修改STM32系统时钟

MEYOU_Cc 不吃香菜! 5040

Win10系统安装Ubuntu虚拟机,这回真的是零基础!(结尾附NS3的配置)

Win10系统安装Ubuntu虚拟机(结尾附NS3的配置) 序幕 本人现在还在念大二,有一门很有趣而且老师讲得也不错的课程《计算机网络原理》。这周老师布置了一个实验《NS3网络模拟》,为了详细记录本次实验过程,顺便也便于自己复习,就写了这篇博客,希望能够对你有帮助! NS3是什么呢?实际上就是一门算法,和计算机网络有关的。不过在我们日常使用的Windows系统上去做这个实验是行不通的,这个实验一定要在Linux系统上进行模拟才能玩的下去,作为一名 Windows选手对此表示不爽但是没办法,为了实验也只

灼热之翼的博客 7382

STM32时钟详解(基于STM32F429)

STM32的就像是这个微控制器(MCU)的“心跳”或者“节拍器”。。想象一下,如果你有一个机器人在做动作,时钟就是控制它每一步动作的速度和时间点的。如果时钟快了,机器人的动作就会加速;如果时钟慢了,机器人的动作就会变慢。同样地,在STM32中,如果时钟频率设置得高,MCU就会运行得更快,能够更快地处理数据;如果时钟频率设置得低,MCU就会运行得慢一些。

千千道的博客 3704

2024年中科大分子生物研究生考试建议

分子生物学复习资料及往年考题。

qq_43337249的博客 2951

交换机救命命令手册:华为 & 思科平台最全运维指令速查表

很多时候,真正拉你一把的不是“高深理论”,而是你手里有没有一份靠得住的命令速查表。这篇文章,希望能成为你“进可调试,退可排障”的一份救命卡片。

HuaweiLab_Peach的博客 1515

09 STM32F429 RCC时钟

RCC stm32

qq_27716761的博客 713

【WRF-Chem 工具】CAMStoWRF详解:CAMS数据下载及处理

【WRF-Chem 工具】CAMStoWRF详解:CAMS数据下载及处理

WW、forever的博客 195

STM32基础--RCC—使用 HSE/HSI 配置时钟

RCC :reset clock control 复位和时钟控制器。本章我们主要讲解时钟部分,特别是要着重理解时钟树,理解了时钟树,STM32 的一切时钟的来龙去脉都会了如指掌。

weixin_48713132的博客 2471

Altium Designer(AD24)导入DDB库文件(Protel 99SE)方法

Altium Designer和Protel均为Altium公司开发的软件。本文介绍Altium Designer 24软件导入DDB库文件(Protel 99SE)方法。

fydar的博客 1980

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

STM32F103xx 内部时钟HSI配置

STM32F103xx 内部时钟HSI配置

zzh113的博客 1407

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

STM32F103系列(十四):RCC之使用HSE/HSI配置时钟

1、RCC主要作用–时钟部分 设置系统时钟SYSCLK、设置AHB分频因子(决定HCLK等于多少)、设置APB2分频因子(决定PCLK2等于多少)、设置APB1分频因子(决定PCLK1等于多少)、设置各个外设的分频因子; 控制AHB、APB2和APB1这3条总线时钟的开启、控制每个外设的时钟的开启。对于SYSCLK、HCLK、PCLK2、PCLK1这4个时钟的配置一般是:PCLK2=HCLK=SY...

weifeng blog 7592

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

STM32 RCC—使用 HSE 配置时钟

使用 HSE 配置时钟一,STM32时钟树系统二,系统时钟配置流程三,其他时钟四,实验(MCO 输出)实验结果 一,STM32时钟树系统 STM32F103单片机微处理器的神经中枢是时钟系统,时钟系统为整个硬件系统的各个模块提供时钟信号。但因为每个硬件模块对时钟信号要求不同,因此需要在系统中设置多个振荡器,分别提供时钟信号,或者从一个主振荡器开始经过多次倍频,分频,锁相环等电路,生成各个模块的独立时钟信号。 STM32单片机的时钟树如下图所示: STM32中时钟来源; **1.**HSI:高速内部时钟信号8

qq_44223560的博客 2763

再造STM32---第十三部分:RCC—使用 HSE/HSI 配置时钟

配合《STM32F4xx 中文参考手册》 RCC 章节一起阅读,效果会更佳,特别是涉及到寄存器说明的部分。 RCC : reset clock control 复位和时钟控制器。本章我们主要讲解时钟部分,特别是要着重理解时钟树,理解了时钟树, F429 的一切时钟的来龙去脉都会了如指掌。 13.1 RCC 主要作用—时钟部分: 设置系统时钟 SYSC...

sumjess 4573

STM32时钟系统以及配置及源码分析

  目录 1.STM32F429时钟概述 2.系统时钟的初始化寄存器源码分析 3.系统时钟的初始化HAL库函数源码分析     1.STM32F429时钟概述 时钟系统是 CPU 的脉搏,就像人的心跳一样。所以时钟系统的重要性就不言而喻了。 STM32有多个时钟来源的选择,采用一个系统时钟不是很简单吗?为什么 STM32 要有多个时钟源呢? 因为首先 STM32 本身非常复杂,外设...

广源的博客 3万+
上一篇: 第14章 启动文件详解—零死角玩转STM32-F429系列
下一篇: 第16章 STM32中断应用概览—零死角玩转STM32-F429系列
0木木0
博客等级 码龄17年 458粉丝 58原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值