完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
时钟系统框图
观察上图时钟系统框图,可知道 蓝色矩形表示时钟振荡源(5个):HSI RC、HSE Osc、PLL(锁相环、倍频器)、LSE Osc、LSI RC H:快速、L:低速、S:速度、I:内部、E:外部 灰色梯形表示选择器:通过不同选择器的选择,SYSCLK系统时钟、RTCCLK实时时钟、IWDGCLK独立看门狗时钟、USBCLK USB时钟可有多种选择。 黄色矩形css表示时钟监视系统:监控若时钟出错,则自动切换为HSI 白色小矩形:OSC_OUT、OSC_IN表示外接时钟信号。MCO输出内部时钟的引脚PA8。 绿色矩形表示分频器 总结: STM32 有5个时钟源:HSI、HSE、LSI、LSE、PLL。 ①、HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。 ②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。 ③、LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟。WDG ④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。RTC ⑤、PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。 倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。 系统时钟SYSCLK可来源于三个时钟源: ①、HSI振荡器时钟 ②、HSE振荡器时钟 ③、PLL时钟 STM32可以选择一个时钟信号输出到MCO脚(PA8)上,可以选择为PLL 输出的2分频、HSI、HSE、或者系统时钟。 任何一个外设在使用之前,必须首先使能其相应的时钟。 几个重要的时钟: ①、SYSCLK(系统时钟) ②、 AHB总线时钟 ③、 APB1总线时钟(低速): 速度最高36MHz ④、 APB2总线时钟(高速): 速度最高72MHz ⑤、 PLL时钟 RCC相关配置寄存器 stm32f10x.h中可找到以下结构体。 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; RCC相关文件和固件库源文件 头文件:stm32f10x_rcc.h、源文件:stm32f10x_rcc.c systemInit()函数详细解读 打开项目中:system_stm32f10x.c下面的system_stm32f10x.h可找到systemInit()函数。也可直接从system_stm32f10x.c中找到systemInit()函数的相关定义。 再打开STM32参考手册6.3小结中,可知时钟控制寄存器(RCC_CR)的相关应用。 根据参考手册中关于寄存器CR的介绍可知,CR是32位寄存器。做要打开振荡源HSI RC需要对CR寄存器中最后一位置1,即下面代码的操作: /* Set HSION bit */ RCC-》CR |= (uint32_t)0x00000001; 因为我们使用的大容量,末尾为HD,故下面这几段代码并不会执行: #ifndef STM32F10X_CL RCC-》CFGR &= (uint32_t)0xF8FF0000; #else RCC-》CFGR &= (uint32_t)0xF0FF0000; #endif /* STM32F10X_CL */ 重置HSEBYP为0.(设置为0相当于关闭) /* Reset HSEBYP bit */ RCC-》CR &= (uint32_t)0xFFFBFFFF 寄存器CFGR中重置PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE为0. /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */ RCC-》CFGR &= (uint32_t)0xFF80FFFF; 根据主板的型号,执行对应位置的代码,我们用的是HD,故应该执行#else下的语句,将所有的中断都清理掉。 #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 接下来调用厦门这个函数,可以“Go To Definition of“ SetSysClock();”” /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */ /* Configure the Flash Latency cycles and enable prefetch buffer */ 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 /* If none of the define above is enabled, the HSI is used as System clock source (default after reset) */ } 这边是根据宏定义是哪个,就执行里面的语句,可以接着从中随便“Go To Definition of“ xxx;””选择一个查看,可追溯到以下程序: #if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL) /* #define SYSCLK_FREQ_HSE HSE_VALUE */ #define SYSCLK_FREQ_24MHz 24000000 #else /* #define SYSCLK_FREQ_HSE HSE_VALUE */ /* #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 #endif 这边根据需要,选择不同的频率,不用的频率要相应的注释掉。根据这边,我们知道这边选择的是:SYSCLK_FREQ_72MHz,所以就会执行的函数就是:SetSysClockTo72();即以下程序: 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); /Go To 后,可知是对第20位进行置1,即打开外部高速时钟/ /等待对应的时钟源稳定,这边使用do while循环实现,判断对应位寄存器的数值是否为1/ /* Wait till HSE is ready and if Time out is reached exit */ do { HSEStatus = RCC-》CR & RCC_CR_HSERDY; /判断RCC_CR_HSERDY(17位)的数值是否为1/ StartUpCounter++; } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT)); if ((RCC-》CR & RCC_CR_HSERDY) != RESET) /若这边就绪了则执行0x01赋值/ { HSEStatus = (uint32_t)0x01; } else { HSEStatus = (uint32_t)0x00; } if (HSEStatus == (uint32_t)0x01) { /* Enable Prefetch Buffer */ FLASH-》ACR |= FLASH_ACR_PRFTBE; /关于flash的设置,要参考STM32参考手册下的STM32FLASHxxxxx里面的STM32F10xxx闪存编程参考手册/ /* Flash 2 wait state */ FLASH-》ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); FLASH-》ACR |= (uint32_t)FLASH_ACR_LATENCY_2; /* HCLK = SYSCLK *//根据判断这两个值是否相等来知道这边分频的系数(倍率),查看手册中关于寄存器CFGR/ RCC-》CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; /* PCLK2 = HCLK */ RCC-》CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; /* PCLK1 = HCLK /2*/ /这边是二分频/ 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 */ /系统时钟切换成PLL的来源/ 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 |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9); #endif /* STM32F10X_CL */ /* Enable PLL */ /第24位,看手册/ 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 */ } } #endif 为什么我们的main函数中并没有关于时钟相关的初始化,但是确能实现对时钟的初始化呢?选择工程中的CORE文件夹下的startup_stm32f10x_hd.s的文件,我们可以找到: Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main IMPORT SystemInit LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP 这个应该是汇编语句吧,看不懂(官方视频也说看不懂)。但是应该是实现的先执行SystemInit函数,然后在执行main函数,这就证明了为什么main函数里面不需要对时钟的初始化。 |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1627 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1550 浏览 1 评论
984 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
688 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1601 浏览 2 评论
1867浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
650浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
518浏览 3评论
536浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
506浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-24 22:24 , Processed in 0.905048 second(s), Total 77, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号