找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

3163

积分

1

好友

425

主题
发表于 昨天 01:10 | 查看: 1| 回复: 0

在进行嵌入式设备开发时,一个清晰、高效的软件框架是成功的一半。今天要分享的,就是一个在单片机(MCU)上广泛使用的通用调度器框架——基于任务和事件的OSAL调度器。

OSAL,全称操作系统抽象层(Operating System Abstraction Layer)。这个概念最初由德州仪器(TI)在其ZigBee协议栈Z-Stack中引入。严格来说,它并非一个完整的操作系统,但它巧妙地实现了一套事件驱动的任务调度机制,为资源受限的单片机编程提供了结构化的解决方案。

在这个框架中,事件(Event)是最基本的执行单位,而多个相关的事件则组合成一个任务(Task)。整个调度过程可以概括为:当某个事件(比如定时器超时、收到数据)发生时,OSAL负责将这个事件分配给能够处理它的任务;接着,任务会判断事件的类型,并调用对应的事件处理函数来完成具体操作。

其核心工作流程如下图所示:

OSAL事件与任务分配机制示意图

这个OSAL调度器主要实现了两大核心功能:任务调度时间管理

  • 任务调度:它通过一个任务事件数组 tasks_events 来管理各个任务的状态,并通过任务处理函数数组 tasks_arr 来关联具体的处理逻辑。开发者可以使用 osal_set_event()osal_clear_event() 函数来动态设置或清除某个任务的事件标志,从而实现任务的立即执行或取消。
  • 时间管理:OSAL通常利用MCU的硬件定时器(如STM32的SysTick)作为时间基准,在此之上虚拟出多个软件定时器。通过 osal_start_timer() 等函数,可以方便地设置延时任务事件,实现了周期或单次触发的定时功能。

这套调度器的代码结构清晰,主要由以下几组C/C++源文件构成:

OSAL调度器相关源文件列表

  • osal.cosal.h:这是调度的核心,实现了任务的注册、事件循环调度,并对外提供了事件设置/清除的接口函数。
  • osal_clock.cosal_clock.h:负责与硬件时钟对接,更新系统时基,并检查软件定时器是否超时。
  • osal_timers.cosal_timers.h:采用链表管理所有的软件定时器实体,提供了启动和停止定时器的底层操作。

OSAL调度器如何使用?

理解其执行流程是使用的第一步。下面的流程图清晰地展示了从初始化到事件处理的完整过程:

OSAL系统任务调度流程图

系统启动后,首先进行板级外设初始化和OSAL任务初始化(通常在 main 函数中完成)。随后,程序进入主循环,不断调用 run_system() 函数。这个函数会更新定时器、查找就绪的任务事件,并执行对应的处理函数,执行完毕后再清除事件标志。

run_system() 的核心实现逻辑如下,它展示了如何查找就绪任务并安全地调用事件处理函数:

void run_system(void) {
    unsigned char idx = 0;
    osal_time_update(); //更新系统时间,查找定时器任务
    do {
        if (tasks_events[idx]) break; //查找当前就绪的任务事件
    } while (++idx < tasks_cnt);
    if (idx < tasks_cnt) { //当前有任务就绪
        unsigned short events;
        _disable_irq();
        events = tasks_events[idx];
        tasks_events[idx] = 0;
        _enable_irq();
        events = (tasks_arr[idx])(idx, events); //调用事件处理函数
        _disable_irq();
        tasks_events[idx] |= events; //保存未处理的事件
        _enable_irq();
    }
}

实战:添加一个看门狗任务

假设我们需要添加一个独立看门狗(IWDG)任务,用于监控系统运行并定时“喂狗”。我们可以按以下步骤操作:

  1. osal.h 中为看门狗任务定义一个唯一的任务ID,例如 IWDG_TASK_ID
  2. 创建任务源文件 iwdg_task.c 和头文件 iwdg_task.h。在头文件中定义该任务所包含的事件,例如定时喂狗事件和复位事件。

看门狗任务头文件宏定义示例

  1. iwdg_task.c 中实现任务初始化函数和事件处理函数。每个任务都必须提供这两个标准接口。

看门狗任务初始化和处理函数实现

iwdg_task_init() 函数中,我们通过 register_task_array() 将任务ID与处理函数 iwdg_task() 绑定,初始化硬件看门狗外设,最后调用 osal_start_timer() 启动一个周期性的喂狗定时事件。

关键API接口

在实际开发中,以下几个API函数会被频繁使用:

  • 立即事件管理
    osal_set_event与osal_clear_event函数声明
    osal_set_event(task_id, event_flag)osal_clear_event(task_id, event_flag) 用于立即设置或清除某个任务的事件。事件一旦被设置,在下次 run_system() 循环中就会立即得到执行。

  • 定时器事件管理
    osal_start_timer与osal_stop_timer函数声明
    osal_start_timer(task_id, event_id, timeout_value, reload_timeout_value)osal_stop_timer(...) 用于管理延时任务。timeout_value 是首次执行的超时时间,reload_timeout_value 是后续周期执行的重载时间。若将重载时间设为0,则该定时事件仅触发一次。

需要说明的是,原生的TI OSAL还包含一套消息队列机制,用于任务间通信。但为了让调度器更加轻量、易于理解和移植,本文分享的这个版本暂未集成此机制。多个任务之间的数据交换,目前仍通过共享全局变量(即共享内存)的方式来实现。

开源实战与获取

这个基于任务和事件的OSAL调度器,已经应用在多个实际物联网设备端的MCU项目中,证明了其稳定性和实用性。

完整的项目源码已开源,你可以通过以下地址获取并深入了解:

如果你正在为单片机项目寻找一个结构清晰、不依赖复杂RTOS的轻量级调度方案,不妨试试这个OSAL框架,或许它能为你带来全新的开发体验。




上一篇:IEEE发布MyTerms标准,机器可读隐私条款或将重构Cookie机制
下一篇:基于STM32与OSAL的开源物联网中控模块设计:集成SI4432/NRF24L01无线通信
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-2-7 10:13 , Processed in 0.422303 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表