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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM