购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

任务1.3
STM32F4系统时钟的配置

1.3.1 任务分析

本任务要求完成STM32F4开发板(板上连接的外部晶振频率为8 MHz)系统时钟的配置,具体配置要求如下:

● 系统时钟(SYSCLK)配置为168 MHz;

● 高性能总线时钟(HCLK)配置为168 MHz;

● 高速外设总线时钟(PCLK2)配置为84 MHz;

● 低速外设总线时钟(PCLK1)配置为42 MHz。

时钟(Clock)是微控制器的脉搏。在数字系统中,所有部件要正常工作都离不开时钟。时钟之于数字系统,如心跳之于人,其重要性不言而喻。

一般情况下,我们在使用标准外设库进行STM32开发时无须对系统时钟进行配置,原因是STM32开发板上提供的晶振频率基本上都与ST公司官方标准的晶振频率相同。但对于一些特殊的应用场景(如超低功耗),我们可能需要对MCU进行降频,即对系统时钟进行配置。

STM32F4标准外设库为用户提供了复位与时钟控制(Reset and Clock Control,RCC)库,用于系统时钟的配置。

本任务涉及的知识点有:

● STM32F4系列微控制器的时钟源;

● STM32F4系列微控制器中的一些重要的时钟信号概念;

● STM32F4标准外设库中与RCC库配置相关的内容。

1.3.2 知识链接

1.STM32F4的时钟源

与51系列单片机相比,STM32F4的时钟系统更加复杂。由于STM32F4的系统架构复杂,外设种类繁多,且每种外设所需的时钟频率不尽相同,因此系统有多个时钟源。STM32F4的时钟树图标明了各时钟源的信息,如图1-3-1所示。

图1-3-1中的标号 处分别标明了STM32F4的5个时钟源,它们的介绍如下。

(1)高速内部时钟

高速内部时钟(High Speed Internal,HSI)由STM32F4系列微控制器芯片内部的RC振荡器产生,其频率为16MHz,可作为SYSCLK或锁相环(PLL)的时钟源。它位于图1-3-1中标号 所示的位置。

(2)高速外部时钟

高速外部时钟(High Speed External,HSE)由石英振荡器或陶瓷振荡器产生,也可直接使用外部时钟源,其频率范围是4~26MHz,可作为SYSCLK或锁相环(PLL)的时钟源。它位于图1-3-1中标号 所示的位置。

图1-3-1 STM32F4的时钟树图

(3)低速内部时钟

低速内部时钟(Low Speed Internal,LSI)由STM32F4系列微控制器芯片内部的RC振荡器产生,其频率为32kHz,可供独立“看门狗”或实时时钟(RTC)使用。它位于图1-3-1中标号 所示的位置。

(4)低速外部时钟

低速外部时钟(Low Speed External,LSE)一般由频率为32.768kHz的石英振荡器产生,可供独立“看门狗”或实时时钟(RTC)使用。它位于图1-3-1中标号 所示的位置。

(5)锁相环倍频输出

锁相环(Phase Locked Loop,PLL)的主要作用是对其他输入时钟进行倍频,然后把时钟信号输出到各个功能部件。STM32F4系列微控制器有两个PLL,一个是主PLL,另一个是PLLI2S,它们位于图1-3-1中标号 所示的位置。

主PLL的输入可以是HSI或HSE,输出共有两路:一路输出PLLP提供的时钟信号PLLCLK,可作为系统时钟SYSCLK的时钟源,最高频率168MHz;另一路输出PLLQ,可用于生成48MHz的时钟信号PLL48CK,可供给USB OTG FS、随机数发生器和SDIO接口等使用。

PLLI2S用于生成精准时钟PLLI2SCLK,其可供给I2S总线接口以实现高品质音频输出。

2.几个重要的时钟信号概念

图1-3-1中的标号A、B、C、D、E、F处分别标明了STM32F4中几个重要的时钟信号,它们的介绍如下。

