裸机任务调度框架(时间片轮询 + 事件驱动混合调度)

裸机任务调度框架通常指的是在没有操作系统的情况下,通过某种机制实现多任务的调度。常见的调度方法包括前后台系统、时间片轮询、状态机、协程等。

时间片轮询是比较常见的,通过定时器中断切换任务;状态机适合处理不同状态的任务;协程可以实现协作式多任务;事件驱动则依赖事件触发任务执行。可能还有基于优先级的调度,但裸机下实现复杂。

但是对于各个框架都是各自的优缺点的,时间片轮询实现简单,但实时性不高;状态机适合流程控制,但任务多了管理复杂;协程需要栈管理,可能占用较多内存;事件驱动响应快,但需要事件触发机制。

这个时候我觉得时间片轮询和事件驱动结合可能是个不错的选择,既有时间管理,又能响应外部事件。或者协程方式,但需要处理栈空间。 

我的代码设计思路:

  • 需要选择一个调度框架,比如时间片轮询,用SysTick定时器作为时基,任务函数在循环中按时间片执行
  • 或者使用状态机,每个任务分成多个状态,每次执行一个状态。
  • 或者用协作式调度,任务主动让出CPU
  • 还要考虑到中断处理,使用SysTick中断来更新时间基准,但裸机下可能直接在循环中读取时间戳,减少中断依赖

一、常见裸机任务调度框架

1.1 前后台系统(超级循环)
  • 原理:主循环(后台)轮询任务,中断处理(前台)处理紧急事件。

  • 优点

    • 实现简单,无需复杂调度逻辑。

    • 资源占用极低。

  • 缺点

    • 实时性差,任务可能因阻塞导致响应延迟。

    • 难以处理复杂多任务场景。

1.2 时间片轮询调度
  • 原理:通过定时器中断划分时间片,按固定周期轮询任务。

  • 优点

    • 任务执行时间可控。

    • 支持优先级划分(需手动管理)。

  • 缺点

    • 高优先级任务可能阻塞低优先级任务。

    • 时间片划分不合理会导致任务饥饿。

1.3 状态机调度
  • 原理:每个任务分解为多个状态,通过状态迁移控制执行流程。

  • 优点

    • 逻辑清晰,适合流程化任务(如通信协议)。

    • 非阻塞设计,节省CPU资源。

  • 缺点

    • 状态迁移逻辑复杂,代码维护成本高。

    • 难以实现任务抢占。

1.4 协程(Coroutine)调度
  • 原理:通过手动切换任务上下文(保存/恢复寄存器),实现协作式多任务。

  • 优点

    • 任务切换开销低。

    • 代码结构类似多线程,易于理解。

  • 缺点

    • 需要手动管理栈空间,易出现栈溢出。

    • 协作式调度需任务主动让出CPU。

1.5 事件驱动调度
  • 原理:任务由事件触发(如按键、定时器到期),通过事件队列管理任务执行。

  • 优点

    • 响应速度快,适合异步事件处理。

    • 资源利用率高。

  • 缺点

    • 事件队列管理复杂。

    • 需处理事件优先级和冲突。

二、框架对比和选型

框架类型实时性资源占用复杂度适用场景
前后台系统极低简单控制逻辑
时间片轮询周期性任务(如数据采集)
状态机流程化任务(如协议解析)
协程协作式多任务
事件驱动异步事件处理(如GUI)
最佳选择:时间片轮询 + 事件驱动混合调度
  • 理由

    • 平衡性:时间片轮询确保周期性任务按时执行,事件驱动处理异步请求。

    • 扩展性:支持优先级和动态任务添加。

三、代码实现(重头戏)

3.1 调度器核心数据结构
#include "stm32f10x.h"
#include <stdint.h>

// 任务状态
typedef enum {
    TASK_READY,     // 任务就绪
    TASK_SUSPENDED  // 任务挂起
} TaskState;

// 任务结构体
typedef struct {
    void (*task_func)(void);  // 任务函数
    uint32_t interval;        // 执行间隔(ms)
    uint32_t last_run;        // 上次执行时间
    TaskState state;          // 任务状态
    uint8_t priority;         // 任务优先级(0为最高)
} Task;

#define MAX_TASKS 10  // 最大任务数
static Task task_list[MAX_TASKS];
static uint8_t task_count = 0;

