http://www.elecfans.com/dianzichangshi/20171113578546.html
一、在STM32中,有五個時鐘源,爲HSI、HSE、LSI、LSE、PLL。
①HSI是高速內部時鐘,RC振盪器,頻率爲8MHz。
②HSE是高速外部時鐘,可接石英/陶瓷諧振器,或者接外部時鐘源,頻率範圍爲4MHz~16MHz。
③LSI是低速內部時鐘,RC振盪器,頻率爲40kHz。
④LSE是低速外部時鐘,接頻率爲32.768kHz的石英晶體。
⑤PLL爲鎖相環倍頻輸出,其時鐘輸入源可選擇爲HSI/2、HSE或者HSE/2。倍頻可選擇爲2~16倍,但是其輸出頻率最大不得超過72MHz。
二、在STM32上如果不使用外部晶振,OSC_IN和OSC_OUT的接法:如果使用內部RC振盪器而不使用外部晶振,請按照下面方法處理:
①對於100腳或144腳的產品,OSC_IN應接地,OSC_OUT應懸空。
②對於少於100腳的產品,有2種接法:第1種:OSC_IN和OSC_OUT分別通過10K電阻接地。此方法可提高EMC性能;第2種:分別重映射OSC_IN和OSC_OUT至PD0和PD1,再配置PD0和PD1爲推輓輸出並輸出'0'。此方法可以減小功耗並(相對上面)節省2個外部電阻。
三、用HSE時鐘,程序設置時鐘參數流程:
01、將RCC寄存器重新設置爲默認值 RCC_DeInit;
02、打開外部高速時鐘晶振HSE RCC_HSEConfig(RCC_HSE_ON);
03、等待外部高速時鐘晶振工作 HSEStartUpStatus = RCC_WaitForHSEStartUp();
04、設置AHB時鐘 RCC_HCLKConfig;
05、設置高速AHB時鐘 RCC_PCLK2Config;
06、設置低速速AHB時鐘 RCC_PCLK1Config;
07、設置PLL RCC_PLLConfig;
08、打開PLL RCC_PLLCmd(ENABLE);
09、等待PLL工作 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
10、設置系統時鐘 RCC_SYSCLKConfig;
11、判斷是否PLL是系統時鐘 while(RCC_GetSYSCLKSource() != 0x08)
12、打開要使用的外設時鐘 RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd()
四、下面是STM32軟件固件庫的程序中對RCC的配置函數(使用外部8MHz晶振)
/*******************************************************************************
* Function Name : RCC_Configuration
* Description : RCC配置(使用外部8MHz晶振)
* Input : 無
* Output : 無
* Return : 無
*******************************************************************************/
void RCC_Configuration(void)
{
RCC_DeInit(); /*將外設RCC寄存器重設爲缺省值*/
/*設置外部高速晶振(HSE)*/
RCC_HSEConfig(RCC_HSE_ON); //RCC_HSE_ON——HSE晶振打開(ON)
/*等待HSE起振*/
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS) //SUCCESS:HSE晶振穩定且就緒
{
/*設置AHB時鐘(HCLK)*/
RCC_HCLKConfig(RCC_SYSCLK_Div1); //RCC_SYSCLK_Div1——AHB時鐘= 系統時鐘
/* 設置高速AHB時鐘(PCLK2)*/
RCC_PCLK2Config(RCC_HCLK_Div1); //RCC_HCLK_Div1——APB2時鐘= HCLK
/*設置低速AHB時鐘(PCLK1)*/
RCC_PCLK1Config(RCC_HCLK_Div2); //RCC_HCLK_Div2——APB1時鐘= HCLK / 2
/*設置FLASH存儲器延時時鐘週期數*/
FLASH_SetLatency(FLASH_Latency_2); //FLASH_Latency_2 2延時週期
/*選擇FLASH預取指緩存的模式*/
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); // 預取指緩存使能
/*設置PLL時鐘源及倍頻係數*/
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
// PLL的輸入時鐘= HSE時鐘頻率;RCC_PLLMul_9——PLL輸入時鐘x 9
RCC_PLLCmd(ENABLE); /*使能PLL */
/*檢查指定的RCC標誌位(PLL準備好標誌)設置與否*/
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{}
/*設置系統時鐘(SYSCLK)*/
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
//RCC_SYSCLKSource_PLLCLK——選擇PLL作爲系統時鐘
/* PLL返回用作系統時鐘的時鐘源*/
while(RCC_GetSYSCLKSource() != 0x08) //0x08:PLL作爲系統時鐘
{
}
}
/*使能或者失能APB2外設時鐘*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
RCC_APB2Periph_GPIOC , ENABLE);
//RCC_APB2Periph_GPIOA GPIOA時鐘
//RCC_APB2Periph_GPIOB GPIOB時鐘
//RCC_APB2Periph_GPIOC GPIOC時鐘
//RCC_APB2Periph_GPIOD GPIOD時鐘
}
五、時鐘頻率
STM32F103內部8M的內部震盪,經過倍頻後最高可以達到72M。目前TI的M3系列芯片最高頻率可以達到80M。
在stm32固件庫3.0中對時鐘頻率的選擇進行了大大的簡化,原先的一大堆操作都在後臺進行。系統給出的函數爲SystemInit()。但在調用前還需要進行一些宏定義的設置,具體的設置在system_stm32f10x.c文件中。
文件開頭就有一個這樣的定義:
//#define SYSCLK_FREQ_HSE HSE_Value
//#define SYSCLK_FREQ_20MHz 20000000
//#define SYSCLK_FREQ_36MHz 36000000
//#define SYSCLK_FREQ_48MHz 48000000
//#define SYSCLK_FREQ_56MHz 56000000
#define SYSCLK_FREQ_72MHz 72000000
ST 官方推薦的外接晶振是 8M,所以庫函數的設置都是假定你的硬件已經接了 8M 晶振來運算的.以上東西就是默認晶振 8M 的時候,推薦的 CPU 頻率選擇.在這裏選擇了:
#define SYSCLK_FREQ_72MHz 72000000
也就是103系列能跑到的最大值72M
然後這個 C文件繼續往下看
#elif defined SYSCLK_FREQ_72MHz
const uint32_t SystemFrequency = SYSCLK_FREQ_72MHz;
const uint32_t SystemFrequency_SysClk = SYSCLK_FREQ_72MHz;
const uint32_t SystemFrequency_AHBClk = SYSCLK_FREQ_72MHz;
const uint32_t SystemFrequency_APB1Clk = (SYSCLK_FREQ_72MHz/2);
const uint32_t SystemFrequency_APB2Clk = SYSCLK_FREQ_72MHz;
這就是在定義了CPU跑72M的時候,各個系統的速度了.他們分別是:硬件頻率,系統時鐘,AHB總線頻率,APB1總線頻率,APB2總線頻率.再往下看,看到這個了:
#elif defined SYSCLK_FREQ_72MHz
static void SetSysClockTo72(void);
這就是定義 72M 的時候,設置時鐘的函數.這個函數被 SetSysClock ()函數調用,而
SetSysClock ()函數則是被 SystemInit()函數調用.最後 SystemInit()函數,就是被你調用的了
所以設置系統時鐘的流程就是:
首先用戶程序調用 SystemInit()函數,這是一個庫函數,然後 SystemInit()函數裏面,進行了一些寄存器必要的初始化後,就調用 SetSysClock()函數. SetSysClock()函數根據那個#define SYSCLK_FREQ_72MHz 72000000 的宏定義,知道了要調用SetSysClockTo72()這個函數,於是,就一堆麻煩而複雜的設置~!@#$%^然後,CPU跑起來了,而且速度是 72M. 雖然說的有點累贅,但大家只需要知道,用戶要設置頻率,程序中就做的就兩個事情:
第一個: system_stm32f10x.c 中 #define SYSCLK_FREQ_72MHz 72000000
第二個:調用SystemInit()
正點原子,戰艦板
在 STM32 中,有五個時鐘源,爲 HSI、HSE、LSI、LSE、PLL。從時鐘頻率來分可以分爲
高速時鐘源和低速時鐘源,在這 5 箇中 HIS,HSE 以及 PLL 是高速時鐘,LSI 和 LSE 是低速時
鍾。從來源可分爲外部時鐘源和內部時鐘源,外部時鐘源就是從外部通過接晶振的方式獲取時
鍾源,其中 HSE 和 LSE 是外部時鐘源,其他的是內部時鐘源。下面我們看看 STM32 的 5 個時
鍾源,我們講解順序是按圖中紅圈標示的順序:
①、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。
上面我們簡要概括了 STM32 的時鐘源,那麼這 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)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_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;
#endif
這裏總結一下 SystemInit()函數中設置的系統時鐘大小:
SYSCLK(系統時鐘) =72MHz
AHB 總線時鐘(使用 SYSCLK) =72MHz
APB1 總線時鐘(PCLK1) =36MHz
APB2 總線時鐘(PCLK2) =72MHz
PLL 時鐘 =72MHz