(1)SYSCLK

系统时钟(SYSCLK)是STM32大部分器件的时钟源,它经AHB预分频器分频后分配到各个部件,如图1-3-1中标号“A”位置所示。SYSCLK的时钟源可以是HSI、HSE或PLLCLK,具体由时钟配置寄存器(RCC_CFGR)的SW位进行配置。

(2)HCLK

先进的高性能总线(Advanced High-Performance Bus,AHB)时钟(High-Performance Clock,HCLK)由AHB预分频器分频后得到,分频系数可以是1、2、4、8、16、64、128、256、512等,由RCC_CFGR的HPRE位进行配置,一般选择1分频。HCLK供Cortex-M4内核使用,它决定了STM32系列微控制器的运算速度和数据存取速度,一般也称为主频,如图1-3-1中标号“B”位置所示。

(3)SysTick

系统定时器(SysTick)是Cortex-M4内核的一个外设,它是一个24bit的向下递减的计数器,一般用于产生时基信号,如实时操作系统中的系统心跳信号就是由SysTick产生的。SysTick的时钟源一般设置为SYSCLK的1/8,如图1-3-1中标号“C”位置所示。

(4)FCLK

自由运行时钟(Free Running Clock,FCLK)独立于HCLK,它用于采样中断信号以及为调试模块计时。在处理器休眠期间,FCLK可确保采样到中断信号或跟踪到休眠事件,如图1-3-1中标号“D”位置所示。

(5)PCLK1和PCLK2

外设时钟(Peripheral Clock,PCLK)是APB上的时钟信号。STM32F4上有两条APB,分别是低速外设总线(APB1)和高速外设总线(APB2)。APB1上的时钟信号为PCLK1,APB2上的时钟信号为PCLK2。PCLK1和PCLK2由SYSCLK分别经APB1预分频器和APB2预分频器分频后产生,分频系数可以是1、2、4、8、16等。

PCLK1的最大频率为42MHz,它主要为挂载在APB1上的低速外设提供时钟,如USART2、TIM2和TIM3等。

PCLK2的最大频率为84MHz,它主要为挂载在APB2上的高速外设提供时钟,如USART1、TIM1和GPIO等,如图1-3-1中标号“E”位置所示。

(6)TIMxCLK

从图1-3-1中标号“F”位置可以看到,APB预分频器有一路输出接入定时器(Timer)的倍频器。PCLK信号经倍频后作为定时器时钟(TIMxCLK),倍频系数可选1或2,即TIMxCLK=PCLK×1(或2),更详细的配置内容见本书3.1.2节。

1.3.3 任务实施

1.主PLL的配置

本任务要求将系统时钟(SYSCLK)配置为168MHz,而外部晶振(HSE)频率仅为8MHz,因此必须使用主PLL倍频来实现。主PLL的树图如图1-3-2所示,我们需要为主PLL配置以下参数:压控振荡器(VCO)输入时钟分频系数 M 、VCO输出时钟倍频系数 N 、PLLCLK时钟分频系数 P 和48MHz时钟输出的分频系数 Q

图1-3-2 主PLL的树图

根据《STM32F4xx中文参考手册》, M 的取值范围为2~63, N 的取值范围192~432, P 的取值为2、4、6、8中的一个, Q 的取值范围为2~15。

从图1-3-1可知,SYSCLK来源于PLLCLK。当HSE为8MHz时,如果要使PLLCLK输出为168MHz,则须配置 M 值为8, N 值为336, P 值为2。计算过程如下所示。

PLLCLK=(8MHz/ M )×( N / P )=1MHz×(336/2)=168MHz

同样地,配置 Q 值为7时,可使PLL48CK输出满足任务要求。计算过程如下所示。

PLL48CK=(8MHz/ M )×( N / Q )=1MHz×(336/7)=48MHz

2.根据开发板的硬件配置修改标准外设库的相关文件