// 系统时间戳(通过SysTick更新)
volatile uint32_t system_ticks = 0;
3.2 调度器初始化
// SysTick初始化(1ms中断)
void SysTick_Init(void) {
    SysTick_Config(SystemCoreClock / 1000);  // 72MHz / 1000 = 72kHz
}

// SysTick中断服务函数
void SysTick_Handler(void) {
    system_ticks++;
}

// 添加任务
uint8_t Scheduler_AddTask(
    void (*task_func)(void),
    uint32_t interval,
    uint8_t priority
) {
    if (task_count >= MAX_TASKS) return 0;

    task_list[task_count] = (Task){
        .task_func = task_func,
        .interval = interval,
        .last_run = system_ticks,
        .state = TASK_READY,
        .priority = priority
    };
    task_count++;
    return 1;
}
3.3 任务调度逻辑
// 按优先级排序任务(冒泡排序)
static void SortTasks(void) {
    for (int i = 0; i < task_count - 1; i++) {
        for (int j = 0; j < task_count - i - 1; j++) {
            if (task_list[j].priority > task_list[j + 1].priority) {
                Task temp = task_list[j];
                task_list[j] = task_list[j + 1];
                task_list[j + 1] = temp;
            }
        }
    }
}

// 任务调度器主循环
void Scheduler_Run(void) {
    while (1) {
        SortTasks();  // 按优先级排序任务

        for (uint8_t i = 0; i < task_count; i++) {
            Task *task = &task_list[i];
            if (task->state != TASK_READY) continue;

            // 检查是否到达执行时间
            if ((system_ticks - task->last_run) >= task->interval) {
                task->task_func();            // 执行任务
                task->last_run = system_ticks;
            }
        }
    }
}
3.4 举个例子
// LED闪烁任务(优先级1)
void Task_LED_Blink(void) {
    static uint8_t led_state = 0;
    GPIO_WriteBit(GPIOA, GPIO_Pin_0, (led_state ^= 1) ? Bit_SET : Bit_RESET);
}

// 串口数据发送任务(优先级0)
void Task_UART_Send(void) {
    static uint8_t counter = 0;
    printf("Counter: %d\n", counter++);
}

int main(void) {
    // 硬件初始化
    HAL_Init();
    SysTick_Init();
    // 初始化GPIO和UART...

    // 添加任务
    Scheduler_AddTask(Task_LED_Blink, 500, 1);  // 500ms间隔,优先级1
    Scheduler_AddTask(Task_UART_Send, 1000, 0); // 1000ms间隔,优先级0

    // 启动调度器
    Scheduler_Run();
    return 0;
}

四、框架的优化与扩展

4.1 动态任务管理
// 挂起任务
void Scheduler_SuspendTask(void (*task_func)(void)) {
    for (uint8_t i = 0; i < task_count; i++) {
        if (task_list[i].task_func == task_func) {
            task_list[i].state = TASK_SUSPENDED;
            break;
        }
    }
}

// 恢复任务
void Scheduler_ResumeTask(void (*task_func)(void)) {
    for (uint8_t i = 0; i < task_count; i++) {
        if (task_list[i].task_func == task_func) {
            task_list[i].state = TASK_READY;
            break;
        }
    }
}
4.2 事件驱动扩展
// 事件队列
#define MAX_EVENTS 10
typedef struct {
    void (*handler)(void);  // 事件处理函数
    uint32_t timestamp;
} Event;

static Event event_queue[MAX_EVENTS];
static uint8_t event_head = 0, event_tail = 0;

// 事件入队
void Event_Post(void (*handler)(void)) {
    if ((event_tail + 1) % MAX_EVENTS != event_head) {
        event_queue[event_tail] = (Event){
            .handler = handler,
            .timestamp = system_ticks
        };
        event_tail = (event_tail + 1) % MAX_EVENTS;
    }
}

// 在调度器中处理事件
void Scheduler_Run(void) {
    while (1) {
        // 处理事件队列
        while (event_head != event_tail) {
            Event *event = &event_queue[event_head];
            event->handler();
            event_head = (event_head + 1) % MAX_EVENTS;
        }

        // 原有任务调度逻辑...
    }
}

五、总结

框架还不够完美,仍需优化,继续改进,期待下一篇哟。

  • 混合调度(时间片轮询 + 事件驱动)

    • 时间片轮询:确保周期性任务(如传感器采集)按时执行。

    • 事件驱动:快速响应外部中断(如按键、通信)。

    • 优先级控制:通过排序实现简单优先级调度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值