STM32是使用的内部时钟还是外部时钟

STM32是使用的内部时钟还是外部时钟,经常会有人问这个问题。

1、先了解时钟树,见下图:

2、在MDK中,使用的是HSE+PLL作为SYSCLK,因此需要对时钟配置寄存器(RCC_CFGR)进行配置,寄存器内容如下:

根据时钟树,需要对时钟配置寄存器(RCC_CFGR)的PLLXTPRE(bit17),PLLSRC(bit16),PLLMUL[3:0](bit21:18),SW[1:0](bit1:0)进行配置。

#define RCC_CFGR_PLLXTPRE ((uint32_t)0x00020000)

// RCC_CFGR)的PLLXTPRE(bit17)

#define RCC_CFGR_PLLSRC_HSE ((uint32_t)0x00010000)

//令PLLSRC=1选择HSE时钟源

#define RCC_CFGR_PLLMULL9 ((uint32_t)0x001C0000)

//令PLLMUL=7,设置PLL乘法因子为9

#define RCC_CFGR_SW_PLL ((uint32_t)0x00000002) // SW选择PLL作为系统时钟源

static void SetSysClockTo72(void)

{

__IO uint32_t StartUpCounter = 0, HSEStatus = 0;

/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/

/* Enable HSE */

RCC->CR |= ((uint32_t)RCC_CR_HSEON); //使能HSE外部时钟

/* 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)

{

/* Enable Prefetch Buffer */

FLASH->ACR |= FLASH_ACR_PRFTBE;

/* Flash 2 wait state */

FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);

FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;

/*设置AHB分频器的值为0,则HCLK = SYSCLK=72MHz */

RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;

/*设置APB2分频器的值为0,则 PCLK2 = HCLK= SYSCLK=72MHz */

RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

/*设置APB1分频器的值为2,则PCLK1 = HCLK/2=36MHz */

RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

#ifdef STM32F10X_CL

/* Configure PLLs ------------------------------------------------------*/

/* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */

/* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */

RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |

RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);

RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |

RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);

/* Enable PLL2 */

RCC->CR |= RCC_CR_PLL2ON;

/* Wait till PLL2 is ready */

while((RCC->CR & RCC_CR_PLL2RDY) == 0)

{

}

/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */

RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);

RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |

RCC_CFGR_PLLMULL9);

#else

/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */

RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |

RCC_CFGR_PLLMULL));

//利用RCC_CFGR_PLLXTPRE 将PLLXTPRE=0,HSE输入时钟不用分频

RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);

// RCC_CFGR_PLLSRC_HSE令PLLSRC=1选择HSE时钟源

// RCC_CFGR_PLLMULL9令PLLMUL=7,设置PLL乘法因子为9

//至此外部晶振为8MHz,到这里就是72MHz了

#endif /* STM32F10X_CL */

/* 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;

// 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 */

}

}

3、系统是怎么调用SetSysClockTo72()

STM32默认是使用HSI内部RC 8MHz启动的,上电复位会执行Reset_Handler,见下图:

在Reset_Handler中,有一个SystemInit,就是C语言的SystemInit()函数,复位中断执行结束后则跳转到main(),SystemInit()函数原型如下:

void SystemInit (void)

{

/* Reset the RCC clock configuration to the default reset state(for debug purpose) */

/* Set HSION bit */

RCC->CR |= (uint32_t)0x00000001;

/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */

#ifndef STM32F10X_CL

RCC->CFGR &= (uint32_t)0xF8FF0000;

#else

RCC->CFGR &= (uint32_t)0xF0FF0000;

#endif /* STM32F10X_CL */

/* Reset HSEON, CSSON and PLLON bits */

RCC->CR &= (uint32_t)0xFEF6FFFF;

/* Reset HSEBYP bit */

RCC->CR &= (uint32_t)0xFFFBFFFF;

/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */

RCC->CFGR &= (uint32_t)0xFF80FFFF;

#ifdef STM32F10X_CL

/* Reset PLL2ON and PLL3ON bits */

RCC->CR &= (uint32_t)0xEBFFFFFF;

/* Disable all interrupts and clear pending bits */

RCC->CIR = 0x00FF0000;

/* Reset CFGR2 register */

RCC->CFGR2 = 0x00000000;

#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)

/* Disable all interrupts and clear pending bits */

RCC->CIR = 0x009F0000;

/* Reset CFGR2 register */

RCC->CFGR2 = 0x00000000;

#else

/* Disable all interrupts and clear pending bits */

RCC->CIR = 0x009F0000;

#endif /* STM32F10X_CL */

#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)

#ifdef DATA_IN_ExtSRAM

SystemInit_ExtMemCtl();

#endif /* DATA_IN_ExtSRAM */

#endif

/* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */

/* Configure the Flash Latency cycles and enable prefetch buffer */

SetSysClock();//设置系统时钟

#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

}

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();

//由于在"Options for Target 'CAN Slave'"中定义了STM32F10X_MD,所以程序会执行这条语句配置系统时钟

#endif

/* If none of the define above is enabled, the HSI is used as System clock

source (default after reset) */

}

程序调用SetSysClockTo72()的说明如下:

在"Options for Target 'CAN Slave'"中定义了STM32F10X_MD,见下图:

因此,在MAK-ARM中,会调用SetSysClockTo72()这个函数,从而实现对系统的配置。

4、HSE,HIS和PLL时钟启动和工作状态

MDK已经写好了,就不要去逐句理解了。我们的目的是会使用,因此,只要重点掌握CPU是从HSI时钟切换到HSE,使用PLL使用作为系统时钟,就可以了。如果你想做低功耗,就需要你自己去深入学习时钟树和内部寄存器的用法。

5、配置后的时钟树

相关推荐
一川月白7096 小时前
51单片机---硬件学习(电子琴、主从应答模式、modbus模型、DS18B20传感器显示温度)
嵌入式硬件·51单片机·串口通信·异步通信·串行通信·同步通信·并行通信
逼子格6 小时前
【Proteus仿真】定时器控制系列仿真——秒表计数/数码管显示时间
数据库·单片机·嵌入式硬件·51单片机·proteus·定时器·硬件工程师
芯片智造7 小时前
一文看懂什么是GaN HEMT以及其工艺流程(氮化镓高电子迁移率晶体管)
经验分享·芯片·半导体·晶体管·氮化镓高电子迁移率晶体管
2401_888423098 小时前
51单片机-按键、蜂鸣器、定时器模块及中断
单片机·嵌入式硬件·51单片机
东亚_劲夫8 小时前
STM32—SPI协议
stm32·单片机·嵌入式硬件
罗光记10 小时前
腾讯混元游戏视觉生成平台正式发布2.0版本
数据库·经验分享·百度·facebook·开闭原则
♞沉寂10 小时前
c51串口通信原理及实操
单片机·51单片机·c51
猫头虎10 小时前
2025最新超详细FreeRTOS入门教程:第一章 FreeRTOS移植到STM32
stm32·单片机·嵌入式硬件·机器人·硬件架构·freertos·嵌入式实时数据库
清风66666612 小时前
基于STM32单片机的酒驾检测设计
stm32·单片机·嵌入式硬件·毕业设计·课程设计
恒森宇电子有限公司13 小时前
IP5326_BZ 支持C同口输入输出的移动电源芯片 2.4A的充放电电流 支持4LED指示灯
c语言·开发语言·单片机