在前一段時間的公司的項目中要求用到STM32這款處理器在外部晶振異常的情況下自動的切換到內部晶振,在網上找了N多的資料終于在網上找到了一個官方的研討會的PPT里面簡單的介紹了一下,于是順著這個思路試著去編寫代碼,沒想到官方提供的思路還蠻靠譜!
—————————————————我是華麗的分割線———————————————————
—————————————————我是華麗的分割線———————————————————
函數一、
void INIT_CLOCK(void)
{
#if 1
ErrorStatus HSEStartUpStatus;
RCC_DeInit(); //復位RCC寄存器
RCC_HSEConfig(RCC_HSE_ON); //設置外部高速晶振 (HSE)
HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待 HSE 起振
#if 1
//判斷外部晶振是否OK,如果OK就用外部晶振,如果不行,就用內部晶振,優先用外部晶振。
if(HSEStartUpStatus == SUCCESS)
{
RCC_ClockSecuritySystemCmd(ENABLE); //啟動時鐘安全系統 CSS
//外部晶振配置
RCC_HCLKConfig(RCC_SYSCLK_Div1); //設置ABH時鐘(HCLK):HCLK=SYSCLK
//設置PLL時鐘源及倍頻系數, PLLCLK = HSE*PLLMul = 8*8 = 64MHz 實際是:8*8=64MHz
RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_2);
RCC_PLLCmd(ENABLE); //使能PLL
//檢查指定的RCC標志位設置與否
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); // Wait till PLL is ready
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //設置系統時鐘 (SYSCLK)
//返回作用系統時鐘的時鐘源
// Wait till PLL is used as system clock source
while(RCC_GetSYSCLKSource() != 0x08);
}
else
#endif
{
//內部晶振配置
RCC_DeInit(); //復位RCC寄存器
RCC_HSEConfig(RCC_HSE_OFF); //關閉外部晶(HSE)
RCC_HCLKConfig(RCC_SYSCLK_Div1); //設置ABH時鐘(HCLK):HCLK=SYSCLK
//設置PLL時鐘源及倍頻系數, PLLCLK = HSI/2*PLLMul = 8/2*12 = 48MHz 實際是:48MHz
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_12);
RCC_PLLCmd(ENABLE); //使能PLL
//檢查指定的RCC標志位設置與否
//while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); // Wait till PLL is ready
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //設置系統時鐘 (SYSCLK)
//返回作用系統時鐘的時鐘源
// Wait till PLL is used as system clock source
while(RCC_GetSYSCLKSource() != 0x08);
}
#endif
}
—————————————————我是華麗的分割線———————————————————
在上面哪一個函數中只有在外部晶振啟動初始化中才啟動了時鐘安全系統(PS:紅色加粗部分)因為只有外部晶振初始失敗再切換至內部晶振,此函數是外部晶振啟動優先只有外部晶振啟動失敗再去啟動內部晶振。
函數二、
void NMIException(void)
{
if(RCC_GetITStatus(RCC_IT_CSS) != RESET)
{
#if 0 //內部晶振配置
RCC_DeInit(); //復位RCC寄存器
RCC_HSEConfig(RCC_HSE_OFF); //關閉外部晶(HSE)
RCC_HCLKConfig(RCC_SYSCLK_Div1); //設置ABH時鐘(HCLK):HCLK=SYSCLK
//設置PLL時鐘源及倍頻系數, PLLCLK = HSI/2*PLLMul = 8/2*12 = 48MHz 實際是:48MHz
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_12);
RCC_PLLCmd(ENABLE); //使能PLL
//檢查指定的RCC標志位設置與否
//while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //設置系統時鐘 (SYSCLK)
//返回作用系統時鐘的時鐘源
// Wait till PLL is used as system clock source
while(RCC_GetSYSCLKSource() != 0x08);
CLKOUT_8M_INIT(); //PA8端口時鐘輸出為24025提供8MHz時鐘
RCC_ITConfig(RCC_IT_HSIRDY,ENABLE); //使能 HSI就緒中斷
RCC_ITConfig(RCC_IT_PLLRDY,ENABLE); //使能 PLL就緒中斷
#else
NVIC_SystemReset(); //重啟
RCC_ITConfig(RCC_IT_HSERDY,ENABLE); //使能 HSE就緒中斷
RCC_ITConfig(RCC_IT_PLLRDY,ENABLE); //使能 PLL就緒中斷
#endif
RCC_ClearITPendingBit(RCC_IT_CSS); //清除時鐘安全系統中斷的掛起位
}
}
—————————————————我是華麗的分割線———————————————————
NMIException()函數是晶振異常函數的處理函數在異常中斷函數中調用此函數,紅色部分是內部晶振初始如果所以紅色部分的代碼可以實現外部晶振“無縫”的切換到內部晶振(如果是用于特定的場合如:醫療設備可以使用此段代碼),但由于我們產品對實時性要求不是很高我還是決定重新重啟設備再初始化晶振。
函數三、
void NMI_Handler(void)
{
NMIException();
}
—————————————————我是華麗的分割線———————————————————
NMI_Handler()函數是在STM32的庫文件中的“stm32f0xx_it.c”中的我們把晶振異常處理函數放置此不可屏蔽的異常中斷函數中就可以實現晶振異常時的相當于處理。
—————————————————我是華麗的分割線———————————————————
int main(void)
{
SystemInit();
INIT_CLOCK(); //使用HSI時鐘初始化系統時鐘
for(;;)
{
......
}
}
上一篇:STM32F103時鐘配置流程
下一篇:OK6410-實驗指令筆記
推薦閱讀
史海拾趣