STM32學習筆記(二)——STM32 時鐘系統

衆所周知,時鐘系統是 CPU 的脈搏,就像人的心跳一樣。所以時鐘系統的重要性就不言而喻了。
首先讓我們來看看 STM32 的時鐘系統圖吧:

在這裏插入圖片描述

在 STM32 中有五個時鐘源,爲 HSI、HSE、LSI、LSE、PLL。從時鐘頻率來分可以分爲高速時鐘源和低速時鐘源,在這 5 箇中 HIS,HSE 以及 PLL 是高速時鐘,LSI 和 LSE 是低速時鐘。從來源可分爲外部時鐘源和內部時鐘源,外部時鐘源就是從外部通過接晶振的方式獲取時鐘源,其中 HSE 和 LSE 是外部時鐘源,其他的是內部時鐘源。

、HSI 是高速內部時鐘,RC 振盪器,頻率爲 8MHz。
、HSE 是高速外部時鐘,可接石英/陶瓷諧振器,或者接外部時鐘源,頻率範圍爲4MHz~16MHz。我們的開發板接的是 8M 的晶振。
、LSI 是低速內部時鐘,RC 振盪器,頻率爲 40kHz。獨立看門狗的時鐘源只能是 LSI,同時 LSI 還可以作爲 RTC 的時鐘源。
、LSE 是低速外部時鐘,接頻率爲 32.768kHz 的石英晶體。這個主要是 RTC 的時鐘源。
、PLL 爲鎖相環倍頻輸出,其時鐘輸入源可選擇爲HSI/2、HSE 或者 HSE/2。倍頻可選擇爲2~16 倍,但是其輸出頻率最大不得超過 72MHz。

這 5 個時鐘源是給各個外設以及系統提供時鐘的方法:
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)2、3、4 倍頻器使用。
⑤、送給 APB2 分頻器。APB2 分頻器分頻輸出一路供 APB2 外設使用(PCLK2,最大頻率 72MHz),另一路送給定時器(Timer)1 倍頻器使用。

注意 APB1 和 APB2 的區別,APB1 上面連接的是低速外設,包括電源接口、備份接口、CAN、USB、I2C1、I2C2、UART2、UART3 等等,APB2 上面連接的是高速外設包括 UART1、SPI1、Timer1、ADC1、ADC2、所有普通 IO 口(PA~PE)、第二功能 IO 口等。 APB2 下面所掛的外設的時鐘要比 APB1 的高。
在以上的時鐘輸出中,有很多是帶使能控制的,例如 AHB 總線時鐘、內核時鐘、各種 APB1外設、APB2 外設等等。當需要使用某模塊時,記得一定要先使能對應的時鐘。

STM32 時鐘系統的配置除了初始化的時候在system_stm32f10x.c 中的 SystemInit()函數中外,其他的配置主要在 stm32f10x_rcc.c 文件中。在設置時鐘的時候,一定要仔細參考 STM32 的時鐘圖。這裏需要指明一下,對於系統時鐘,默認情況下是在 SystemInit 函數的 SetSysClock()函數中間判斷的,而設置是通過宏定義設置的。我們可以看看 SetSysClock()函數體:

static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSESetSysClockToHSE();
#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; 
#endif

總結一下 SystemInit()函數中設置的系統時鐘大小:
SYSCLK(系統時鐘) =72MHz
AHB 總線時鐘(使用 SYSCLK) =72MHz
APB1 總線時鐘(PCLK1) =36MHz
APB2 總線時鐘(PCLK2) =72MHz
PLL 時鐘 =72MHz

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章