2. 按键中断与任务调度
任务说明
本案例在 XMOS 多核处理器上实现按键中断驱动的任务切换:按键按下时触发端口中断,在中断服务程序中置位事件标志;主循环检测到标志后切换当前执行任务,演示事件驱动编程模型。目标是通过实际代码展示 XMOS 的端口中断响应机制与协作式任务调度方法。
硬件连接
按键 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 状态翻转一次,且长时间运行无异常,即判定案例通过。