实验4 系统时钟实验
上一章,我们介绍了STM32 内部系统滴答定时器,该滴答定时器产生的延时非常精确。
在本章中,我们将自定义RCC系统时钟,通过改变其倍频与分频实现延时时间变化,实现LED灯闪烁效果。
通过本章的学习,你将了解 RCC系统时钟的使用。
本章分为以下学习目标:
1、了解 STM32 的系统构架。
2、了解 STM32 的时钟构架。
3、了解 RCC 时钟的操作步骤。
1.1 STM32 的系统构架
STM32 的时钟比较复杂,它可以选择多种时钟源,也可以选择不一样的时钟频率,而且在系统总线上面,每条系统的时钟选择都是有差异的。
所以想要清楚的了解 STM32 的时钟分配,我们先来了解一下 STM32 的系统构架是什么样的。
从上图我们知道,RCC 时钟输出时钟出来,然后经过 AHB 系统总线,分别
分配给其他外设时钟,而不一样的外设,是先挂在不一样的桥上的。
比如: ADC1、ADC2、 SPI1、GPIO 等都是挂在 APB2 上面,而有些是挂在 APB1上面,所以,虽然它们都是从 RCC 获取的时钟,但是它们的频率有时候是不一样的。
1.2 STM32 的时钟树
STM32 单片机上电之后,系统默认是用的时钟是单片机内部的高速晶振时钟,而这个晶振容易受到温度的影响,所以晶振跳动的时候不是有一定的影响,所以一般开发使用的时候都是使用外部晶振,而且单片机刚启动的时候,它的时钟频率是 8MHZ,而 STM32 时钟的最高频率是 72MHZ,所以单片机一般开机之后运行的程序是切换时钟来源,并设置时钟频率。
大家可能有点疑惑,在第一章到第三章之中,我们并没有看到单片机开机之后设置时钟来源和时钟频率的。
其实在使用库函数的时候,其实在库函数启动文件里面,是帮助我们把时钟频率设置到 72MHZ 了。
大家可以打开一个库函数工程,在 system_stm32f10x.c 的第 106行,它定义了一个 SYSCLK_FREQ_72MHz:
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
#define SYSCLK_FREQ_24MHz 24000000
#else
#define SYSCLK_FREQ_72MHz 72000000
然后在下面的程序中,根据这个 SYSCLK_FREQ_72MHz 定义,它默认设置成
72MHZ。
接下来我们来看一下具体的 RCC 时钟树:
从上图我们可以知道,STM32 的时钟一共有可以有 4 个晶振源:
1) 内部自带的高速时钟:HIS。
单片机启动之后默认使用的时钟来源。
2) 外部高速时钟:HSE。
大多数时钟时钟的是 8MHZ 的晶振。
3) 外部低速时钟:LSE。
主要用来给单片机内部的 RTC 提供时钟。
4) 内部的低速时钟:LSI。
主要用来给单片机内部的 RTC 和看门狗提供时钟。
而 STM32 的系统时钟源,有 3 个时钟来源:
1) 直接来自内部的高速时钟 HIS。
2) 直接来自外部的高速时钟 HSE。
3) 将 HIS 或者 HSE 进行处理,倍频之后的 PLL 时钟。
注意:从图上,大家可以看到很多外设时钟都有一个外设时钟使能,以当我们使用相应的外设的时候,注意要将时钟使能打开。
因为在单片机启动之后,为了降低单片机的功耗,这些外设时钟使能是默认关闭的。
1.3 STM32 设置 RCC 时钟的步骤
以设置外部高速时钟作为 PLL 输入,然后用 PLL 作为时钟源为例子,具体操作步骤如下:
1) 复位 RCC 时钟。
2) 打开 HSE 外部高速时钟。
3) 检测 HSE 外部高速时钟是否开启成功。
4) 设置 FLASH 的读写。
(这个是用来支持程序对 FLASH 的读写的,必须设置。
)
5) 设置 AHB 总线的分频,还有 APB1 和 APB2 的分频。
注意,AHB 和 APB2 最大频率是 72MHZ,APB1 的最大频率是才 36MHZ。
6) 设置 HSE 外部高速时钟作为 PLL 时钟的时钟输入(注意 HSE 外部高速时钟作为 PLL 时钟输入时,可以直接输入,也可以作二分频之后再输入,要选择输入的方式。
)
7) 设置 PLL 时钟的倍频的倍数。
8) 打开 PLL 时钟的使能。
9) 等待 PLL 时钟开启成功。
10) 将系统时钟源设置为 PLL 时钟。
11) 等待时钟源切换成功。
1.4 V3.5 库函数介绍
1、RCC_DeInit()函数
复位函数是将RCC 时钟复位为内部高速时钟作为输入,让我们能够进行时钟设置操作。
2、RCC_HSEConfig()函数
这个函数是设置HSE 外部高速时钟的函数,可以开启、关闭、和旁路。
3、RCC_WaitForHSEStartUp()函数
4、RCC_HCLKConfig()函数
5、RCC_PCLK2Config()函数
6、RCC_PCLK1Config()函数
7、RCC_PLLConfig()函数
8、RCC_PLLCmd()函数
9、RCC_GetFlagStatus()函数
这个函数可以用来获取各种状态标志,以检测设置是否成功。
10、RCC_SYSCLKConfig()函数
11、RCC_GetSYSCLKSource()函数
1.5 RCC 时钟例程程序
1)主函数
/**************************************************************************** * Function Name : main
* Description : Main program.
* Input : None
* Output : None
* Return : None
****************************************************************************/ int main()
{
LED_Init(); //LED端口初始化
RCC_HSE_Configuration();// 自定义系统时间,通过修改里面的倍频及分频即可
while(1)
{
GPIO_SetBits(GPIOC,LED);
delay_ms(500);//精确延时为0.5s
GPIO_ResetBits(GPIOC,LED);
delay_ms(500);//精确延时为0.5s
}
}
程序下载到板子上面之后的程序效果是: LED闪烁时间本来延时是500ms,由于RCC系统时钟频率改变,使得LED闪烁时间变为1秒。
2)RCC 时钟设置函数
/****************************************************************************** *
* 函数名: RCC_HSE_Configuration
* 函数功能: 自定义系统时钟,可以通过修改PLL时钟源和倍频系数实现时钟调整
* 输入: 无
* 输出: 无
******************************************************************************* /
void RCC_HSE_Configuration() //自定义系统时间(可以修改时钟)
{
RCC_DeInit(); //将外设RCC寄存器重设为缺省值
RCC_HSEConfig(RCC_HSE_ON);//设置外部高速晶振(HSE)
if(RCC_WaitForHSEStartUp()==SUCCESS) //等待HSE起振
{
RCC_HCLKConfig(RCC_SYSCLK_Div1);//设置AHB时钟(HCLK)
RCC_PCLK1Config(RCC_HCLK_Div2);//设置低速AHB时钟(PCLK1)
RCC_PCLK2Config(RCC_HCLK_Div1);//设置高速AHB时钟(PCLK2)
RCC_PLLConfig(RCC_PLLSource_HSE_Div2,RCC_PLLMul_9);//设置PLL时钟源及倍频系数
RCC_PLLCmd(ENABLE); //使能或者失能PLL
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET);//检查指定的RCC标志位设置与否,PLL就绪
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);//设置系统时钟(SYSCLK)
while(RCC_GetSYSCLKSource()!=0x08);//返回用作系统时钟的时钟源,0x08:PLL作为系统时钟
}
这个函数的作用是:设置单片机的时钟来源为 HSE 外部高速时钟,并根据输入频率参数设置相应的频率。
要注意的是设置的输入频率参数一定要是 8 的倍数,并且是从 4 倍到 9 倍的频率数值。