天天看點

STM32的時鐘簡介和配置方法

STM32的時鐘簡介:

STM32中使用任何一個外設都必須打開相應的時鐘。在STM32中有5個時鐘源可供使用者選擇:

1.HSI高速内部時鐘,RC震蕩器,頻率為8MHz。

2.HSE高速外部時鐘,右英/陶瓷諧振器,或着外部時鐘源,4MHz-16MHz.

3.LSI内部低速時鐘,RC震蕩器頻率為40Hz。

4.LSE外部低速時鐘,接頻率為32.768KHz的石英晶體。

5.PLL鎖相環頻輸出,時鐘源可選為HIS/2、HSE或HSE/2。倍頻可選2-16倍,但其輸出頻率最大不能超過72MHz。

系統時鐘SYSCLK,它是供STM32中絕大部分器件工作的時鐘源,系統時鐘可選擇為PLL輸出、HSI或者HSE。系統時鐘的做大頻率為72MHz,它通過AHB分頻器分頻後送給個子產品使用,AHB分頻器可選擇1、2...512分頻。AHB分頻器輸出的時鐘送給5大子產品使用:

1.送給AHB總線、核心、記憶體、DMA使用的HCLK時鐘。

2.通過8分頻送給系統定時器的定時時鐘(嘀嗒定時器)。

3.直接送給Cortex的空閑時鐘PCLK。

4.送給APB1分頻器可選擇1、2、4、8、16分頻,其輸出一路供APB1外設使用(PCLK1,最大頻率36M)另一路送給定時器(Timer)2、3、4倍頻器使用。該倍頻器可選擇1或着2倍頻,時鐘輸出供定時器2、3、4使用。

5.送給APB2分頻器可選擇1、2、4、8、16分頻,其輸出一路供APB2外設使用(PCLK2,最大頻率72M)另一路送給定時器(Timer)1倍頻器使用。該倍頻器可選擇1或着2倍頻。時鐘輸出供定時器1使用。另外,APB2分頻器還有一路輸出供ADC分頻器使用,分頻後送給ADC子產品使用。ADC分頻器可選 擇為2、4、6、8分頻。

連接配接在APB1(低速外設)上裝置有:電源接口、備份接口、CAN、USB、I2C1、I2C2、UART2、UART3、SPI2、視窗看門狗、TIMER2、TIMER3、TIMER4。

連接配接在APB2(高速外設)上裝置有:UART1、SPI1、Timer1、ADC1、ADC2、所有普通IO口、第二功能IO口。

STM32的時鐘簡介和配置方法

涉及的寄存器:

RCC 寄存器結構,RCC_TypeDeff,在檔案“stm32f10x_map.h”中定義如下: 

typedef struct 

vu32 CR;                  //HSI,HSE,CSS,PLL等的使能 

vu32 CFGR;              //PLL等的時鐘源選擇以及分頻系數設定

vu32 CIR;                // 清除/使能 時鐘就緒中斷

vu32 APB2RSTR;      //APB2線上外設複位寄存器

vu32 APB1RSTR;      //APB1線上外設複位寄存器

vu32 AHBENR;         //DMA,SDIO等時鐘使能

vu32 APB2ENR;       //APB2線上外設時鐘使能

vu32 APB1ENR;      //APB1線上外設時鐘使能

vu32 BDCR;           //備份域控制寄存器

vu32 CSR;            

} RCC_TypeDef;

在ST公司的外設固件庫的示例裡,對于工程項目檔案,ST并沒有在啟動函數main()裡初始化PLL,因為其已經在硬體初始化階段完成對系統時鐘的配置。這樣也就帶了一個問題,ST庫裡的均使用了外設8MHz的晶振,而我們平時的項目就一定采用的是這個頻率,實際配置的低于8MHz,MCU不能全速運作,高于8MHz,外設時鐘即配置失敗,甚至無法運作。那麼如何重新配置時鐘就需要我們重新設計了。

以下為使用庫函數重新編寫了STM32F系統時鐘PLL初始化過程:

以下的函數需要添加#include "stm32f10x.h"的頭檔案來調用ST固件庫。

static void SysClockInit(void)

{

RCC_DeInit();

RCC_HSEConfig(RCC_HSE_ON);

HSEStartUpStatus = RCC_WaitForHSEStartUp();

if (HSEStartUpStatus == SUCCESS)

{

FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

FLASH_SetLatency(FLASH_Latency_2);

RCC_HCLKConfig(RCC_SYSCLK_Div1);

RCC_PCLK2Config(RCC_HCLK_Div1);

RCC_PCLK1Config(RCC_HCLK_Div2);

RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

RCC_PLLCmd(ENABLE);

while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)

{

}

RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

while(RCC_GetSYSCLKSource() != 0x08)

{

}

}

else

{

while (1)

{

}

}

}

繼續閱讀