zoukankan      html  css  js  c++  java
  • STM32(四)- 时钟树、时钟配置

    reset clock control 复位和时钟控制器

    一、stm32时钟树

     stm32时钟树:由时钟源到外设的结构框图。

    基本时钟源(图中绿色箭头指出):

    (1)HSI高速内部时钟,RC振荡器,8MHz。

    (2)HSE高速外部时钟,石英/陶瓷谐振器,8MHz。

    (3)LSI低速内部时钟,RC振荡器,40kHz。

    (4)LSE低速外部时钟,RTC石英晶振,32.768kHz。

    注:内部指的是片上外设,外部指的是芯片外部。

    (5)除了上述基本时钟源,还有num3中的PLL锁相环倍频时钟源,它是将HSI和HSE倍频后输出。

     二、PLLCLK  -  PLL时钟(num4)

    时钟来源:(1)HSI/2        (2)HSE

     三、SYSCLK  -  系统时钟(num5)

     时钟来源:(1)HSI          (2)PLLCLK      (3)HSE

    SYSCLK经过分频后,得到AHB总线时钟HCLK;

    HCLK再分频得到APB1总线时钟PCLK1和APB2总线时钟PCLK2;

    PCLK2分频后得到ADCCLK最大14MHz。

     四、RTCCLK(灰色框中)

    时钟来源:(1)HSE/128   (2)LSE             (3)LSI

     五、系统时钟配置

     系统时钟有三个来源,PLLCLK、HSE、HSI。

    正常情况下,时钟配置是在system_stm32f10x.c中完成,这里的的时钟配置是直接控制寄存器完成的。

    在 stm32f10x_rcc.c中定义了关于时钟配置的库函数,此时未用。

    打开system_stm32f10x.c,找到void SystemInit (void),再找到 SetSysClock()并查看定义,

    定义中可知是通过在system_stm32f10x.c中宏定义SYSCLK_FREQ_72MHz选择系统时钟配置函数SetSysClockTo72(),

    即72MHz的系统时钟就是在此函数中配置的,函数如下:(HSE(不分频)->PLLCLK(9倍频)->72MHz系统时钟)

     1 static void SetSysClockTo72(void)
     2 {
     3   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
     4   
     5   /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
     6   /* 使能 HSE */    
     7   RCC->CR |= ((uint32_t)RCC_CR_HSEON);
     8  
     9   /* 等待HSE就绪并做超时处理 */
    10   do
    11   {
    12     HSEStatus = RCC->CR & RCC_CR_HSERDY;
    13     StartUpCounter++;  
    14   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
    15 
    16   if ((RCC->CR & RCC_CR_HSERDY) != RESET)
    17   {
    18     HSEStatus = (uint32_t)0x01;
    19   }
    20   else
    21   {
    22     HSEStatus = (uint32_t)0x00;
    23   }  
    24 
    25   // 如果HSE启动成功,程序则继续往下执行
    26   if (HSEStatus == (uint32_t)0x01)
    27   {
    28     /* 使能预取指 */
    29     FLASH->ACR |= FLASH_ACR_PRFTBE;
    30 
    31     /* Flash 2 wait state */
    32     FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
    33     FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    
    34 
    35  
    36     /* HCLK = SYSCLK = 72M */
    37     RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
    38       
    39     /* PCLK2 = HCLK = 72M */
    40     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
    41     
    42     /* PCLK1 = HCLK = 36M*/
    43     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
    44     
    45     /*  锁相环配置: PLLCLK = HSE * 9 = 72 MHz */
    46     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
    47                                         RCC_CFGR_PLLMULL));
    48     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
    49 
    50     /* 使能 PLL */
    51     RCC->CR |= RCC_CR_PLLON;
    52 
    53     /* 等待PLL稳定 */
    54     while((RCC->CR & RCC_CR_PLLRDY) == 0)
    55     {
    56     }    
    57     /* 选择PLLCLK作为系统时钟*/
    58     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    59     RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    
    60 
    61     /* 等待PLLCLK切换为系统时钟 */
    62     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
    63     {
    64     }
    65   }
    66   else
    67   { /* 如果HSE 启动失败,用户可以在这里添加处理错误的代码 */
    68   }
    69 }

     这里再以库函数形式中重新配置系统时钟和MCO:

    user中新建RCC文件夹,新建bsp_rccclkconfig.c和bsp_rccclkconfig.h文件,同时对main函数做补充。(GPIO&KEY例程继续写的)

     bsp_rccclkconfig.h

    1 #ifndef __BSP_RCCCLKCONFIG_H
    2 #define __BSP_RCCCLKCONFIG_H
    3 
    4 #include "stm32f10x.h"
    5 
    6 void HSE_SetSysClk( uint32_t RCC_PLLMul_x );
    7 void MCO_GPIO_Config();
    8 void HSI_SetSysClk( uint32_t RCC_PLLMul_x );
    9 #endif /*__BSP_RCCCLKCONFIG_H */

    bsp_rccclkconfig.c

     1 #include "bsp_rccclkconfig.h"
     2 
     3 void HSE_SetSysClk( uint32_t RCC_PLLMul_x )
     4 {
     5     ErrorStatus HSEStatus;
     6     
     7     //把RCC寄存器复位成复位值
     8     RCC_DeInit();    
     9 
    10     // 使能 HSE 
    11     RCC_HSEConfig(RCC_HSE_ON);
    12     
    13     HSEStatus = RCC_WaitForHSEStartUp();
    14     
    15     if( HSEStatus == SUCCESS )
    16     {
    17         // 使能预取址
    18         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    19         FLASH_SetLatency(FLASH_Latency_2);
    20         
    21         RCC_HCLKConfig(RCC_SYSCLK_Div1);
    22         RCC_PCLK1Config(RCC_HCLK_Div2);
    23         RCC_PCLK2Config(RCC_HCLK_Div1);
    24         
    25         // 配置 PLLCLK = HSE * RCC_PLLMul_x
    26     RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_x);
    27         
    28     // 使能PLL
    29         RCC_PLLCmd(ENABLE);
    30         
    31         // 等待PLL稳定
    32         while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );
    33         
    34     // 选择系统时钟
    35         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    36         
    37     while( RCC_GetSYSCLKSource() != 0x08 );
    38     }
    39     else
    40   {
    41         /* 如果HSE启动失败,用户可以在这里添加错误的处理代码 */
    42     }
    43 }
    44 
    45 void HSI_SetSysClk( uint32_t RCC_PLLMul_x )
    46 {
    47     __IO uint32_t HSIStatus = 0;
    48     
    49     // 把RCC寄存器复位成复位值
    50     RCC_DeInit();    
    51 
    52     // 使能 HSI 
    53     RCC_HSICmd(ENABLE);
    54     
    55     HSIStatus = RCC->CR & RCC_CR_HSIRDY;
    56     
    57     if( HSIStatus == RCC_CR_HSIRDY )
    58     {
    59         // 使能预取址
    60         FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    61         FLASH_SetLatency(FLASH_Latency_2);
    62         
    63         RCC_HCLKConfig(RCC_SYSCLK_Div1);
    64         RCC_PCLK1Config(RCC_HCLK_Div2);
    65         RCC_PCLK2Config(RCC_HCLK_Div1);
    66         
    67         // 配置 PLLCLK = HSI * RCC_PLLMul_x
    68     RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_x);
    69         
    70     // 使能PLL
    71         RCC_PLLCmd(ENABLE);
    72         
    73         // 等待PLL稳定
    74         while( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET );
    75         
    76     // 选择系统时钟
    77         RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    78         
    79     while( RCC_GetSYSCLKSource() != 0x08 );
    80     }
    81     else
    82   {
    83         /* 如果HSI启动失败,用户可以在这里添加处理错误的代码 */
    84     }
    85 }
    86 
    87 void MCO_GPIO_Config()//MCO时钟输出GPIO配置,PA8
    88 {
    89     GPIO_InitTypeDef  GPIO_InitStruct;
    90     
    91     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    92     
    93     GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
    94     GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
    95     GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    96     
    97     GPIO_Init(GPIOA, &GPIO_InitStruct);    
    98 }

    main.c

     1 #include "stm32f10x.h"   //
     2 #include "bsp_key.h"
     3 #include "bsp_led.h"
     4 #include "bsp_rccclkconfig.h"
     5 void Delay( uint32_t count )   //软件延时函数,但是实际时间间隔取决于系统时钟
     6 {
     7     for(; count!=0; count--);
     8 }
     9 
    10 int main(void)
    11 {
    12     // 来到这里的时候,系统时钟已经被配置成72M
    13     LED_GPIO_Config();
    14     KEY_GPIO_Config();
    15     //这里重新配置时钟,如果注释掉下面两条HSE和HSI语句,将使用默认的system_stm32f10x.c寄存器配置版72M

    16 //HSE=8MHZ,PLL九倍频=72MHZ 17 HSE_SetSysClk( RCC_PLLMul_9 ); 18 //HSI/2=4MHZ,PLL十六倍频=64MHZ 19 //HSI_SetSysClk( RCC_PLLMul_16 ); 20 21 //MCO的GPIO初始化 22 MCO_GPIO_Config(); 23 //选择系统时钟作为MCO输出 24 RCC_MCOConfig(RCC_MCO_SYSCLK); //PA8接示波器可见 25 //RCC_MCOConfig(RCC_MCO_HSI); 26 27 while(1)//更改系统时钟频率,小灯的闪烁间隔出现变化 28 { 29 // 30 //if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) ==KEY_ON ) 31 // LED_G_TOGGLE; 32 33 LED_G(OFF); 34 Delay(0xFFFFF); 35 36 LED_G(ON); 37 Delay(0xFFFFF); 38 } 39 }

    7

  • 相关阅读:
    百度影音盒插入论坛帖子自动播放代码及方法
    vFloppy1.5-虚拟启动软盘
    飞秋的实现原理
    博客盈利请先考虑这七点
    下载站运行广告合作exe文件然后再运行程序文件的bat
    木马病毒是什么以及手工清除木马病毒具体步骤
    网站盈利模式分析分类
    软件更新原理
    浅析php学习的路线图
    网页常用分享代码大全(前端必备)
  • 原文地址:https://www.cnblogs.com/wuguangzong/p/10887547.html
Copyright © 2011-2022 走看看