基于正点原子mini开发板、STM32RCT6、库函数
时钟系统是CPU的脉搏。
无论是小型单片机还是像STM32这样的高级单片机,它们工作的核心都是大规模的时序逻辑电路,而驱动电路的关键则是准确而且稳定的时钟源。时钟为时序电路提供基本的脉冲信号,用于协调和同步各单元运行。
51单片机不需要配置时钟,是因为一个时钟开了之后所有的功能都可以用了,而这个时钟是默认开启的。stm32之所以是低功耗,是因为它将所有的外设时钟都默认设置为disable,也就是说用到什么外设,只要打开对应外设的时钟就可以,其他的没用到的可以还是disable,这样耗能就会减少。
在 STM32 中,有五个时钟源,为 HSI、HSE、LSI、LSE、PLL。从时钟频率来分可以分为高速时钟源和低速时钟源,在这 5 个中 HIS,HSE 以及 PLL 是高速时钟,LSI 和 LSE 是低速时钟。从来源可分为外部时钟源和内部时钟源,外部时钟源就是从外部通过接晶振的方式获取时钟源,其中 HSE 和 LSE 是外部时钟源,其他的是内部时钟源。
1、HSI
HSI,High Speed Internal Clock Signal,高速内部时钟,由内置RC振荡器产生,频率为8MHz,精度不高,备用时钟。
2、HSE
HSE,High Speed External Clock Signal,高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4-16MHz(常用8MHz),启动后需要稳定时间才能输出稳定的时钟信号。
3、LSE
LSE,Low Speed External Clock Signal,低速外部时钟,外接频率为32.768KHz的晶振,启动后需要稳定时间才能输出稳定的时钟信号,主要是RTC(Real Time Clock)实时时钟单元的时钟源。
4、LSI
LSI,Low Speed Internal Clock Signal,低速内部时钟,内置RC振荡器产生,频率约为40KHz,在30-60KHz范围浮动,精度差,是独立看门狗的时钟源、RTC的时钟源之一。
5、PLL
PLL,Phase Locked Loop,锁相环对输入信号进行倍频,输入信号:HSE、HSE/2,HIS/2,输出信号:输入信号*倍频系数,倍频系数:2-16,但是其输出频率最大不得超过72MHz。
6、SYSCLK(系统时钟)
供STM32中绝大部分部件工作的时钟源。输入信号:HSE、HSI、PLLCLK,频率最大不得超过72MHz。经AHB预分频器分频后送给各模块使用。
7、USBCLK(USB时钟)
频率48MHz,时钟源来自于PLL,当需要使用USB模块时,PLL必须使能,并且时钟频率配置为48MHz或72MHz,经USB预分频器分频后得到48MHz供给USB使用。
8、MCO功能模块(引脚)
MCO是STM32一个时钟输出的IO口,可选择SYSCLK、HIS、HSE、PLLCLK/2中的一个作为输出,供给其他系统作为输入时钟源。
9、APB1与APB2
APB1 上面连接的是低速外设,包括电源接口、备份接口、CAN、USB、I2C1、I2C2、UART2、UART3 等等,APB2 上面连接的是高速外设包括 UART1、SPI1、Timer1、ADC1、ADC2、所有普通 IO 口(PA~PE)、第二功能 IO 口等。
RCC相关配置寄存器可查阅官方芯片手册。
typedef struct
{
__IO uint32_t CR; //HSI,HSE,CSS,PLL等的使能和就绪标志位
__IO uint32_t CFGR; //PLL等的时钟源选择,分频系数设定
__IO uint32_t CIR; // 清除/使能 时钟就绪中断
__IO uint32_t APB2RSTR; //APB2线上外设复位寄存器
__IO uint32_t APB1RSTR; //APB1线上外设复位寄存器
__IO uint32_t AHBENR; //DMA,SDIO等时钟使能
__IO uint32_t APB2ENR; //APB2线上外设时钟使能
__IO uint32_t APB1ENR; //APB1线上外设时钟使能
__IO uint32_t BDCR; //备份域控制寄存器
__IO uint32_t CSR; //控制状态寄存器
} RCC_TypeDef;
STM32时钟系统的配置主要在 stm32f10x_rcc.c 文件中,里面有很多时钟设置函数:
1.时钟使能配置:
RCC_LSEConfig() 、RCC_HSEConfig()、 RCC_HSICmd() 、 RCC_LSICmd() 、
RCC_PLLCmd() ……
2. 时钟源相关配置:
RCC_PLLConfig ()、 RCC_SYSCLKConfig() 、 RCC_RTCCLKConfig() …
3. 分频系数选择配置:
RCC_HCLKConfig() 、 RCC_PCLK1Config() 、 RCC_PCLK2Config()…
4. 外设时钟使能:
RCC_APB1PeriphClockCmd(); //APB1线上外设时钟使能
RCC_APB2PeriphClockCmd(); //APB2线上外设时钟使能
RCC_AHBPeriphClockCmd();//AHB线上外设时钟使能
5. 其他外设时钟配置:
RCC_ADCCLKConfig (); RCC_RTCCLKConfig();
6. 状态参数获取参数:
RCC_GetClocksFreq(); RCC_GetSYSCLKSource(); RCC_GetFlagStatus()
7. RCC中断相关函数 :
RCC_ITConfig() 、 RCC_GetITStatus() 、 RCC_ClearITPendingBit()…
在设置时钟的时候,一定要仔细参考 STM32 的时钟图,做到心中有数。这里需要指明一下,对于系统时钟,默认情况下是在 SystemInit 函数的 SetSysClock()函数中间判断的,而设置是通过宏定义设置的。可以看到SetSysClock()函数体:
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
SetSysClockTo56();
#elif defined SYSCLK_FREQ_72MHz
SetSysClockTo72();
#endif
}
这段代码就是判断系统宏定义的时钟是多少,然后设置相应值。系统默认宏定义是 72MHz:
#define SYSCLK_FREQ_72MHz 72000000
如果要设置为 36MHz,只需要注释掉上面代码,然后加入下面代码即可:
#define SYSCLK_FREQ_36MHz 36000000
同时还要注意的是,当我们设置好系统时钟后,可以通过变量 SystemCoreClock 获取系统时钟值,如果系统是 72M 时钟,那么 SystemCoreClock=72000000。这是在 system_stm32f10x.c 文件中设置的:
#ifdef SYSCLK_FREQ_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_HSE;
#elif defined SYSCLK_FREQ_36MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_36MHz;
#elif defined SYSCLK_FREQ_48MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz;
#elif defined SYSCLK_FREQ_56MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz;
#elif defined SYSCLK_FREQ_72MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz;
#else
uint32_t SystemCoreClock = HSI_VALUE;
#endif
总结一下 SystemInit()函数中设置的系统时钟大小:
SYSCLK(系统时钟) =72MHz
AHB 总线时钟(使用 SYSCLK) =72MHz
APB1 总线时钟(PCLK1) =36MHz
APB2 总线时钟(PCLK2) =72MHz
PLL 时钟 =72MHz