前面时钟树的学习说明单片机的主频是可以修改的,那么怎么更改系统的主频,这里做一个简单的介绍。首先要明白,单片机的程序是如何运行,这里简单说明一下。
对应的代码在startup_stm32....文件里面,这里是复位程序的汇编代码。
复位子程序是系统上电后第一个执行的程序,调用 SystemInit 函数初始化系统时钟,然后调用 C 库函数 _mian,最终调用 main 函数去到 C 的世界。
WEAK:表示弱定义,如果外部文件优先定义了该标号则首先引用该标号,如果外部文件没有声 明也不会出错。这里表示复位子程序可以由用户在其他文件重新实现,这里并不是唯一的。 IMPORT:表示该标号来自外部文件,跟 C 语言中的 EXTERN 关键字类似。这里表示 SystemInit 和 __main 这两个函数均来自外部的文件。
SystemInit() 是一个标准的库函数,在 system_stm32f103xe.c 这个库文件中定义。主要作用是配置 系统时钟,这里调用这个函数之后,单片机的系统时钟配被配置为 72M。
__main 是一个标准的 C 库函数,主要作用是初始化用户堆栈,并在函数的最后调用 main 函数去 到 C 的世界。这就是为什么我们写的程序都有一个 main 函数的原因。
所以更改主频应该找到SystemInit()函数,这个函数在system_stm32f10x.c文件中。这里给出一个详细的代码。
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_CLRCC->CFGR &= (uint32_t)0xF8FF0000;
#elseRCC->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_ExtSRAMSystemInit_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_SRAMSCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#elseSCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif
}
其中是复杂的宏定义,抛开未被使用到的部分,两个重要的函数
SystemInit_ExtMemCtl()//外部时钟的引脚配置函数
SetSysClock()//时钟初始化函数
接下来看这两个函数是如何定义的
可以看到这个文档里面给出了一些宏定义,这个就是系统的频率,选定哪个,就是设定哪个频率,这里就以72MHZ为例子看是如何配置时钟的,在文档中搜索一些使用到72MHZ的地方。可以看到如果宏定义了SYSCLK_FREQ_72MHz,那 SystemCoreClock=SYSCLK_FREQ_72MHz并且定义了一个SetSysClockTo72()的函数。并且在SetSysClock()中使用SetSysClockTo72()函数。SetSysClockTo72()函数里面进行了详细的配置是系统的频率达到72MHZ。
SystemInit_ExtMemCtl()中就是对一些外部时钟引脚的定义
void SystemInit_ExtMemCtl(void)
{
/*!< FSMC Bank1 NOR/SRAM3 is used for the STM3210E-EVAL, if another Bank is required, then adjust the Register Addresses *//* Enable FSMC clock */RCC->AHBENR = 0x00000114;/* Enable GPIOD, GPIOE, GPIOF and GPIOG clocks */ RCC->APB2ENR = 0x000001E0;GPIOD->CRL = 0x44BB44BB; GPIOD->CRH = 0xBBBBBBBB;GPIOE->CRL = 0xB44444BB; GPIOE->CRH = 0xBBBBBBBB;GPIOF->CRL = 0x44BBBBBB; GPIOF->CRH = 0xBBBB4444;GPIOG->CRL = 0x44BBBBBB; GPIOG->CRH = 0x44444B44;/*---------------- FSMC Configuration ---------------------------------------*/
/*---------------- Enable FSMC Bank1_SRAM Bank ------------------------------*/FSMC_Bank1->BTCR[4] = 0x00001011;FSMC_Bank1->BTCR[5] = 0x00000200;
}
使用的F103系列的引脚是GPIOD,所以可以看到使用寄存器的方式配置了相关的引脚,能够使用外部晶振。
最终调用SystemInit()完成时钟的配置,所以只要在宏定义处使用官方配置好的一些就行,如果想要自己定义,就要重新编写寄存器相关的操作。
查看RM0008参考手册,原来这两个引脚默认为外部晶振功能(仅限于36/48/64引脚封装)
参考资料
STM32标准库修改HSI时钟教程_stm32 l011 hsi 时钟 不准确-CSDN博客