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

原文地址:https://www.cnblogs.com/wuguangzong/p/10887547.html