RCC—使用HSE配置系統時鐘
晶片提供時鐘就要有時鐘樹
時鐘樹在參考手冊RCC章節開頭就有(這裡的時鐘樹看到感覺眼睛打了馬賽克,小弟截圖技術有限)

什麼是晶振?
晶振:晶體振蕩器,用于各種電路中産生振蕩頻率,每個單片機裡都會有晶振,給單片機提供時鐘頻率,振蕩得越快,時鐘頻率就越高,單片機運作的速度就越快
解析時鐘樹的方法:(系統時鐘)
- 時鐘是由晶振提供的,首先要找到時鐘的入口點。圖中OSC_IN 和 OSC_OUT,這兩個是外部晶振的引腳,是以時鐘是從這裡進入的。接有源晶振時,時鐘從OSC_IN進入,OSC_OUT懸空。接無源晶振時,時鐘從OSC_IN 和 OSC_OUT一起進入
- 時鐘進入以後會經過PLL鎖相環,進入前會經過一個M分頻,進入PLL鎖相環之後就會進入N倍頻,輸出時經過一個P分頻,輸出的時鐘為PLLCLK
- 可以選擇PLLCLK、HSE、HIS作為系統時鐘
-
然後經過AHB總線的分頻因子,成為HCLK作為AHB總線的時鐘,或者再經過APB的分頻因子作為APB1、APB2總線的時鐘(根據參考手冊AHB總線頻率最大為180MHZ 、高速APB2總線頻率最大為90MHZ 低速APB1總線頻率最大為45MHZ)
上述分析的是時鐘樹的系統時鐘,還有其他時鐘RTC實時時鐘、看門狗時鐘、I2S時鐘、以太網時鐘、MCO輸出時鐘,這些等需要用到的時鐘看吧
下面用固件庫編寫使用HSE配置系統時鐘函數
(HSI也是同樣的思路)
- 啟動HSE,在頭檔案尋找HSE啟動的函數void RCC_HSEConfig(uint8_t RCC_HSE)
-
等待HSE穩定ErrorStatus RCC_WaitForHSEStartUp(void)
這個函數是如何實作的:在這個函數中還調用了函數
FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)
那先講解這個函數是如何實作的:這個函數的功能是檢查是否設定了指定的RCC标志。RCC的标志(RCC_FLAG)都會有自己的值,首先檢查參數,然後得到RCC寄存器的位号(根據RCC的标志确定在RCC的哪個寄存器裡),最後獲得RCC寄存器的位置判斷是否設定了指定的參數,然後傳回值,如果設定了傳回1,否傳回0
判斷HSE是否準備好,如果是傳回1,否傳回0
-
設定HCLK、APB1、APB2預分頻因子
void RCC_HCLKConfig(uint32_t RCC_SYSCLK)
void RCC_PCLK1Config(uint32_t RCC_HCLK)
void RCC_PCLK2Config(uint32_t RCC_HCLK)
- 設定進入PLL鎖相環的M分頻因子 PLL鎖相環的N倍頻因子 出PLL鎖相環的P分頻因子 void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t PLLM, uint32_t PLLN, uint32_t PLLP, uint32_t PLLQ)控制系統時鐘的頻率就在于這幾個分頻因子
-
啟動PLL void RCC_PLLCmd(FunctionalState NewState)
等待PLL穩定 使用了FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)把RCC_FLAG設為RCC_FLAG_PLLRDY,若準備好傳回1
- 設定PLLCLK為系統時鐘void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource)
-
讀取狀态位確定PLLCLK被選中為系統時鐘
uint8_t RCC_GetSYSCLKSource(void)//該函數功能:傳回時鐘源用作系統時鐘
若傳回數值為PLLCLK數值,則PLLCLK被選為系統時鐘
代碼如下
函數的形參根據函數中需要傳入的資料所設定
void HSE_SetSysclk ( uint32_t PLLM, uint32_t PLLN, uint32_t PLLP, uint32_t PLLQ)
{
RCC_HSEConfig(RCC_HSE_ON);
if(RCC_WaitForHSEStartUp()==SUCCESS)
{
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div4);
RCC_PCLK2Config(RCC_HCLK_Div2);
RCC_PLLConfig(RCC_PLLSource_HSE,PLLM, PLLN, PLLP, PLLQ);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY)==RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(RCC_GetSYSCLKSource()!=0x08);
}
else
{
while(1)
{
}
}
}