热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

STM32F系列ARMCortex_M3核微控制器基础之系统时钟三

STM32F系列ARMCortex_M3核微控制器之系统时钟三问题一:若未对系统进行时钟配置,那么系统上电后时钟系统将是怎样配置的?在S

                                                                                  STM32F系列ARM Cortex_M3核微控制器之系统时钟三

问题一:若未对系统进行时钟配置,那么系统上电后时钟系统将是怎样配置的?

        在STM32启动文件startup_stm32f10x_hd.s中有下面一段汇编:

Reset_Handler PROCEXPORT Reset_Handler [WEAK]IMPORT __mainIMPORT SystemInitLDR R0, =SystemInitBLX R0 LDR R0, =__mainBX R0ENDP其中IMPORT __main和IMPORT SystemInit为声明要使用C语言中的main函数和IMPORT SystemInit函数。LDR R0,=SystemInit 把SystemInit函数的地址加载到寄存器R0中。BLX R0 程序跳转到R0中的地址处执行。

我们来看看system_stm32f10x.c文件中的SystemInit()函数对系统时钟的配置情况

/*** @brief Setup the microcontroller system* Initialize the Embedded Flash Interface, the PLL and update the * SystemCoreClock variable. 初始化内部Flash,PLL,更新系统时钟变量* @note This function should be used only after reset. 仅能在复位后使用* @param None* @retval None*/
void SystemInit (void)
{/* Reset the RCC clock configuration to the default reset state(for debug purpose) *///复位RCC时钟配置为默认复位状态(为了调试目的)/* Set HSION bit 置位内部高速时钟使能位*///内部8MHz振荡器开启RCC->CR |= (uint32_t)0x00000001;/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits *///复位系统时钟切换,AHB预分频,低速APB预分频,高速APB预分频,ADC预分频,微控制器时钟输出位//HSI作为系统时钟,SYSCLK不分频作为HCLK,HCLK不分频做为PCLK1,PCLK2,PCLK2 2分频后作为ADC时钟,MCO引脚没有微控制器时钟输出
#ifndef STM32F10X_CLRCC->CFGR &= (uint32_t)0xF8FF0000;
#elseRCC->CFGR &= (uint32_t)0xF0FF0000;
#endif /* STM32F10X_CL */ /* Reset HSEON, CSSON and PLLON bits *///复位外部高速时钟使能,时钟安全系统使能,PLL使能//外部高速时钟关闭,时钟监测器关闭,PLL关闭RCC->CR &= (uint32_t)0xFEF6FFFF;/* Reset HSEBYP bit *///复位外部高速时钟旁路//外部3-25MHz时钟没有旁路RCC->CR &= (uint32_t)0xFFFBFFFF;/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits *///复位PLL输入时钟源,HSE分频作为PLL输入,PLL倍频系数,USB预分频位//HSI振荡器时钟经2分频后作为PLL输入时钟,HSE不分频作为PLL输入时钟,PLL2倍频输出,PLL时钟1.5倍分频作为USB时钟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 *///配置系统时钟频率,HCLK,PCLK2,PCLK1预分频/* Configure the Flash Latency cycles and enable prefetch buffer *///配置Flash延时周期,使能预取缓存SetSysClock();#ifdef VECT_TAB_SRAMSCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
#else//向量表放置于内部FLASHSCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
#endif
}
该函数将RCC时钟先置为复位状态,然后调用SystemInit_ExtMemCtl()(如果定义了DATA_IN_ExtSRAM),调用SetSysClock()以及设置向量表的位置。这里不对SystemInit_ExtMemCtl()进行解释,置解释SetSysClock()函数

/*** @brief Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.配置系统时钟频率,HCLK,PCLK2,PCLK1预分频* @param None* @retval None*/
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSESetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHzSetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHzSetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHzSetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHzSetSysClockTo56();
#elif defined SYSCLK_FREQ_72MHzSetSysClockTo72();
#endif/* If none of the define above is enabled, the HSI is used as System clocksource (default after reset) */  //如果上面的宏定义都没定义,HSI用作系统时钟  }
这里定义了SYSCLK_FREQ_72MHz系统时钟频率

#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
这里使能的函数是SetSysClockTo72();

