天天看點

stm32之時鐘的了解stm32中五個時鐘源的介紹對時鐘源的配置

對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 進行逐項配置

配置流程:

  1. 将RCC寄存器重新設定為預設值 RCC_DeInit;
  2. 打開外部高速時鐘晶振HSE RCC_HSEConfig(RCC_HSE_ON);
  3. 等待外部高速時鐘晶振工作 HSEStartUpStatus = RCC_WaitForHSEStartUp();
  4. 設定AHB時鐘 RCC_HCLKConfig;
  5. 設定高速AHB時鐘 RCC_PCLK2Config;
  6. 設定低速速AHB時鐘 RCC_PCLK1Config;
  7. 設定PLL RCC_PLLConfig;
  8. 打開PLL RCC_PLLCmd(ENABLE);
  9. 等待PLL工作 while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
  10. 設定系統時鐘 RCC_SYSCLKConfig;
  11. 判斷是否PLL是系統時鐘 while(RCC_GetSYSCLKSource() != 0x08)
  12. 打開要使用的外設時鐘 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時鐘  
           

繼續閱讀