STM32F4标准外设库的启动文件startup_stm32f40xx.s调用库函数SystemInit()进行系统时钟配置后,进入用户主程序main()函数。startup_stm32f40xx.s文件是用汇编语言实现的,其调用SystemInit库函数的具体实现如图1-3-3所示。

图1-3-3 启动文件调用SystemInit库函数

由于STM32F4标准外设库板载晶振的参数和主PLL的各项参数( M N P Q )的默认配置可能与开发者所用的开发板不匹配,因此需要根据开发板硬件配置对标准外设库相关文件进行修改。需要修改的地方有以下几处。

一是开发板晶振频率的配置,此项配置位于stm32f4xx.h文件的第144行。ST公司官方开发板使用的晶振频率为25MHz,如果我们的开发板的板载晶振频率为8MHz,则需要将原有宏定义“#define HSE_VALUE((uint32_t)25000000)”修改为“#define HSE_VALUE((uint32_t)8000000)”。

二是主PLL各项参数( M N P Q )的配置,它们分别位于system_stm32f4xx.c文件的第371、384、401和403行。如果板载晶振频率为8 MHz,则需要将第371行原有的宏定义“#define PLL_M 25”修改为“#define PLL_M 8”,即将VCO输入时钟分频系数 M 的值由25改为8。其他各项参数( N P Q )可根据项目实际需要进行配置。

3.为工程添加与RCC配置相关的库文件

本任务需要调用与RCC配置相关的库函数以完成系统时钟的配置,这些库函数都包含在stm32f4xx_rcc.c库文件中,因此我们应在工程中添加此文件,如图1-3-4所示。

图1-3-4 为工程添加stm32f4xx_rcc.c库文件

4.调用与RCC配置相关的函数以进行系统时钟的配置

相关准备工作完成以后,我们就可以调用与RCC配置相关的函数进行系统时钟的配置。外部时钟HSE作为时钟源的配置步骤如下。

(1)复位RCC寄存器值为默认值


RCC_DeInit(); 

(2)开启HSE,并等待其工作稳定


RCC_HSEConfig(RCC_HSE_ON); 
HSEStartUpStatus = RCC_WaitForHSEStartUp(); 

(3)配置AHB、APB2、APB1的预分频系数


RCC_HCLKConfig(RCC_SYSCLK_Div1);   // HCLK = SYSCLK / 1(1分频) 
RCC_PCLK2Config(RCC_HCLK_Div2);    // PCLK2 = HCLK / 2 (2分频) 
RCC_PCLK1Config(RCC_HCLK_Div4);    // PCLK1 = HCLK / 4 (4分频)

(4)配置主PLL的参数


RCC_PLLConfig(RCC_PLLSource_HSE, 8, 336, 2, 7); 

上述代码片段配置 M =8, N =336, P =2, Q =7。

(5)开启PLL,并等待其工作稳定


RCC_PLLCmd(ENABLE); 
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

(6)选择PLLCLK作为SYSCLK的时钟源,并等待其稳定


RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); 
while (RCC_GetSYSCLKSource() != 0x08); 

5.编写系统时钟配置程序

复制一份任务1.2的工程,修改工程名为“RCC_Configuration”,在工程根目录下新建“SYSTEM”文件夹,并建立子文件夹“sys”,新建“sys.c”和“sys.h”两个文件,在“sys.c”文件中输入以下代码:


