文章目录
一.系统时钟原理图
在 STM32f103 中,有五个时钟源,为 HSI、HSE、LSI、LSE、PLL。从时钟频率来分可以分为高速时钟源和低速时钟源,在这 5 个中 HIS,HSE 以及 PLL 是高速时钟,LSI 和 LSE 是低速时钟。从来源可分为外部时钟源和内部时钟源,外部时钟源就是从外部通过接晶振的方式获取时钟源,其中 HSE 和 LSE 是外部时钟源,其他的是内部时钟源。
二.系统时钟配置方法
1.通过汇编进入系统初始化函数(startup_stm32f10x_hd.s)
//通过汇编进入系统初始化函数
IMPORT SystemInit
2.在系统初始化函数SystemInit中调用系统时钟设置函数SetSysClock(system_stm32f10x.c)
//在系统初始化函数SystemInit中调用系统时钟设置函数SetSysClock()
void SystemInit (void)
{
/* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
/* Configure the Flash Latency cycles and enable prefetch buffer */
SetSysClock();
}
3.对各时钟进行宏定义(system_stm32f10x.c)
//对各时钟进行宏定义
#define SYSCLK_FREQ_HSE HSE_VALUE //8000000
//#define SYSCLK_FREQ_16MHz 16000000
//#define SYSCLK_FREQ_24MHz 24000000
//#define SYSCLK_FREQ_36MHz 36000000
//#define SYSCLK_FREQ_48MHz 48000000
//#define SYSCLK_FREQ_56MHz 56000000
//#define SYSCLK_FREQ_72MHz 72000000
4.声明各系统时钟配置函数(system_stm32f10x.c)
//声明各系统时钟配置函数
#ifdef SYSCLK_FREQ_HSE
static void SetSysClockToHSE(void);
#elif defined SYSCLK_FREQ_16MHz
static void SetSysClockTo16(void);
#elif defined SYSCLK_FREQ_24MHz
static void SetSysClockTo24(void);
#elif defined SYSCLK_FREQ_36MHz
static void SetSysClockTo36(void);
#elif defined SYSCLK_FREQ_48MHz
static void SetSysClockTo48(void);
#elif defined SYSCLK_FREQ_56MHz
static void SetSysClockTo56(void);
#elif defined SYSCLK_FREQ_72MHz
static void SetSysClockTo72(void);
#endif
5.调用各系统时钟配置函数(system_stm32f10x.c)
//调用各系统时钟配置函数
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
SetSysClockToHSE(); //8MHz
#elif defined SYSCLK_FREQ_16MHz
SetSysClockTo16(); //16MHz
#elif defined SYSCLK_FREQ_24MHz
SetSysClockTo24(); //24MHz
#elif defined SYSCLK_FREQ_36MHz
SetSysClockTo36(); //36MHz
#elif defined SYSCLK_FREQ_48MHz
SetSysClockTo48(); //48MHz
#elif defined SYSCLK_FREQ_56MHz
SetSysClockTo56(); //56MHz
#elif defined SYSCLK_FREQ_72MHz
SetSysClockTo72(); //72MHz
#endif
/* If none of the define above is enabled, the HSI is used as System clock
source (default after reset) */
}
6.以设置系统时钟为16MHz为例(system_stm32f10x.c)
//设置系统时钟为16MHz
static void SetSysClockTo16(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
#if !defined STM32F10X_LD_VL && !defined STM32F10X_MD_VL && !defined STM32F10X_HD_VL
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE;
/* Flash 0 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0;
#endif
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1;
/* PLL configuration: = (HSE / 2) * 4 = 16 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_HSE_Div2 | RCC_CFGR_PLLMULL4);
/* Enable PLL */
RCC->CR |= RCC_CR_PLLON;
/* Wait till PLL is ready */
while((RCC->CR & RCC_CR_PLLRDY) == 0)
{
}
/* Select PLL as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* Wait till PLL is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
{
}
}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}
其中不同配置需要改的地方:
1)选择FLASH_ACR_LATENCY:
FLASH_ACR_LATENCY_0/FLASH_ACR_LATENCY_1/FLASH_ACR_LATENCY_2
FLASH_ACR_LATENCY的选择:
STM32的FLASH手册上,关于FLASH_ACR寄存器的LATENCY位的说明,上面明确写着:
0 wait state if 0MHz < SYSCLK <= 24MHz
1 wait state if 24MHz < SYSCLK <= 48MHz
2 wait state if 48MHz < SYSCLK <= 72MHz
2)配置PLL时钟:
/* PLL configuration: = (HSE / 2) * 4 = 16 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_HSE_Div2 | RCC_CFGR_PLLMULL4);
三.获取各系统时钟方法
//在stm32f10x_rcc.h中定义
/*定义枚举类型变量获取时钟类型**/
typedef enum
{
SYSCLK_frequency=0u, /* 获取SYSCLK时钟 */
AHB_frequency=1u, /* 获取AHB时钟 */
APB1_frequency=2u, /* 获取APB1时钟 */
APB2_frequency=3u, /* 获取APB2时钟 */
ADCCLK_frequency=4u, /* 获取APB2时钟 */
}RCC_clock_type;
u32 Get_rcc_clock(RCC_clock_type clock_type); //声明获取当前时钟函数
//在stm32f10x_rcc.c中定义
u32 Get_rcc_clock(RCC_clock_type clock_type)
{
u32 RCC_clock;
RCC_ClocksTypeDef get_rcc_clock; //获取系统时钟状态
RCC_GetClocksFreq(&get_rcc_clock); //通过结构体get_rcc_clock获取各时钟
switch (clock_type)
{
case SYSCLK_frequency:
RCC_clock=get_rcc_clock.SYSCLK_Frequency; //获取SYSCLK时钟
break;
case AHB_frequency:
RCC_clock=get_rcc_clock.HCLK_Frequency; //获取AHB时钟
break;
case APB1_frequency:
RCC_clock=get_rcc_clock.PCLK1_Frequency; //获取APB1时钟
break;
case APB2_frequency:
RCC_clock=get_rcc_clock.PCLK2_Frequency; //获取APB2时钟
break;
case ADCCLK_frequency:
RCC_clock=get_rcc_clock.ADCCLK_Frequency; //获取ADCCLK时钟
break;
default:
RCC_clock=0;
break;
}
return RCC_clock;
}
//在main.c中获取当前时钟
printf("SYSCLK_frequency=%d\r\n",Get_rcc_clock(SYSCLK_frequency));
printf("AHB_frequency=%d\r\n",Get_rcc_clock(AHB_frequency));
printf("APB1_frequency=%d\r\n",Get_rcc_clock(APB1_frequency));
printf("APB2_frequency=%d\r\n",Get_rcc_clock(APB2_frequency));
printf("ADCCLK_frequency=%d\r\n",Get_rcc_clock(ADCCLK_frequency));
四. 感谢支持
完结撒花!希望看到这里的小伙伴能点个关注,我后续会持续更新,也欢迎大家广泛交流。
码字实属不易,如果本文对你有10分帮助,就赏个10分把,感谢各位大佬支持!