stm32 時鐘系統學習

http://www.elecfans.com/dianzichangshi/20171113578546.html

一、在STM32中,有五個時鐘源,爲HSIHSELSILSEPLL

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

 

 

 

 

 

 

 

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