Zephyr OS 入门与实战

第8课:中断与异步事件处理

中断服务程序(ISR)编写规范

在Zephyr RTOS中,中断服务程序(ISR)是处理硬件中断的关键组件。Zephyr提供了标准化的方法来定义和连接ISR。

1. IRQ_CONNECT 宏

使用IRQ_CONNECT宏将中断服务程序连接到特定的中断线:

#include <zephyr.h>
#include <device.h>
#include <drivers/gpio.h>

#define MY_IRQ_PIN 5
#define MY_IRQ_PRIORITY 2

void my_isr(const void *arg)
{
    // 中断处理代码
    printk("中断触发!\n");
}

void main(void)
{
    // 连接中断服务程序
    IRQ_CONNECT(DT_IRQN(DT_NODELABEL(my_device)),  // 中断号
                MY_IRQ_PRIORITY,                  // 中断优先级
                my_isr,                            // ISR函数
                NULL,                              // 传递给ISR的参数
                0);                                // 标志位
    
    // 启用中断
    irq_enable(DT_IRQN(DT_NODELABEL(my_device)));
}

注意: Zephyr推荐使用设备树(DTS)来获取中断号,而不是硬编码,如DT_IRQN(DT_NODELABEL(my_device))所示。

2. ISR编写最佳实践

保持简短

ISR应该尽可能简短,只执行最必要的操作。长时间运行的操作应该推迟到线程上下文。

避免阻塞调用

ISR中不能使用可能导致阻塞的API,如k_sleep()k_mutex_lock()等。

使用内核对象

可以通过信号量、消息队列等内核对象通知线程上下文有中断发生。

警告: 在ISR中调用打印函数(如printk)可能会影响实时性能,只应在调试时使用。

工作队列(Workqueue)延迟处理

工作队列是Zephyr中用于延迟处理的一种机制,特别适合将ISR中的耗时操作推迟到线程上下文中执行。

1. 系统工作队列

Zephyr提供了一个预定义的系统工作队列(k_sys_work_q),可以直接使用:

#include <zephyr.h>
#include <sys/work_q.h>

struct k_work my_work;

void work_handler(struct k_work *work)
{
    printk("工作项被执行\n");
}

void main(void)
{
    // 初始化工作项
    k_work_init(&my_work, work_handler);
    
    // 提交到系统工作队列
    k_work_submit(&my_work);
}

2. 自定义工作队列

对于需要更高优先级或专用线程的情况,可以创建自定义工作队列:

#include <zephyr.h>
#include <sys/work_q.h>

#define MY_STACK_SIZE 1024
#define MY_PRIORITY 5

K_THREAD_STACK_DEFINE(my_stack_area, MY_STACK_SIZE);
struct k_work_q my_work_q;

struct k_work my_work;

void work_handler(struct k_work *work)
{
    printk("自定义工作队列中的工作项被执行\n");
}

void main(void)
{
    // 初始化自定义工作队列
    k_work_queue_init(&my_work_q);
    
    // 启动工作队列线程
    k_work_queue_start(&my_work_q,
                      my_stack_area,
                      K_THREAD_STACK_SIZEOF(my_stack_area),
                      MY_PRIORITY,
                      NULL);
    
    // 初始化工作项
    k_work_init(&my_work, work_handler);
    
    // 提交到自定义工作队列
    k_work_submit_to_queue(&my_work_q, &my_work);
}

3. 延迟工作项

Zephyr还支持延迟执行的工作项:

#include <zephyr.h>
#include <sys/work_q.h>

struct k_delayed_work delayed_work;

void delayed_work_handler(struct k_work *work)
{
    printk("延迟工作项被执行\n");
}

void main(void)
{
    // 初始化延迟工作项
    k_delayed_work_init(&delayed_work, delayed_work_handler);
    
    // 提交延迟工作项(1秒后执行)
    k_delayed_work_submit(&delayed_work, K_SECONDS(1));
}

4. 工作队列与ISR的配合

典型的中断+工作队列处理模式:

#include <zephyr.h>
#include <sys/work_q.h>

struct k_work isr_work;

void isr_work_handler(struct k_work *work)
{
    // 在线程上下文中处理中断事件
    printk("处理中断事件\n");
}

void my_isr(const void *arg)
{
    // 在ISR中提交工作项
    k_work_submit(&isr_work);
}

void main(void)
{
    // 初始化工作项
    k_work_init(&isr_work, isr_work_handler);
    
    // 连接中断
    IRQ_CONNECT(DT_IRQN(DT_NODELABEL(my_device)),
                2, my_isr, NULL, 0);
    irq_enable(DT_IRQN(DT_NODELABEL(my_device)));
}

5. 工作队列特性比较

特性 系统工作队列 自定义工作队列
预定义
优先级 低(通常) 可自定义
线程资源 共享 专用
使用场景 一般延迟任务 实时性要求高的任务
客服小姐姐(优先添加)

扫描访问店铺

客服微信

扫描添加客服