Stellaris系列单片机在晶振被拔去后能够自动切换到内部振荡器,继续工作,不会死机!
Luminary公司的Stellaris系列单片机拥有3个时钟验证电路,该电路使用定时器通过一个慢速时钟来检验快速时钟: ● 主振荡器检验PLL ● 主振荡器检验内部振荡器 ● 内部振荡器除以64检验主振荡器
其中,PLL和内部振荡器都在芯片内部,是完全可靠的,实际上没有必要对其进行检测。但是主振荡器外接的晶体可能会偶然失效。时钟验证电路能够自动检测出晶体失效,会使系统时钟自动切换到工作时钟,并向控制器发出中断。在中断里可以采取某种对策。
以下是一个演示程序。
在程序运行后,配置为主振荡器MOSC+外部6MHz晶体,并使能MOSC失效检测功能,在主循环里工作指示灯WORK_LED慢速闪烁。 当拔去晶体时,会自动检测到MOSC失效,并触发中断。在中断里,系统时钟改为内部12MHz的振荡器IOSC,并点亮错误指示灯ERROR_LED,随后退出中断。 在退出中断后,我们发现LED快速闪烁,速度大约是原来的2倍。
由此可见,在Stellaris系列单片机里,正在工作的晶体即使被突然拔去,也不会造成死机,芯片可以自动切换到内部振荡器继续工作!
#include "hw_types.h" #include "hw_memmap.h" #include "hw_ints.h" #include "hw_sysctl.h" #include "hw_gpio.h" #include "src/interrupt.h" #include "src/sysctl.h" #include "src/gpio.h"
// 将较长的标识符定义为较短的形式 #define SysCtlPeriphEn SysCtlPeripheralEnable #define SysCtlMOSCVeriSet SysCtlMOSCVerificationSet #define GPIOPinTypeIn GPIOPinTypeGPIOInput #define GPIOPinTypeOut GPIOPinTypeGPIOOutput
// 定义LED指示灯,均为低电平点亮 #define WORK_LED GPIO_PORTB_BASE, GPIO_PIN_0 #define ERROR_LED GPIO_PORTB_BASE, GPIO_PIN_1
// 定义LED操作宏 #define WorkLedOn() GPIOPinWrite(WORK_LED, 0x00) #define WorkLedOff() GPIOPinWrite(WORK_LED, 0x01) #define ErrorLedOn() GPIOPinWrite(ERROR_LED, 0x00) #define ErrorLedOff() GPIOPinWrite(ERROR_LED, 0x02)
// LED初始化 void LedInit(void) { SysCtlPeriphEn(SYSCTL_PERIPH_GPIOB); // 使能GPIOB端口 GPIOPinTypeOut(WORK_LED); // 设置WORK_LED所在管脚为输出 GPIOPinTypeOut(ERROR_LED); // 设置WORK_LED在管脚为输出 WorkLedOff(); // 初始化时熄灭WORK_LED ErrorLedOff(); // 初始化时熄灭ERROR_LED }
// 时钟初始化 void ClockInit(void) { SysCtlClockSet(SYSCTL_USE_OSC | // 采用MOSC+6MHz晶体 SYSCTL_OSC_MAIN | SYSCTL_XTAL_6MHZ); SysCtlMOSCVeriSet(true); // 使能IOSC/64验证MOSC功能 SysCtlIntEnable(SYSCTL_INT_MOSC_FAIL); // 使能MOSC失效中断 IntEnable(INT_SYSCTL); // 使能系统控制中断 IntMasterEnable(); // 使能处理器中断 }
// 延时 void TimeDelay(unsigned long ulVal) { do { } while ( --ulVal != 0 ); }
// 主函数 int main(void) { // 初始化 LedInit(); ClockInit();
// 在6MHz晶体下LED闪烁发光,若拔去晶体,自动改用12MHz的IOSC,闪烁加快 for (;;) { WorkLedOn(); TimeDelay(400000UL); WorkLedOff(); TimeDelay(400000UL); } }
// 系统控制中断服务函数 void System_Control_ISR(void) { SysCtlClockSet(SYSCTL_USE_OSC | SYSCTL_OSC_INT); // 改用IOSC SysCtlMOSCVeriSet(false); // 禁止IOSC/64验证MOSC功能 SysCtlIntClear(SYSCTL_INT_MOSC_FAIL); // 清除MOSC失效中断 ErrorLedOn(); // 点亮错误指示灯 }
|