时钟对于MCU而言就像脉搏一样,在恶劣情况下如果出现外部晶振短路的情况会导致MCU无法正常运行。如果MCU应用于安全生产时,有可能造成安全事故。为了应对这一突发状况,ST公司生产的STM32采用双时钟机制,在外部晶振被短路的情况下,转而使用内部RC振荡器作为自己时钟心跳保证系统正常运行。然而RC振荡器并不是非常的准确,我们希望能够在外部晶振恢复正常的情况下继续使用外部晶振。本文主要研究内容是在外部晶振被短路的情况下,转而使用内部HSI。当外部晶振恢复正常后,重新使用外部晶振。
根据以上理论研究可知,当晶振被短路以后,进入NMI中断。这个中断不需要开启,而且等级很好。
设计方案:开启CSS功能-设置RCC中断等级
|
|
|
NMI中断中-------打开HSE--开启HSE中断就绪中断
|
|
RCC中断-------检测HSE就绪状态----设置HSE作为时钟----关闭HSE就绪中断----清楚状态位
/**************************RCC中断处理函数**************************/
//当HSE恢复正常时进入该函数
void RCC_IRQHandler(void)
{
if(RESET != RCC_GetITStatus(RCC_IT_HSERDY)) //如果HSE就绪
{
#if defined (DBGUG_RCC_IRQHandler)
printf("i'm in IRQ\n"); //串口输出进入RCC中断
#endif
Set_SysClockToHSE(); //设置系统时钟为HSE
RCC_ITConfig(RCC_IT_HSERDY, DISABLE); //关闭HSE就绪中断
RCC_ClearITPendingBit(RCC_IT_HSERDY); // 清除HSE就绪中断标志位
}
} /*************************NMI中断函数入口**************************/
//当外部晶振被短路不能起振后进入NMI中断函数
void NMI_Handler(void)
{
if (RCC_GetITStatus(RCC_IT_CSS) != RESET) //HSE、PLl已经被禁止(但是PLL设置未变)
{
#if defined(DEBUG_NMI_Handler)
printf("i'm in NMI\n"); //串口输出进入NMI中断
#endif
RCC_HSEConfig(RCC_HSE_ON); // 使能HSE
RCC_ITConfig(RCC_IT_HSERDY, ENABLE); // 使能HSE就绪中断
RCC_ClearITPendingBit(RCC_IT_CSS); // 清除时钟安全系统的中断挂起位
}
}
/*************************************************************
****函 数 名:CSS_Init
****功 能:初始化CSS(时钟安全)
****入口参数:无
****返 回 值:无
****说 明:无
**************************************************************/
void CSS_Init(void)
{
//设置HSE就绪中断的优先级
//NVIC 配置
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = RCC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ; //抢占优先级0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
RCC_ClockSecuritySystemCmd(ENABLE); //启动时钟安全系统CSS
}
/*************************************************************
****函 数 名:Set_SysClockToHSE
****功 能:设置系统时钟为HSE
****入口参数:无
****返 回 值:
****说 明:无
**************************************************************/
static void Set_SysClockToHSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/
/* Enable HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
/* Wait till HSE is ready and if Time out is reached exit */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
{
HSEStatus = (uint32_t)0x01;
}
else
{
HSEStatus = (uint32_t)0x00;
}
if (HSEStatus == (uint32_t)0x01)
{
#if !defined STM32F10X_LD_VL && !defined STM32F10X_MD_VL && !defined STM32F10X_HD_VL
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE;
/* Flash 0 wait state */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
#ifndef STM32F10X_CL
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0;
#else
if (HSE_VALUE <= 24000000)
{
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0;
}
else
{
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1;
}
#endif /* STM32F10X_CL */
#endif
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1;
/* Select HSE as system clock source */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_HSE;
/* Wait till HSE is used as system clock source */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x04)
{
}
}
else
{ /* If HSE fails to start-up, the application will have wrong clock
configuration. User can add here some code to deal with this error */
}
}/*************************************************/
/*************************************************/
开发环境使用KEIL,库函数版本为3.5
1.本函数不依赖其他头文件,可以独立移植,所需要的头文件文件已经包含在文件中。
注意:在头文件中有包含串口头文件,使用时请将#include "usart.h"中的usart.h替换成
工程中串口文件命
2.该功能使用前提为:将系统时钟设置成HSE(外部晶振,8M),在移植时请将官方提供的
system_stm32f10x.c system_stm32f10x.h替换成本工程提供的文件,并根据宏定义修改系统时钟为HSE(默认为HSE)
3.设置后系统时钟为HSE(假定8MHz)后,AHB为8MHz,APB1为4MHz,APB2为8MHz
注意:APB1下的定时器仍未8MHz
文件下载地址:
http://download.csdn.net/detail/wandermen/8779101
本文探讨了STM32在外部晶振短路时如何利用内部RC振荡器确保系统运行,并在外部晶振恢复后切换回外部晶振的方法。通过KEIL开发环境,介绍了不依赖额外头文件的独立移植函数,强调了系统时钟配置和时钟频率设置的重要性。
研究及实现&spm=1001.2101.3001.5002&articleId=46388921&d=1&t=3&u=a8cf1f8c15d4492d873564024dc163de)
1805
研究及实现&spm=1001.2101.3001.11663&articleId=46388921&d=1&t=3&u=8cdeb28d2411426da4b56d6c84696302)

被折叠的 条评论
为什么被折叠?



