對stm32時鐘源的進一步了解
stm32中五個時鐘源的介紹
- HSI 是高速内部時鐘,RC 振蕩器,頻率為 8MHz。
- HSE 是高速外部時鐘,可接石英/陶瓷諧振器,或者接外部時鐘源,頻率範圍為4MHz~16MHz。推薦接8MHz。
- LSI 是低速内部時鐘,RC 振蕩器,頻率為 40kHz。獨立看門狗的時鐘源隻能是 LSI,同時 LSI 還可以作為 RTC 的時鐘源。
- LSE 是低速外部時鐘,接頻率為 32.768kHz 的石英晶體。這個主要是 RTC 的時鐘源。
- PLL 為鎖相環倍頻輸出,其時鐘輸入源可選擇為 HSI/2、HSE 或者 HSE/2。倍頻可選擇為2~16 倍,但是其輸出頻率最大不得超過 72MHz。
對時鐘源的配置
RCC_Configuration 進行逐項配置
配置流程:
- 将RCC寄存器重新設定為預設值 RCC_DeInit;
- 打開外部高速時鐘晶振HSE RCC_HSEConfig(RCC_HSE_ON);
- 等待外部高速時鐘晶振工作 HSEStartUpStatus = RCC_WaitForHSEStartUp();
- 設定AHB時鐘 RCC_HCLKConfig;
- 設定高速AHB時鐘 RCC_PCLK2Config;
- 設定低速速AHB時鐘 RCC_PCLK1Config;
- 設定PLL RCC_PLLConfig;
- 打開PLL RCC_PLLCmd(ENABLE);
- 等待PLL工作 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
- 設定系統時鐘 RCC_SYSCLKConfig;
- 判斷是否PLL是系統時鐘 while(RCC_GetSYSCLKSource() != 0x08)
- 打開要使用的外設時鐘 RCC_APB2PeriphClockCmd()/RCC_APB1PeriphClockCmd()
RCC的配置函數(使用外部8MHz晶振)
void RCC_Configuration(void)
{
/*将外設RCC寄存器重設為預設值*/
RCC_DeInit();
/*設定外部高速晶振(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
/*使能PLL */
RCC_PLLCmd(ENABLE);
/*檢查指定的RCC标志位(PLL準備好标志)設定與否*/
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
/*設定系統時鐘(SYSCLK)*/
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
//RCC_SYSCLKSource_PLLCLK——選擇PLL作為系統時鐘
/* PLL傳回用作系統時鐘的時鐘源*/
while(RCC_GetSYSCLKSource() != ) //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時鐘
}
我們可以通過這串代碼明白是如何配置的RCC,不過為了友善,一般用SystemInit()來配置。
SystemInit()對時鐘的配置
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
}
隻需定義
#define SYSCLK_FREQ_72MHz 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
舉一個RTC配置的例子
u8 RTC_Init(void)
{
//檢查是不是第一次配置時鐘
u8 temp=;
if (BKP_ReadBackupRegister(BKP_DR1) != ) //從指定的後備寄存器中讀出資料:讀出了與寫入的指定資料不相乎
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE); //使能PWR和BKP外設時鐘
PWR_BackupAccessCmd(ENABLE); //使能後備寄存器通路
BKP_DeInit(); //複位備份區域
RCC_LSEConfig(RCC_LSE_ON); //設定外部低速晶振(LSE),使用外設低速晶振
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) //檢查指定的RCC标志位設定與否,等待低速晶振就緒
{
temp++;
delay_ms();
}
if(temp>=)return ;//初始化時鐘失敗,晶振有問題
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //設定RTC時鐘(RTCCLK),選擇LSE作為RTC時鐘
RCC_RTCCLKCmd(ENABLE); //使能RTC時鐘
RTC_WaitForLastTask(); //等待最近一次對RTC寄存器的寫操作完成
RTC_WaitForSynchro(); //等待RTC寄存器同步
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中斷
RTC_WaitForLastTask(); //等待最近一次對RTC寄存器的寫操作完成
RTC_EnterConfigMode();/// 允許配置
RTC_SetPrescaler(); //設定RTC預分頻的值
RTC_WaitForLastTask(); //等待最近一次對RTC寄存器的寫操作完成
RTC_Set(,,,,,); //設定時間
RTC_ExitConfigMode(); //退出配置模式
BKP_WriteBackupRegister(BKP_DR1, ); //向指定的後備寄存器中寫入使用者程式資料
}
else//系統繼續計時
{
RTC_WaitForSynchro(); //等待最近一次對RTC寄存器的寫操作完成
RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中斷
RTC_WaitForLastTask(); //等待最近一次對RTC寄存器的寫操作完成
}
RTC_NVIC_Config();//RCT中斷分組設定
RTC_Get();//更新時間
return ; //ok
}
通過這兩句就實作了RTC的配置
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); //設定RTC時鐘(RTCCLK),選擇LSE作為RTC時鐘
RCC_RTCCLKCmd(ENABLE); //使能RTC時鐘