/*** @brief Sets System clock frequency to 72MHz and configure HCLK, PCLK2 * and PCLK1 prescalers.设置系统时钟为72MHz,配置HCLK,PCLK2,PCLK1预分频* @note This function should be used only after reset.* @param None* @retval None*/
static void SetSysClockTo72(void)
{__IO uint32_t StartUpCounter = 0, HSEStatus = 0;/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*///配置SYSCLK, HCLK, PCLK2 and PCLK1/* Enable HSE */ //使能高速外部振荡器 RCC->CR |= ((uint32_t)RCC_CR_HSEON);/* Wait till HSE is ready and if Time out is reached exit *///等到HSE稳定,时间到则退出循环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时序延迟2周期FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2; /* HCLK = SYSCLK */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 */ 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 *///PLL配置 HSE时钟作为PLL输入时钟 PLL9倍频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 *///使能PLLRCC->CR |= RCC_CR_PLLON;/* Wait till PLL is ready */while((RCC->CR & RCC_CR_PLLRDY) == 0){}/* Select PLL as system clock source *///选择PLL作为系统时钟源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 *///等到PLL作为系统时钟源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 *///如果HSE启动失败,应用会产生错误时钟配置,在这里对错误情况进行处理}
}
这里的配置是:HSE的外部晶振使用8MHz,HSE时钟作为PLL输入时钟,PLL 9倍频,SYSCLK = 72MHz,HCLK = AHB时钟为72MHz,PCLK1 = AHB/2 = 36MHz,PCLK2 = AHB = 72MHz。

初始化之后可以通过变量SystemCoreClock获取系统核心时钟频率(HCLK)。SystemCoreClock变量:包含核心时钟(HCLK),可以用于建立SysTick或配置其他参数

/*******************************************************************************
* Clock Definitions
*******************************************************************************/
#ifdef SYSCLK_FREQ_HSEuint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /*!#elif defined SYSCLK_FREQ_24MHzuint32_t SystemCoreClock = SYSCLK_FREQ_24MHz; /*!#elif defined SYSCLK_FREQ_36MHzuint32_t SystemCoreClock = SYSCLK_FREQ_36MHz; /*!#elif defined SYSCLK_FREQ_48MHzuint32_t SystemCoreClock = SYSCLK_FREQ_48MHz; /*!#elif defined SYSCLK_FREQ_56MHzuint32_t SystemCoreClock = SYSCLK_FREQ_56MHz; /*!#elif defined SYSCLK_FREQ_72MHzuint32_t SystemCoreClock = SYSCLK_FREQ_72MHz; /*!#else /*!#endif


z再看看该文件下的另一个函数SystemCoreClockUpdate(),
由于SystemCoreClock变量中存储的是核心频率HCLK,每次系统时钟改变时,都需要使用该函数对该变量进行更新。

/*** @brief Update SystemCoreClock variable according to Clock Register Values.* The SystemCoreClock variable contains the core clock (HCLK), it can* be used by the user application to setup the SysTick timer or configure* other parameters.* 根据时钟寄存器值来更新SystemCoreClock变量,SystemCoreClock保存的是系统核心时钟(HCLK) * @note Each time the core clock (HCLK) changes, this function must be called* to update SystemCoreClock variable value. Otherwise, any configuration* based on this variable will be incorrect. * 当核心时钟变化时,必须调用该函数来更新SystemCoreClock变量。* @note - The system frequency computed by this function is not the real * frequency in the chip. It is calculated based on the predefined * constant and the selected clock source:* 该函数计算的系统频率是基于预定义的频率和选择的时钟源,不一定是芯片真正的频率 * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)* * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)* * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**) * or HSI_VALUE(*) multiplied by the PLL factors.* * (*) HSI_VALUE is a constant defined in stm32f1xx.h file (default value* 8 MHz) but the real value may vary depending on the variations* in voltage and temperature. * * (**) HSE_VALUE is a constant defined in stm32f1xx.h file (default value* 8 MHz or 25 MHz, depedning on the product used), user has to ensure* that HSE_VALUE is same as the real frequency of the crystal used.* Otherwise, this function may have wrong result.* * - The result of this function could be not correct when using fractional* value for HSE crystal.* @param None* @retval None*/
void SystemCoreClockUpdate (void)
{uint32_t tmp = 0, pllmull = 0, pllsource = 0;#ifdef STM32F10X_CLuint32_t prediv1source = 0, prediv1factor = 0, prediv2factor = 0, pll2mull = 0;
#endif /* STM32F10X_CL */#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)uint32_t prediv1factor = 0;
#endif /* STM32F10X_LD_VL or STM32F10X_MD_VL or STM32F10X_HD_VL *//* Get SYSCLK source -------------------------------------------------------*///得到SYSCLK所选时钟源tmp = RCC->CFGR & RCC_CFGR_SWS;switch (tmp){case 0x00: /* HSI used as system clock */SystemCoreClock = HSI_VALUE;break;case 0x04: /* HSE used as system clock */SystemCoreClock = HSE_VALUE;break;case 0x08: /* PLL used as system clock *//* Get PLL clock source and multiplication factor ----------------------*///得到PLL时钟源和倍频系数pllmull = RCC->CFGR & RCC_CFGR_PLLMULL;pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;#ifndef STM32F10X_CL pllmull = ( pllmull >> 18) + 2;if (pllsource == 0x00){/* HSI oscillator clock divided by 2 selected as PLL clock entry *///HSI 2分频后作为PLL时钟源SystemCoreClock = (HSI_VALUE >> 1) * pllmull;}else{#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1;/* HSE oscillator clock selected as PREDIV1 clock entry */SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull; #else/* HSE selected as PLL clock entry */if ((RCC->CFGR & RCC_CFGR_PLLXTPRE) != (uint32_t)RESET){/* HSE oscillator clock divided by 2 *///HSE时钟2分频SystemCoreClock = (HSE_VALUE >> 1) * pllmull;}else{//HSE不分频SystemCoreClock = HSE_VALUE * pllmull;}#endif}
#elsepllmull = pllmull >> 18;if (pllmull != 0x0D){pllmull += 2;}else{ /* PLL multiplication factor = PLL input clock * 6.5 */pllmull = 13 / 2; }if (pllsource == 0x00){/* HSI oscillator clock divided by 2 selected as PLL clock entry */SystemCoreClock = (HSI_VALUE >> 1) * pllmull;}else{/* PREDIV1 selected as PLL clock entry *//* Get PREDIV1 clock source and division factor */prediv1source = RCC->CFGR2 & RCC_CFGR2_PREDIV1SRC;prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1;if (prediv1source == 0){ /* HSE oscillator clock selected as PREDIV1 clock entry */SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull; }else{/* PLL2 clock selected as PREDIV1 clock entry *//* Get PREDIV2 division factor and PLL2 multiplication factor */prediv2factor = ((RCC->CFGR2 & RCC_CFGR2_PREDIV2) >> 4) + 1;pll2mull = ((RCC->CFGR2 & RCC_CFGR2_PLL2MUL) >> 8 ) + 2; SystemCoreClock = (((HSE_VALUE / prediv2factor) * pll2mull) / prediv1factor) * pllmull; }}
#endif /* STM32F10X_CL */ break;default:SystemCoreClock = HSI_VALUE;break;}/* Compute HCLK clock frequency ----------------*///计算/* Get HCLK prescaler */tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];/* HCLK clock frequency */SystemCoreClock >>= tmp;
}









推荐阅读
  • React项目中运用React技巧解决实际问题的总结
    本文总结了在React项目中如何运用React技巧解决一些实际问题,包括取消请求和页面卸载的关联,利用useEffect和AbortController等技术实现请求的取消。文章中的代码是简化后的例子,但思想是相通的。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
  • node.jsrequire和ES6导入导出的区别原 ... [详细]
  • PHP反射API的功能和用途详解
    本文详细介绍了PHP反射API的功能和用途,包括动态获取信息和调用对象方法的功能,以及自动加载插件、生成文档、扩充PHP语言等用途。通过反射API,可以获取类的元数据,创建类的实例,调用方法,传递参数,动态调用类的静态方法等。PHP反射API是一种内建的OOP技术扩展,通过使用Reflection、ReflectionClass和ReflectionMethod等类,可以帮助我们分析其他类、接口、方法、属性和扩展。 ... [详细]
  • 前段时间做一个项目,需求是对每个视频添加预览图,这个问题最终选择方案是:用canvas.toDataYRL();来做转换获取视频的一个截图,添加到页面中,达到自动添加预览图的目的。 ... [详细]
  • 使用这个技巧要达到的目标:一般来说,模型和控制器你都不会有相同的类名字。让我先创建一个取名为post的model。classPostextendsModel{}现在 ... [详细]
  • 本文介绍了brain的意思、读音、翻译、用法、发音、词组、同反义词等内容,以及脑新东方在线英语词典的相关信息。还包括了brain的词汇搭配、形容词和名词的用法,以及与brain相关的短语和词组。此外,还介绍了与brain相关的医学术语和智囊团等相关内容。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 《2017年3月全国计算机等级考试二级C语言上机题库完全版》由会员分享,可在线阅读,更多相关《2017年3月全国计算机等级考试二级C语言上机题库完全版( ... [详细]
  • C语言自带的快排和二分查找
    Author🚹:CofCaiEmail✉️:cai.dongjunnexuslink.cnQQ😙:1664866311personalPage&#x ... [详细]
  • c语言基础编写,c语言 基础
    本文目录一览:1、C语言如何编写?2、如何编写 ... [详细]
  • 利用空间换时间减少时间复杂度以及以C语言字符串处理为例减少空间复杂度
    在处理字符串的过程当中,通常情况下都会逐个遍历整个字符串数组,在多个字符串的处理中,处理不同,时间复杂度不同,这里通过利用空间换时间等不同方法,以字符串处理为例来讨论几种情况:1: ... [详细]
  • 该楼层疑似违规已被系统折叠隐藏此楼查看此楼*madebyebhrz*#include#include#include#include#include#include#include ... [详细]
  • C语言的经典程序有哪些
    本篇内容介绍了“C语言的经典程序有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何 ... [详细]
author-avatar
歌歌了_618
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有