stm32f10x 标准外设固件库时钟配置函数分析

来源:互联网 发布:c语言在线编程 编辑:程序博客网 时间:2024/04/29 01:41

为了使stm32f10x的初学者在学习STM32的时候不必去考虑STM32f10x复杂的时钟系统,官方提供了时钟配置的函数并在调用main函数之前调用,这在启动文件中可以看到,以STM32F103VC为例(以后芯片均已此款芯片为例),对应的启动文件为startup_stm32f10x_hd.s

; Reset handlerReset_Handler   PROC                EXPORT  Reset_Handler             [WEAK]                IMPORT  __main                IMPORT  SystemInit                LDR     R0, =SystemInit                BLX     R0                               LDR     R0, =__main                BX      R0                ENDP

下面来看看 SystemInit 函数中到底做了哪些事

void SystemInit (void){  RCC->CR |= (uint32_t)0x00000001;//开启内部8MHz振荡器#ifndef STM32F10X_CL//非STM32F10x互联型  RCC->CFGR &= (uint32_t)0xF8FF0000;//HSI作为系统时钟 AHB预分频器不分频 APB1不分频 APB2不分频 PCLK 2分频后作为ADC时钟 MCO无时钟输出#else//STM32F10x互联型  RCC->CFGR &= (uint32_t)0xF0FF0000;//HSI作为系统时钟 AHB预分频器不分频 APB1不分频 APB2不分频 PCLK 2分频后作为ADC时钟 MCO无时钟输出#endif /* STM32F10X_CL */     RCC->CR &= (uint32_t)0xFEF6FFFF;//HSE 振荡器关闭 时钟监测器关闭  PLL关闭  RCC->CR &= (uint32_t)0xFFFBFFFF;//外部4-16Mhz 振荡器没有旁路  RCC->CFGR &= (uint32_t)0xFF80FFFF;//HSI振荡器时钟经2分频后作为PLL输入时钟 HSE不分频 PLL 2倍频输出  PLL 时钟1.5分频作为USB时钟#ifdef STM32F10X_CL//STM32F10x互联型  RCC->CR &= (uint32_t)0xEBFFFFFF;//PLL2 关闭 PLL3 关闭  RCC->CIR = 0x00FF0000;//关闭所有中断并清除所有中断标志位  RCC->CFGR2 = 0x00000000;//复位CFGR2寄存器#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL) //STM32F10X 超值产品线  RCC->CIR = 0x009F0000;//关闭所有中断并清除所有中断标志位  RCC->CFGR2 = 0x00000000;//复位CFGR2寄存器#else  RCC->CIR = 0x009F0000;//关闭所有中断并清除所有中断标志位#endif /* STM32F10X_CL */    #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)//这段代码用于STM3210E-EVAL 板使用外部SRAM  #ifdef DATA_IN_ExtSRAM    SystemInit_ExtMemCtl();   #endif /* DATA_IN_ExtSRAM */#endif   SetSysClock();//配置系统时钟 HCLK PCLK1 PCLK2 预分频器 FLASH 延时周期和预取缓冲器#ifdef VECT_TAB_SRAM  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET;//内部SRAM向量表迁移#else  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; //内部FLASH向量表迁移#endif }

下面看看 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}

根据不同的宏定义来调用不同的函数 如果上述的宏定义都没有定义 则HSI作为系统时钟(复位后的默认情况)

我这里以SetSysClockTo72 函数为例分析

static void SetSysClockTo72(void){  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;       RCC->CR |= ((uint32_t)RCC_CR_HSEON);//开启HSE振荡器   /* 等待HSE就绪如果超时则退出 */  do  {    HSEStatus = RCC->CR & RCC_CR_HSERDY;//获取HSE就绪标志位    StartUpCounter++;    } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));  if ((RCC->CR & RCC_CR_HSERDY) != RESET)//如果HSE就绪  {    HSEStatus = (uint32_t)0x01;  }  else  {    HSEStatus = (uint32_t)0x00;  }    if (HSEStatus == (uint32_t)0x01)//如果HSE就绪  {    FLASH->ACR |= FLASH_ACR_PRFTBE;//使能 FLASH 预取缓冲区    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    //FLASH 2 等待状态(48 MHz < SYSCLK ≤ 72 MHz )    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;//HCLK = SYSCLK    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;//PCLK2 = HCLK     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;//PCLK1 = HCLK/2  #ifdef STM32F10X_CL    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);// PLL2CLK = (HSE / 5) * 8 = (25M / 5) * 8 = 40 MHz   PREDIV1CLK = PLL2 / 5 = 8 MHz     RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);    RCC->CR |= RCC_CR_PLL2ON;//使能PLL2    while((RCC->CR & RCC_CR_PLL2RDY) == 0)//等待 PLL2 就绪    {    }    /* PLL 配置: 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 配置: 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 */    RCC->CR |= RCC_CR_PLLON;//使能PLL    while((RCC->CR & RCC_CR_PLLRDY) == 0)//等待PLL就绪    {    }        RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;//选择PLL作为系统时钟    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)//等待PLL作为系统时钟就绪    {    }  }  else  { //如果 HSE 启动失败,系统得到错误的时钟,用户添加代码解决这个错误   }}
至此,系统时钟配置完成,在使用STM外设打开相应的时钟开关就可以操作对应外设。



0 0
原创粉丝点击