2. 按键中断与任务调度

任务说明

本案例在 XMOS 多核处理器上实现按键中断驱动的任务切换:按键按下时触发端口中断,在中断服务程序中置位事件标志;主循环检测到标志后切换当前执行任务,演示事件驱动编程模型。目标是通过实际代码展示 XMOS 的端口中断响应机制与协作式任务调度方法。

硬件连接

XMOS XCORE Tile 0 Core 0: 主循环 Core 1: 按键中断 X0D0 X0D1 按键 SW1 LED D1 R1 3.3V GND R2 3.3V 按键按下 → X0D0 低电平 → 端口中断 中断置位标志 → 主循环切换任务 → X0D1 输出翻转

按键 SW1 一端接 X0D0,另一端接 GND,X0D0 通过上拉电阻 R1 接 3.3V。LED D1 阳极经限流电阻 R2 接 3.3V,阴极接 X0D1。按键按下时 X0D0 产生下降沿,触发端口中断。

代码实现


#include <xs1.h>
#include <platform.h>

// 端口定义
port p_button = XS1_PORT_1A;   // X0D0,按键输入
port p_led    = XS1_PORT_1B;   // X0D1,LED 输出

// 事件标志(全局变量,volatile 防止编译器优化)
volatile int button_flag = 0;

// 任务函数声明
void task_a(void);
void task_b(void);

// 按键中断服务程序:置位事件标志
void button_isr(void)
{
    // 读取端口以清除中断锁存
    p_button :> int _;
    // 置位标志,通知主循环
    button_flag = 1;
}

// 主循环:根据标志切换任务
void main_loop(void)
{
    int current_task = 0;   // 0 = task_a, 1 = task_b

    while (1) {
        if (button_flag) {
            button_flag = 0;    // 清除标志
            current_task = 1 - current_task;  // 切换任务
        }

        if (current_task == 0) {
            task_a();
        } else {
            task_b();
        }
    }
}

// 任务 A:LED 常亮
void task_a(void)
{
    p_led <: 0;    // 输出低电平,LED 点亮
}

// 任务 B:LED 熄灭
void task_b(void)
{
    p_led <: 1;    // 输出高电平,LED 熄灭
}

// 中断处理线程:等待按键端口事件
void button_thread(void)
{
    // 配置端口为输入,启用下降沿中断
    p_button :> int _;   // 初始读取,清除端口状态
    while (1) {
        // 等待端口事件(下降沿触发)
        p_button when pinseq(0) :> int _;
        button_isr();
    }
}

// 主入口
int main(void)
{
    // 并行运行主循环和按键中断线程
    par {
        main_loop();
        button_thread();
    }
    return 0;
}

代码说明

代码使用 par 块并行启动两个逻辑核心:main_loop() 运行任务调度循环,button_thread() 等待按键端口事件。当按键按下时,X0D0 变为低电平,when pinseq(0) 条件触发,线程进入中断服务流程,置位 button_flag。主循环检测到标志后清除标志并切换 current_task,从而在任务 A(LED 亮)和任务 B(LED 灭)之间切换。

关键点:button_flag 声明为 volatile,确保主循环每次读取时都从内存获取最新值;中断服务中先读取端口以清除中断锁存,避免重复触发。

编译与运行


# 使用 xTIMEcomposer 或命令行工具编译
xcc -target=XCORE-200-EXPLORER main.xc -o button_demo.xe

# 烧录到开发板
xrun --io button_demo.xe

编译时需根据实际开发板选择正确的 -target 参数。运行后观察 LED 状态:初始为点亮(任务 A),每按一次按键,LED 状态翻转一次。

验证方法

1. 将程序烧录至开发板,确认 LED 初始为点亮状态。
2. 按下按键 SW1 并释放,观察 LED 应熄灭。
3. 再次按下并释放,LED 应重新点亮。
4. 连续快速按键多次,LED 状态应每次按键后翻转一次,无遗漏或卡死现象。
5. 若 LED 状态与按键次数不一致,检查按键是否抖动导致多次触发,或检查端口连接是否正确。

判定标准:每次按键释放后 LED 状态翻转一次,且长时间运行无异常,即判定案例通过。