Часть 24: Создаем свою RTOS на Arduino (Кооперативная многозадачность)

Да, у нас всего 2 КБ RAM и 16 МГц, но мы можем создать операционную систему реального времени, которая позволит выполнять несколько задач параллельно!

Структура RTOS:

#define MAX_TASKS 8
#define STACK_SIZE 64

// Структура задачи
typedef struct {
    void (*task_func)();
    uint16_t period;
    uint16_t last_run;
    uint8_t priority;
    uint8_t stack[STACK_SIZE];
    uint8_t *sp;
    uint8_t state;  // 0 = остановлена, 1 = готова, 2 = выполняется
} Task;

Task tasks[MAX_TASKS];
uint8_t task_count = 0;

// Добавление задачи
uint8_t add_task(void (*func)(), uint16_t period, uint8_t priority) {
    if (task_count >= MAX_TASKS) return 0;
    
    tasks[task_count].task_func = func;
    tasks[task_count].period = period;
    tasks[task_count].priority = priority;
    tasks[task_count].last_run = millis();
    tasks[task_count].state = 1;
    tasks[task_count].sp = &tasks[task_count].stack[STACK_SIZE - 1];
    
    return task_count++;
}

// Планировщик (вызывается в loop)
void scheduler() {
    uint8_t highest_priority = 255;
    uint8_t selected_task = 255;
    uint32_t current_time = millis();
    
    // Ищем задачу с наивысшим приоритетом, готовую к выполнению
    for (uint8_t i = 0; i < task_count; i++) {
        if (tasks[i].state == 1 && tasks[i].priority < highest_priority) {
            if (current_time - tasks[i].last_run >= tasks[i].period) {
                highest_priority = tasks[i].priority;
                selected_task = i;
            }
        }
    }
    
    if (selected_task != 255) {
        // Выполняем задачу
        tasks[selected_task].state = 2;
        tasks[selected_task].last_run = current_time;
        tasks[selected_task].task_func();
        tasks[selected_task].state = 1;
    }
}

// Пример задачи 1: моргание LED
void task_led() {
    static uint8_t state = 0;
    state = !state;
    digitalWrite(13, state);
}

// Пример задачи 2: чтение датчика
void task_sensor() {
    int val = analogRead(A0);
    Serial.println(val);
}

void setup() {
    Serial.begin(115200);
    pinMode(13, OUTPUT);
    
    add_task(task_led, 500, 1);     // Каждые 500 мс, высокий приоритет
    add_task(task_sensor, 1000, 2); // Каждые 1000 мс, низкий приоритет
}

void loop() {
    scheduler();
    // Можно добавить idle-задачу для низкого приоритета
}

Расширенная RTOS с прерываниями (вытесняющая многозадачность):

; Переключение контекста через таймер
TIMER1_COMPA_vect:
    ; Сохраняем контекст текущей задачи
    PUSH R0
    PUSH R1
    ; ... все регистры
    
    ; Сохраняем SP
    IN R16, SPL
    IN R17, SPH
    STS current_task_sp, R16
    STS current_task_sp+1, R17
    
    ; Выбираем следующую задачу
    CALL scheduler_asm
    
    ; Восстанавливаем SP следующей задачи
    LDS R16, next_task_sp
    LDS R17, next_task_sp+1
    OUT SPL, R16
    OUT SPH, R17
    
    ; Восстанавливаем регистры
    POP R1
    POP R0
    RETI

Вам также может понравиться

About the Author: ардуинчиков

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *