衆所周知,時鐘系統是 CPU 的脈搏,就像人的心跳同樣。因此時鐘系統的重要性就不言而喻了。 STM32 的時鐘系統比較複雜,不像簡單的 51 單片機一個系統時鐘就能夠解決一切。因而有人要問,採用一個系統時鐘不是很簡單嗎?爲何 STM32 要有多個時鐘源呢? 由於首先STM32 自己很是複雜,外設很是的多,可是並非全部外設都須要系統時鐘這麼高的頻率,好比看門狗以及 RTC 只須要幾十 k 的時鐘便可。同一個電路,時鐘越快功耗越大,同時抗電磁干擾能力也會越弱,因此對於較爲複雜的 MCU 通常都是採起多時鐘源的方法來解決這些問題。首先讓咱們來看看 STM32 的時鐘系統圖吧:html
在 STM32 中,有五個時鐘源,爲 HSI、HSE、LSI、LSE、PLL。從時鐘頻率來分能夠分爲高速時鐘源和低速時鐘源,在這 5 箇中 HIS,HSE 以及 PLL 是高速時鐘,LSI 和 LSE 是低速時鐘。歷來源可分爲外部時鐘源和內部時鐘源,外部時鐘源就是從外部經過接晶振的方式獲取時鐘源,其中 HSE 和 LSE 是外部時鐘源,其餘的是內部時鐘源。下面咱們看看 STM32 的 5 個時鐘源,咱們講解順序是按圖中紅圈標示的順序:
①、HSI 是高速內部時鐘,RC 振盪器,頻率爲 8MHz。
②、HSE 是高速外部時鐘,可接石英 / 陶瓷諧振器,或者接外部時鐘源,頻率範圍爲4MHz~16MHz。
③、LSI 是低速內部時鐘,RC 振盪器,頻率爲 40kHz。獨立看門狗的時鐘源只能是 LSI,同時 LSI 還能夠做爲 RTC 的時鐘源。
④、LSE 是低速外部時鐘,接頻率爲 32.768kHz 的石英晶體。這個主要是 RTC 的時鐘源。
⑤、PLL 爲鎖相環倍頻輸出,其時鐘輸入源可選擇爲 HSI/二、HSE 或者 HSE/2。倍頻可選擇爲2~16 倍,可是其輸出頻率最大不得超過 72MHz。
那麼這 5 個時鐘源是怎麼給各個外設以及系統提供時鐘的呢?這裏咱們將一一講解。咱們仍是從圖的下方講解起吧,由於下方比較簡單。圖中咱們用 A ~E 標示咱們要講解的地方。
A. MCO 是 STM32 的一個時鐘輸出 IO(PA8),它能夠選擇一個時鐘信號輸出,能夠選擇爲 PLL 輸出的 2 分頻、HSI、HSE、或者系統時鐘。這個時鐘能夠用來給外部其餘系統提供時鐘源。
B. 這裏是 RTC 時鐘源,從圖上能夠看出,RTC 的時鐘源能夠選擇 LSI,LSE,以及HSE 的 128 分頻。
C. 從圖中能夠看出 C 處 USB 的時鐘是來自 PLL 時鐘源。 STM32 中有一個全速功能的 USB 模塊,其串行接口引擎須要一個頻率爲 48MHz 的時鐘源。該時鐘源只能從 PLL 輸出端獲取,能夠選擇爲 1.5 分頻或者 1 分頻,也就是,當須要使用 USB模塊時,PLL 必須使能,而且時鐘頻率配置爲 48MHz 或 72MHz。
D. D 處就是 STM32 的系統時鐘 SYSCLK,它是供 STM32 中絕大部分部件工做的時鐘源。 系統時鐘可選擇爲 PLL 輸出、 HSI 或者 HSE。系統時鐘最大頻率爲 72MHz,固然你也能夠超頻,不過通常狀況爲了系統穩定性是沒有必要冒風險去超頻的。
E. 這裏的 E 處是指其餘全部外設了。從時鐘圖上能夠看出,其餘全部外設的時鐘最終來源都是 SYSCLK。SYSCLK 經過 AHB 分頻器分頻後送給各模塊使用。這些模塊包括:
①、AHB 總線、內核、內存和 DMA 使用的 HCLK 時鐘。
②、經過 8 分頻後送給 Cortex 的系統定時器時鐘,也就是 systick 了。
③、直接送給 Cortex 的空閒運行時鐘 FCLK。
④、送給 APB1 分頻器。APB1 分頻器輸出一路供 APB1 外設使用(PCLK1,最大頻率 36MHz),另外一路送給定時器(Timer)二、三、4 倍頻器使用。
⑤、送給 APB2 分頻器。APB2 分頻器分頻輸出一路供 APB2 外設使用(PCLK2,最大頻率 72MHz),另外一路送給定時器(Timer)1 倍頻器使用。
其中須要理解的是 APB1 和 APB2 的區別,APB1 上面鏈接的是低速外設,包括電源接口、備份接口、CAN、USB、I2C一、I2C二、UART二、UART3 等等,APB2 上面鏈接的是高速外設包括 UART一、SPI一、Timer一、ADC一、ADC二、全部普通 IO 口(PA~PE)、第二功能 IO 口等。
STM32 時鐘系統的配置除了初始化的時候在 system_stm32f10x.c 中的 SystemInit()函數中外,其餘的配置主要在 stm32f10x_rcc.c 文件中,裏面有不少時鐘設置函數,能夠打開這個文件瀏覽一下,基本上看看函數的名稱就知道這個函數的做用。在設置時鐘的時候,必定要仔細參考 STM32 的時鐘圖,作到心中有數。這裏須要指明一下,對於系統時鐘,默認狀況下是在 SystemInit 函數的 SetSysClock()函數中間判斷的,而設置是經過宏定義設置的。咱們能夠看看 SetSysClock()函數體:
點擊(此處)摺疊或打開
tatic void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
SetSysClockTo56();
#elif defined SYSCLK_FREQ_72MHz
SetSysClockTo72();
#endif
}
這段代碼很是簡單,就是判斷系統宏定義的時鐘是多少,而後設置相應值。咱們系統默認宏定義是 72MHz:
#define SYSCLK_FREQ_72MHz 72000000
若是你要設置爲 36MHz,只須要註釋掉上面代碼,而後加入下面代碼便可:
#define SYSCLK_FREQ_36MHz 36000000
同時還要注意的是,當咱們設置好系統時鐘後,能夠經過變量 SystemCoreClock 獲取系統時鐘值,若是系統是 72M 時鐘,那麼 SystemCoreClock=72000000。這是在
點擊(此處)摺疊或打開
system_stm32f10x.c 文件中設置的:
#ifdef SYSCLK_FREQ_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_HSE;
#elif defined SYSCLK_FREQ_36MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_36MHz;
#elif defined SYSCLK_FREQ_48MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz;
#elif defined SYSCLK_FREQ_56MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz;
#elif defined SYSCLK_FREQ_72MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz;
#else
uint32_t SystemCoreClock = HSI_VALUE;
#endifweb
系統時鐘系統初始化重要函數:SystemInit(); 使用V3.5版本的庫函數,該函數在系統啓動以後會自動調用:svg
初始化以前首先經過宏定義定義系統時鐘頻率:
#define SYSCLK_FREQ_72MHz 72000000
初始化以後的狀態:函數
SYSCLK(系統時鐘) =72MHz
AHB 總線時鐘(使用 SYSCLK) =72MHz
APB1 總線時鐘(PCLK1) =36MHz
APB2 總線時鐘(PCLK2) =72MHz
PLL 時鐘 =72MHzui
初始化以後能夠經過變量SystemCoreClock獲取系統變量。若是 SYSCLK=72MHz,那麼變量SystemCoreClock=72000000。.net
RCC配置相關頭文件和固件庫源文件
一、時鐘使能配置:
RCC_LSEConfig() 、RCC_HSEConfig()、
RCC_HSICmd() 、 RCC_LSICmd() 、 RCC_PLLCmd() ……unix
二、時鐘源相關配置:
RCC_PLLConfig ()、 RCC_SYSCLKConfig() 、 RCC_RTCCLKConfig() …xml
三、分頻係數選擇配置:
RCC_HCLKConfig() 、 RCC_PCLK1Config() 、 RCC_PCLK2Config()…htm
四、外設時鐘使能:
RCC_APB1PeriphClockCmd(): //APB1線上外設時鐘使能
RCC_APB2PeriphClockCmd(); //APB2線上外設時鐘使能
RCC_AHBPeriphClockCmd(); //AHB線上外設時鐘使能blog
- 其餘外設時鐘配置:
RCC_ADCCLKConfig (); RCC_RTCCLKConfig();
六、狀態參數獲取參數:
RCC_GetClocksFreq();
RCC_GetSYSCLKSource();
RCC_GetFlagStatus()
- RCC中斷相關函數 :
RCC_ITConfig() 、 RCC_GetITStatus() 、 RCC_ClearITPendingBit()…
轉自:http://blog.chinaunix.net/uid-24219701-id-4081961.html
本文同步分享在 博客「HeartRain_大西瓜」(CSDN)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。