华大HC32F460 XTAL(外部振荡器)故障检测中断实验代码详解

声明:以下内容均是自己学习心得。

一、基础知识

XTAL外部振荡器包括:外部高速振荡器(4~25MHZ)和外部低速振荡器(32.768KHZ)。

外部高速振荡器可为系统时钟提供更为精确时钟源。

外部低速振荡器可为系统时钟、实时时钟电路(RTC)提供更为精确时钟源。

本次实验所使用寄存器有:GPIO中的通用控制寄存器(PCRxy)、中断控制器(INTC)中INT_NMIFR(不可屏蔽中断标志寄存器)和INT_NMICFR(不可屏蔽中断标志清除寄存器)、时钟控制器(CMU)中的CMU_XTALSTDSR(CMU XTAL振荡故障状态寄存器)、CMU_XTALSTDCR(CMU XTAL振荡故障控制器)和CMU_XTALSTBCR(安定配置寄存器)

二、实验代码详解

硬件连接:PH1、PH0连接外部晶振。

实验目的:通过人为制造XTALSTOP故障,展示MUC的NMI_XTALSTOP中断功能。

只需要将PH1、PH0外部晶振相连接的电容短路用导线或者镊子短路即可。

mian.c中

#define DLY_MS              (500UL)
static void NMI_Xtal_Init(void)
{
    stc_nmi_init_t stcNmiInit;
    stc_clock_xtalstd_init_t stcXtalStdInit;
    stc_clock_xtal_init_t stcXtalInit;

    GPIO_AnalogCmd(BSP_XTAL_PORT, BSP_XTAL_IN_PIN | BSP_XTAL_OUT_PIN, ENABLE);
    (void)CLK_XtalStructInit(&stcXtalInit);
    stcXtalInit.u8State = CLK_XTAL_ON;
    stcXtalInit.u8StableTime = CLK_XTAL_STB_2MS;
    (void)CLK_XtalInit(&stcXtalInit);

    (void)CLK_XtalStdStructInit(&stcXtalStdInit);
    stcXtalStdInit.u8State = CLK_XTALSTD_ON;
    stcXtalStdInit.u8Int = CLK_XTALSTD_INT_ON;
    (void)CLK_XtalStdInit(&stcXtalStdInit);

    /* NMI interrupt configure */
    (void)NMI_StructInit(&stcNmiInit);
    stcNmiInit.u32Src = NMI_SRC_XTAL;
    (void)NMI_Init(&stcNmiInit);
}

代码拆分来分析:

stc_nmi_init_t stcNmiInit; 配置NMI不可屏蔽中断结构体

stc_clock_xtalstd_init_t stcXtalStdInit; 配置CMU_XTALSTDCR(CMU XTAL振荡故障控制器)

stc_clock_xtal_init_t stcXtalInit; 配置XTAL时钟结构体

GPIO_AnalogCmd(BSP_XTAL_PORT, BSP_XTAL_IN_PIN | BSP_XTAL_OUT_PIN, ENABLE)

设置模拟输入,因为外部晶振无法发送信号。

配置XTAL时钟相关寄存器(CMU_XTALCFGR)

(void)CLK_XtalStructInit(&stcXtalInit);

stcXtalInit.u8State = CLK_XTAL_ON;

stcXtalInit.u8StableTime = CLK_XTAL_STB_2MS;

(void)CLK_XtalInit(&stcXtalInit);

我们来看看结构体成员有哪些:

typedef struct {
    uint8_t u8State;            /*!< 使能XTAL时钟  */
    uint8_t u8Drv;              /*!< XTAL驱动能力选择:将4~25MHZ分为:超小、小、中、高驱动能力  */
    uint8_t u8Mode;             /*!< 设置XTAL模式:振荡器模式,外部时钟输入模式  */
    uint8_t u8SuperDrv;         /*!< 设置XTAL超高驱动   */
    uint8_t u8StableTime;       /*!< 设定XTAL稳定时间 */
} stc_clock_xtal_init_t;

这里特别声明:XTAL稳定时间是通过对CMU_XTALSTBCR安定配置寄存器b3~b0操作实现的,稳定计数器的一个计数周期 = LRC周期/8。

配置XTAL故障检测相关寄存器(CMU_XTALSTDCR)

(void)CLK_XtalStdStructInit(&stcXtalStdInit);

stcXtalStdInit.u8State = CLK_XTALSTD_ON;

stcXtalStdInit.u8Int = CLK_XTALSTD_INT_ON;

(void)CLK_XtalStdInit(&stcXtalStdInit);

看看结构体成员有哪些:

typedef struct {
    uint8_t u8State;            /*!< 使能故障检测   */
    uint8_t u8Mode;             /*!< XTAL故障检测模式选择   */
    uint8_t u8Int;              /*!<  使能XTAL故障检测中断   */
    uint8_t u8Reset;            /*!< 重置XTAL故障检测选择   */
} stc_clock_xtalstd_init_t;

配置NMI不可屏蔽中断相关寄存器(INT_NMICR)

(void)NMI_StructInit(&stcNmiInit);

stcNmiInit.u32Src = NMI_SRC_XTAL;

(void)NMI_Init(&stcNmiInit);

看看结构体成员:

typedef struct {
    uint32_t u32Src;            /*!< 设置不可屏蔽中断触发源*/
    uint32_t u32Edge;           /*!< 设置不可屏蔽中断触发边沿 */
    uint32_t u32Filter;         /*!< 设能不可屏蔽中断滤波器 */
    uint32_t u32FilterClock;    /*!< 选择不可屏蔽中断滤波器的时钟 */
} stc_nmi_init_t;

特别声明:为什么NMI中断触发源能选择,因为华大提供了除NMI管脚作为不可屏蔽中断源以外,可以独立选择多种系统中断事件作为不可屏蔽中断。

中断回调函数:

void NMI_Handler(void)
{
    NMI_XtalStop_IrqHandler();
}


static void NMI_XtalStop_IrqHandler(void)
{
    if (SET == NMI_GetNmiStatus(NMI_SRC_XTAL)) {
        NMI_ClearNmiStatus(NMI_SRC_XTAL);
        CLK_ClearXtalStdStatus();
        BSP_LED_Toggle(LED_RED);
        BSP_LED_Off(LED_BLUE);
        DDL_DelayMS(DLY_MS);
    }
}

首先触发NMI的中断回调函数,再里面嵌套一个XTAL故障检测中断回调函数NMI_XtalStop_IrqHandler。

NMI_GetNmiStatus(NMI_SRC_XTAL) 用来判断INT_NMIFR(不可屏蔽中断标志寄存器)的b5位(XTALSTPFR检测主发振器停止中断标志),置1说明发生了XTAL故障。

NMI_ClearNmiStatus(NMI_SRC_XTAL) 用来清零INT_NMICFR(不可屏蔽中断标志清除寄存器)中b5位(XTALSTPCFR检测主发振器停止中断标志清除)。因为该位置1则无法进行下一次XTAL故障检测。

CLK_ClearXtalStdStatus() 用来清零CMU_XTALSTDSR(振荡故障状态寄存器)。置1:检测到XTAL振荡故障。原理同上。

主函数int32_t main(void) 就没有什么难点可讲的。

int32_t main(void)
{
    /* Register write enable for some required peripherals. */
    LL_PERIPH_WE(LL_PERIPH_EFM | LL_PERIPH_FCG | LL_PERIPH_GPIO | LL_PERIPH_PWC_CLK_RMU | LL_PERIPH_SRAM);
    /* BSP LED initialize */
    BSP_LED_Init();
    /* NMI initialize */
    NMI_Xtal_Init();
    /* Register write protected for some required peripherals. */
    LL_PERIPH_WP(LL_PERIPH_EFM | LL_PERIPH_FCG | LL_PERIPH_GPIO | LL_PERIPH_SRAM);
    for (;;) {
        BSP_LED_Off(LED_RED);
        BSP_LED_Toggle(LED_BLUE);
        DDL_DelayMS(DLY_MS);
    }
}

实验现象就是:发生故障:蓝灯停止闪烁,红灯闪烁。

本次实验内容到此结束,有什么疑问可以私信我~

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值