以前使用STM32寫程序的時候,使用的都是默認時鐘。因此寫數碼管顯示、A/D測量電壓的時候都沒有去關心RCC時鐘配置這個事情。那時候只知道在配置外設的時候使用GPIO_InitTypeDef或者ADC_InitTypeDef這些結構體對外設進行初始化,以及使用RCC_APB2PeriphClockCmd或者RCC_ADCCLKConfig函數對外設的時鐘開啓與配置。
這幾天嘗試使用STM32的USB通信寫一個鼠標,發現一些例程中有關於時鐘配置的代碼,才注意起這個事情。爲此進行了一些學習,並且記錄如下的筆記。
一、RCC的結構
以下是STM32時鐘系統的結構圖:
從圖中,我們可以看到,STM32的時鐘有四個來源:外部晶振提供的高速外部時鐘(HSE)、外部晶振提供的低速外部時鐘(LSE)、內部RC振盪器提供的高速內部時鐘(HSI)、內部RC振盪器提供的低速內部時鐘(LSI)。看上去RCC的工作過程好像很複雜,其實細看並不然。
舉個例子吧,Keil編寫程序是默認的時鐘爲72Mhz,其實是這麼來的:外部晶振提供的8MHz(與電路板上的晶振的相關)通過PLLXTPRE分頻器後,進入PLLSRC選擇開關,進而通過PLLMUL鎖相環進行倍頻(x9)後,爲系統提供72MHz的系統時鐘(SYSCLK)。之後是AHB預分頻器對時鐘信號進行分頻,然後爲低速外設提供時鐘。
當然,在實際應用中,我們也可以爲系統時鐘作其他的設置。譬如把內部高速RC振盪器(HSI RC)二分頻後,通過PLLSRC選擇開關進行倍頻而不使用外部晶振作爲輸入,HSI也可以直接通過SW選擇開關來提供系統時鐘。
此外,STM32還提供了一個時鐘監視系統(CSS),用於監視高速外部時鐘(HSE)的工作狀態。倘若HSE失效,會自動切換(高速內部時鐘)HSI作爲系統時鐘的輸入。
二、RCC配置流程
1、將RCC寄存器恢復爲默認值 RCC_DeInit
2、打開外部高速時鐘晶振 RCC_HSEConfig
3、等待外部高速時鐘晶振工作
4、設置AHB時鐘 RCC_HCLKConfig
5、設置高速APB時鐘 RCC_PCLK2Config
6、設置低速APB時鐘 RCC_PCLK1Config
7、設置PLL鎖相環 RCC_PLLConfig
8、打開PLL鎖相環 RCC_PLLCmd
9、等待PLL鎖相環工作 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET)
10、設置系統時鐘 RCC_SYSCLKConfig
11、判斷PLL是否爲系統時鐘 while(RCC_GetSYSCLKSource()!=0x08)
12、打開要使用的外設時鐘 RCC_APB2PeriphClockCmd/RCC_APB1PeriphClockCmd
以上步驟只是舉個例子。根據RCC的工作過程,查閱參考手冊與庫函數的手使用冊可以自己進行的配置。
使用代碼再舉一個例子吧
- void RCC_Configuration(void)
- {
- //----------使用外部RC晶振-----------
- RCC_DeInit(); //初始化爲缺省值
- RCC_HSEConfig(RCC_HSE_ON); //使能外部的高速時鐘
- while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); //等待外部高速時鐘使能就緒
- FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //Enable Prefetch Buffer
- FLASH_SetLatency(FLASH_Latency_2); //Flash 2 wait state
- RCC_HCLKConfig(RCC_SYSCLK_Div1); //HCLK = SYSCLK
- RCC_PCLK2Config(RCC_HCLK_Div1); //PCLK2 = HCLK
- RCC_PCLK1Config(RCC_HCLK_Div2); //PCLK1 = HCLK/2
- RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9); //PLLCLK = 8MHZ * 9 =72MHZ
- RCC_PLLCmd(ENABLE); //Enable PLLCLK
- while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); //Wait till PLLCLK is ready
- RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //Select PLL as system clock
- while(RCC_GetSYSCLKSource()!=0x08); //Wait till PLL is used as system clock source
- //---------打開相應外設時鐘--------------------
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); //使能APB2外設的GPIOA的時鐘
- }