4. 外部中断控制LED

任务说明

本案例使用NXP S32K144开发板,通过按键触发外部中断,在中断服务函数中翻转LED的亮灭状态。需要完成以下目标:配置按键引脚为外部中断输入、编写中断服务函数实现LED翻转、设置中断优先级并验证中断响应。

硬件连接

  • 按键K1连接PTA0引脚(低电平有效,按下为低电平)
  • LED0连接PTD15引脚(高电平点亮)
  • LED1连接PTD16引脚(高电平点亮)
S32K144 MCU PTA0 PTD15 PTD16 按键K1 EXT_INT R1 VDD GND LED0 LED1 R2 R3 GND 中断触发路径

代码实现

本案例使用S32K144的GPIO外部中断功能。PTA0配置为下降沿触发的外部中断输入,PTD15和PTD16配置为GPIO输出控制LED。中断服务函数中翻转两个LED的状态,实现按键按下时LED交替亮灭。

/* external_interrupt_led.c */
#include "S32K144.h"

/* LED引脚定义 */
#define LED0_PIN   15u   /* PTD15 */
#define LED1_PIN   16u   /* PTD16 */
#define KEY_PIN    0u    /* PTA0  */

/* 中断优先级定义 */
#define KEY_ISR_PRIORITY  5u

/* 函数声明 */
void PORT_IRQHandler(void);
void delay_cycles(volatile unsigned int count);

/* 初始化LED引脚 */
void LED_Init(void)
{
    /* 使能PORTD时钟 */
    PCC->PCCn[PCC_PORTD_INDEX] = PCC_PCCn_CGC_MASK;
    
    /* 配置PTD15和PTD16为GPIO输出 */
    PORTD->PCR[LED0_PIN] = PORT_PCR_MUX(1u);   /* 复用为GPIO */
    PORTD->PCR[LED1_PIN] = PORT_PCR_MUX(1u);
    
    PTD->PDDR |= (1u << LED0_PIN) | (1u << LED1_PIN);  /* 设为输出 */
    PTD->PDOR |= (1u << LED0_PIN) | (1u << LED1_PIN);  /* 初始熄灭 */
}

/* 初始化按键外部中断 */
void KEY_EXTI_Init(void)
{
    /* 使能PORTA时钟 */
    PCC->PCCn[PCC_PORTA_INDEX] = PCC_PCCn_CGC_MASK;
    
    /* 配置PTA0为GPIO输入,使能内部上拉 */
    PORTA->PCR[KEY_PIN] = PORT_PCR_MUX(1u) |      /* 复用为GPIO */
                          PORT_PCR_PE_MASK |      /* 使能上拉/下拉 */
                          PORT_PCR_PS_MASK |      /* 选择上拉 */
                          PORT_PCR_IRQC(0xAu);    /* 下降沿触发中断 */
    
    PTA->PDDR &= ~(1u << KEY_PIN);  /* 设为输入 */
    
    /* 设置中断优先级 */
    NVIC_SetPriority(PORTA_IRQn, KEY_ISR_PRIORITY);
    
    /* 使能PORTA中断 */
    NVIC_EnableIRQ(PORTA_IRQn);
}

/* PORTA中断服务函数 */
void PORTA_IRQHandler(void)
{
    /* 检查PTA0是否触发中断 */
    if (PORTA->ISFR & (1u << KEY_PIN))
    {
        /* 翻转LED0和LED1状态 */
        PTD->PTOR = (1u << LED0_PIN) | (1u << LED1_PIN);
        
        /* 清除中断标志 */
        PORTA->ISFR = (1u << KEY_PIN);
    }
}

/* 简单延时函数 */
void delay_cycles(volatile unsigned int count)
{
    while (count--)
    {
        __NOP();
    }
}

/* 主函数 */
int main(void)
{
    /* 初始化系统时钟 */
    WDOG->CNT = 0xD928C520u;  /* 解锁看门狗 */
    WDOG->TOVAL = 0x0000FFFFu;
    WDOG->CS = 0x00002100u;   /* 禁用看门狗 */
    
    /* 初始化外设 */
    LED_Init();
    KEY_EXTI_Init();
    
    while (1)
    {
        /* 主循环空操作,等待中断 */
        __WFI();
    }
}

代码说明

  • LED_Init():使能PORTD时钟,配置PTD15和PTD16为GPIO输出模式,初始状态为高电平(LED熄灭)
  • KEY_EXTI_Init():使能PORTA时钟,配置PTA0为GPIO输入并启用内部上拉电阻,设置下降沿触发外部中断,配置中断优先级为5
  • PORTA_IRQHandler():中断服务函数,检测到PTA0中断标志后,通过PTOR寄存器翻转两个LED的输出状态,然后清除中断标志
  • NVIC_SetPriority():设置PORTA中断优先级为5(数值越小优先级越高,S32K144支持0-15级)

编译与烧录

  1. 在S32 Design Studio中创建新工程,选择S32K144芯片型号
  2. 将上述代码复制到main.c文件中
  3. 编译工程生成.elf或.hex文件
  4. 使用S32K144EVB-Q100开发板,通过OpenSDA调试器连接USB口
  5. 将生成的elf文件烧录到开发板

验证方法

完成烧录后,按下按键K1,观察LED0和LED1的状态变化:

  • 初始状态:LED0和LED1均熄灭
  • 第一次按下按键:LED0和LED1同时点亮
  • 第二次按下按键:LED0和LED1同时熄灭
  • 后续每次按下按键,LED状态都会翻转

判定标准:每次按下按键,两个LED的状态同步翻转,说明外部中断触发正常,中断服务函数正确执行了LED翻转操作。若LED状态不变化,检查按键连接和引脚配置是否正确。

中断优先级说明

本案例将PORTA中断优先级设置为5。S32K144的NVIC支持0~15级优先级,数值越小优先级越高。若系统中存在多个中断源,可通过修改KEY_ISR_PRIORITY宏定义的值来调整按键中断的抢占优先级。例如设置为0则按键中断具有最高优先级,可以抢占其他低优先级中断。