1  #include "sys.h" 
2   
3  /** 
4     * @brief  使用外部晶振进行系统时钟的配置 
5     * @param  M: VCO输入时钟分频系数 
6     * @param  N: VCO输出时钟倍频系数 
7     * @param  P: PLLCLK时钟分频系数 
8     * @param  Q: 48MHz时钟输出的分频系数 
9     * @retval None 
10     */ 
11  void HSE_RCC_Configuration(uint16_t M, uint16_t N, uint16_t P, uint16_t Q) 
12  { 
13      __IO uint32_t HSEStartUpStatus = 0; 
14       
15      RCC_DeInit();//将RCC寄存器重新设置为默认值     
16      RCC_HSEConfig(RCC_HSE_ON);//打开HSE,并等待其工作稳定     
17      HSEStartUpStatus = RCC_WaitForHSEStartUp(); 
18      /* HSE启动成功 */ 
19      if (HSEStartUpStatus == SUCCESS) 
20      { 
21          RCC->APB1ENR |= RCC_APB1ENR_PWREN;  //调压器电压输出级别配置为1 
22          PWR->CR |= PWR_CR_VOS;                 //工作时实现性能和功耗的平衡 
23   
24          RCC_HCLKConfig(RCC_SYSCLK_Div1);     //HCLK  = SYSCLK / 1 
25          RCC_PCLK2Config(RCC_HCLK_Div2);      //PCLK2 = HCLK / 2 
26          RCC_PCLK1Config(RCC_HCLK_Div4);      //PCLK1 = HCLK / 4 
27          /* 设置主PLL相关时钟分频系数 */ 
28          RCC_PLLConfig(RCC_PLLSource_HSE, M, N, P, Q); 
29          /* 开启PLL,并等待其工作稳定 */ 
30          RCC_PLLCmd(ENABLE); 
31          while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); 
32   
33          /* 配置FLASH预取值,指令缓存,数据缓存和等待状态 */ 
34          FLASH->ACR = FLASH_ACR_PRFTEN 
35                        | FLASH_ACR_ICEN 
36                        | FLASH_ACR_DCEN 
37                        | FLASH_ACR_LATENCY_5WS; 
38          /* 选择PLLCLK作为SYSCLK的时钟源,并等待其稳定 */ 
39          RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);     
40          while (RCC_GetSYSCLKSource() != 0x08); 
41      } 
42      /* 如果HSE启动失败 */ 
43      else 
44      { 
45          //TODO 出错处理 
46      } 
47  } 

在“sys.h”文件中输入以下代码:


1  #ifndef __SYS_H 
2  #define __SYS_H 
3  #include "stm32f4xx.h" 
4   
5  void HSE_RCC_Configuration(uint16_t M, uint16_t N, uint16_t P, uint16_t Q); 
6  #endif 

6.编写main()函数

在“main.c”文件中输入以下代码并调用自定义的系统时钟配置函数,编译、下载并观察程序运行情况。如果系统时钟配置成功,可以看到开发板上两个LED同亮同灭,并循环往复。 9rYN1ObCqTP5bx4AWN9dLcWs52IDm+p2jPF0/qnGgqfXCMwlUUBuRhsnZJpcvd+8


1  #include "sys.h" 
2   
3  void Delay(__IO uint32_t nCount); 
4   
5  int main(void) 
6  { 
7      /* 调用自定义的系统时钟配置函数 */ 
8      HSE_RCC_Configuration(8,336,2,7); 
9       
10      GPIO_InitTypeDef GPIO_InitStructure; 
11      RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); 
12      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; 
13      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 
14      GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; 
15      GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed; 
16      GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; 
17      GPIO_Init(GPIOF, &GPIO_InitStructure); 
18   
19      /* 无限循环 */ 
20      while (1) 
21      { 
22          GPIO_SetBits(GPIOF, GPIO_Pin_9 | GPIO_Pin_10); 
23          Delay(0x7FFFFF); 
24          GPIO_ResetBits(GPIOF, GPIO_Pin_9 | GPIO_Pin_10); 
25          Delay(0x7FFFFF); 
26      } 
27  } 
28   
29  /** 
30    * @brief  软件延时函数 
31    * @param  None 
32    * @retval None 
33    */ 
34  void Delay(__IO uint32_t nCount) 
35  { 
36      while(nCount--){} 
37  } 

点击中间区域
呼出菜单
上一章
目录
下一章
×