目录
PLLCLK,SYSCLK,HCKL,PCLK1,PCLK2 之间的关系
STM32时钟系统
时钟系统框图
时钟系统总结
PLLCLK,SYSCLK,HCKL,PCLK1,PCLK2 之间的关系
1、HSI:高速内部时钟信号 stm32单片机内带的时钟 (8M频率)精度较差
2、HSE:高速外部时钟信号精度高来源(1)HSE外部晶体/陶瓷谐振器(晶振) (2)HSE用户外部时钟
3、LSE:低速外部晶体 32.768kHz 主要提供一个精确的时钟源 一般作为RTC时钟使用
五大时钟源
LSE:低速外部晶体 32.768kHz 主要提供一个精确的时钟源 一般作为RTC时钟使用
在STM32中,有五个时钟源,为HSI、HSE、LSI、LSE、PLL:
①、HSI是高速内部时钟,RC振荡器,频率为8MHz。
②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。
③、LSI是低速内部时钟,RC振荡器,频率为40kHz。
④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。
⑤、PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。
简要概述系统时钟源
注:USB模块虽然需要一个单独的48MHz时钟信号,但它应该不是供USB模块工作的时钟,而只是提供给串行接口引擎(SIE)使用的时钟。USB模块工作的时钟应该是由APB1提供的,这个图中输出端口不太全,该图旨在说明核心系统时钟源的功能。
APB1&ABP2总线对应的设备
连接在APB1(低速外设)上的设备有:电源接口、备份接口、CAN、USB、I2C1、I2C2、UART2、UART3、SPI2、窗口看门狗、Timer2、Timer3、Timer4;
连接在APB2(高速外设)上的设备有:UART1、SPI1、Timer1、ADC1、ADC2、所有普通IO口(PA~PE)、第二功能IO口。
与时钟相关的寄存器
我们要知道无论是STM32官方提供的库函数还是其提供的寄存器操作方法,本质上来说都是对相应的寄存器进行操作。
RCC 寄存器结构,RCC_TypeDeff,在文件“stm32f10x_map.h”中定义如下:
typedef struct
{
vu32 CR; //HSI,HSE,CSS,PLL等的使能
vu32 CFGR; //PLL等的时钟源选择以及分频系数设定
vu32 CIR; // 清除/使能 时钟就绪中断
vu32 APB2RSTR; //APB2线上外设复位寄存器
vu32 APB1RSTR; //APB1线上外设复位寄存器
vu32 AHBENR; //DMA,SDIO等时钟使能
vu32 APB2ENR; //APB2线上外设时钟使能
vu32 APB1ENR; //APB1线上外设时钟使能
vu32 BDCR; //备份域控制寄存器
vu32 CSR;
} RCC_TypeDef;
这里RCC是Reset and clock control的缩写,意为“复位与时钟控制”
STM32官方库函数讲解
时钟初始化SystemInit()函数
我们知道在操作STM32开发板之前,必须先初始化全部的时钟,是他们均恢复到默认状态,然后我们再在函数文件中使能相应的时钟。那问题来了,我们一般编写函数文件时没用过SystemInit()函数呀?SystemInit()函数是怎么调用的?
SystemInit()函数在哪里定义的?
SystemInit()函数在那里被调用的?
由于SystemInit()函数调用是STM32的核心代码,因此放到启动文件中,如果要查找可以在CORE->startup_stm32f10x_xx.s中找到。
更加个性化的系统初始化函数调用
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit // 如果你编写了自己的时钟初始化函数可以将SystemInit换为你自己的初始化函数
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
SystemInit()函数如何工作?
// 系统初始化函数SystemInit()
void SystemInit (void)
{
/* 将RCC时钟配置重置为默认重置状态(用于调试) */
/* 设置 HSION 位为1 , 即默认状态下系统时钟源为HSI*/
RCC->CR |= (uint32_t)0x00000001;
/* 设置 HSEON, CSSON and PLLON 位为0 */
RCC->CR &= (uint32_t)0xFEF6FFFF;
/* 设置 HSEBYP 位为0 */
RCC->CR &= (uint32_t)0xFFFBFFFF;
/* 设置 PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE 位为0 */
RCC->CFGR &= (uint32_t)0xFF80FFFF;
/* 配置系统时钟频率,HCLK, PCLK2和PCLK1分频器 */
/* 配置Flash延迟周期并启用预取缓冲区 */
SetSysClock(); // 用于配置系统时钟频率,HCLK, PCLK2和PCLK1预压器
#ifdef VECT_TAB_SRAM
SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif
}
// 系统时钟速度配置函数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
/* 如果以上定义都没有启用,则HSI将用作系统时钟源(使用默认值) */
}
此外,我们还可以自定义初始速度:
只要我们把注释掉的预定义命令恢复,就可以配置不同速度。
可以读出系统时钟速度的变量SystemCoreClock:
/*******************************************************************************
* Clock Definitions
*******************************************************************************/
#ifdef SYSCLK_FREQ_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_24MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_24MHz; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_36MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_36MHz; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_48MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_56MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_72MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz; /*!< System Clock Frequency (Core Clock) */
#else /*!< HSI Selected as System Clock source */
uint32_t SystemCoreClock = HSI_VALUE; /*!< System Clock Frequency (Core Clock) */
#endif
系统文件中跨文件全局变量的宏定义声明
图中“STM32F10X_HD,USE_STDPERIPH_DRIVER “为所有文件均能识别的宏定义标志,其中我们很常见的是” STM32F10X_HD “,它代表的是大容量芯片。