本期带来的基于stm32时间片轮询的调度机制可以在逻辑中使用,用于需要多个传感器分不同的时间进行调度,我们这里把每一个传感器分为一个任务 统一用调度器进行启动 ,我们需要用到这样的框架 第一,此框架所耗费的内存资源较少 比较适合在内存资源有限且需要多传感器的任务场景中使用,第二,此框架是为裸机专门设计的可以类似于RTOS一样进行任务的调度和挂起等,但创建的任务的所有优先级都是相同的需要人为的设置挂起的时机,第三,用这个框架可以很方便的进行传感器的管理并不需要写一大堆的switch语句,这就是本框架的优点,接下来重点讲解框架的设计思路。

此框架通过结点结构体加管理器结构体构建,通过创建结构体数组进行管理,这样内存就是可预知的,比起用链表就不会产生内存碎片。


#define MAX_TASKS    16    // 最大任务数
#define TASK_ID_MAX  32    // 任务ID最大长度

typedef void (*task_func)(void);

typedef enum {
    TASK_STATE_IDLE = 0,
    TASK_STATE_READY,
    TASK_STATE_RUNNING,
    TASK_STATE_SUSPENDED
} task_state_em;

typedef enum {
    TASK_FALSE = 0,
    TASK_TRUE  = 1
} task_bool_em;

/* 单个任务节点 */
typedef struct {
    uint32_t task_id;          // 唯一标识
    uint32_t period;           // 执行周期
    uint32_t last_time;        // 上次执行时间
    uint32_t task_count;       // 执行次数
    task_state_em state;       // 当前状态
    task_func func;            // 任务函数
    uint8_t  is_used;          // 槽位是否被占用
} task_node_t;

/* 管理器 */
typedef struct {
    task_node_t pool[MAX_TASKS];  // 静态任务池
    uint8_t     task_num;         // 当前任务数
    uint8_t scheduler_enable;
} task_manager_t;

接着就是具体函数的构建

#include "KEY.h"


volatile uint32_t sys_tick_ms;

void SysTick_Handler(void)
{
    sys_tick_ms++;
}
uint32_t get_system_tick()
{
    return sys_tick_ms;
}
//框架的初始化
task_state_em task_Init(task_manager_t *manager)
{
    if (manager == NULL) return TASK_FALSE;
    
    for (int i = 0; i < MAX_TASKS; i++) {
        manager->pool[i].is_used = 0;
        manager->pool[i].state   = TASK_STATE_IDLE;
    }
    manager->task_num = 0;
    return TASK_TRUE;
}

//设备的注册
task_bool_em task_Register(task_manager_t *manager, uint32_t id, task_func func, uint32_t period)
{
    if (manager == NULL || func == NULL || period == 0)
        return TASK_FALSE;
        for (int i = 0; i < MAX_TASKS; i++) {
            if (manager->pool[i].is_used == 0) {
                manager->pool[i].task_id    = id;
                manager->pool[i].func       = func;
                manager->pool[i].period     = period;
                manager->pool[i].last_time  = 0;
                manager->pool[i].task_count = 0;
                manager->pool[i].state      = TASK_STATE_READY;
                manager->pool[i].is_used    = 1;
                manager->task_num++;
                return TASK_TRUE;
            }
        }
        return TASK_FALSE;  // 池满了   
}

/* 根据ID启动/挂起任务 */
task_bool_em task_SetState(task_manager_t *manager, uint32_t id, task_state_em state) 
{
     if(manager == NULL)
         return TASK_FALSE;
        for (int i = 0; i < MAX_TASKS; i++)
        {
            if (manager->pool[i].is_used && manager->pool[i].task_id == id)
            {
            manager->pool[i].state = state;
            return TASK_TRUE;
            }
        }
        return TASK_FALSE;
}
//根据ID删除任务
task_bool_em task_Delete(task_manager_t *manager, uint32_t id)
{

     if(manager == NULL)
        return TASK_FALSE;
    for (int i = 0; i < MAX_TASKS; i++)
    {
        if (manager->pool[i].is_used && manager->pool[i].task_id == id)
        {
            manager->pool[i].is_used = 0;
            manager->task_num--;
            return TASK_TRUE;
        }
    }
    return TASK_FALSE;
}
/* 根据ID获取任务状态 */
task_state_em task_GetState(task_manager_t *manager, uint32_t id)
{
    if(manager == NULL)
        return TASK_STATE_IDLE ;
    for (int i = 0; i < MAX_TASKS; i++)
    {
        if (manager->pool[i].is_used && manager->pool[i].task_id == id)
        {
            return manager->pool[i].state;
        }
    }
    return TASK_STATE_IDLE;
}
/* 根据ID设置任务周期 */
task_bool_em task_SetPeriod(task_manager_t *manager, uint32_t id, uint32_t period)
{
    if(manager == NULL)
        return TASK_FALSE;
    for (int i = 0; i < MAX_TASKS; i++)
    {
        if (manager->pool[i].is_used && manager->pool[i].task_id == id)
        {
            manager->pool[i].period = period;
            return TASK_TRUE;
        }
    }
    return TASK_FALSE;
}
/* 根据ID强制运行任务 */
task_bool_em task_ForceRun(task_manager_t *manager, uint32_t id)
{
    if(manager == NULL)
        return TASK_FALSE;
    for (int i = 0; i < MAX_TASKS; i++)
    {
        if (manager->pool[i].is_used && manager->pool[i].task_id == id)
        {
            manager->pool[i].state = TASK_STATE_RUNNING;
            if (manager->pool[i].func) manager->pool[i].func();
            manager->pool[i].state = TASK_STATE_READY;
            return TASK_TRUE;
        }
    }
    return TASK_FALSE;
}
/* 启动调度器 */
void task_StartScheduler(task_manager_t *manager)
{
    if(manager == NULL) return;
    manager->scheduler_enable = 1;
}
/* 停止调度器 */
void task_StopScheduler(task_manager_t *manager)
{
    if(manager == NULL) return;
    manager->scheduler_enable = 0;
}


/* 调度运行 */
void task_Run(task_manager_t *manager) 
{
    if(manager == NULL ||  manager->scheduler_enable == 0)
         return;
        uint32_t now = get_system_tick();  // 需自行实现
        for (int i = 0; i < MAX_TASKS; i++) 
        { 
                task_node_t *t = &manager->pool[i];

            if (!t->is_used || t->state != TASK_STATE_READY)
            continue;

                if ((now - t->last_time) >= t->period) 
                {
                    t->last_time = now;
                    t->state = TASK_STATE_RUNNING;
                    if (t->func) t->func();
                    t->task_count++;
                    t->state = TASK_STATE_READY;
                }
        }
}

因为我们是裸机的框架因此需要借用系统滴答定时器中断这样时间是很精确的 大多数的裸机调度的框架的时间都是基于系统滴答定时器的,接下来看看演示的效果吧。

#include "stm32f10x.h"// Device header
#include "usart.h"
#include "KEY.h"
#include "LED.h"

task_manager_t LED_TASK_manager;

void LED_TASK(void)
{
	printf("LED_TASK is running\r\n");
	task_SetPeriod(&LED_TASK_manager,2,500);
}
void KEY_TASK(void)
{
    printf("KEY_TASK is running\r\n");
}
void USART_TASK(void)
{
    printf("USART_TASK is running\r\n");
}

void main(void)
{
	SysTick_Config(SystemCoreClock / 1000);  
	led_init();
    UART_init(115200);
    task_Init(&LED_TASK_manager);
    task_Register(&LED_TASK_manager, 1, LED_TASK, 500);
    task_Register(&LED_TASK_manager, 2, KEY_TASK, 2000);
    task_Register(&LED_TASK_manager, 3, USART_TASK, 1000);
    task_StartScheduler(&LED_TASK_manager);
	printf("Task Scheduler Start\r\n");

    while (1)
    {   
       task_Run(&LED_TASK_manager);
    }
    
}

我们这里通过主函数注册了三个任务执行的周期分别是500ms,2000ms和1000ms,我们在id为1的任务函数中重新设置了id为2的执行周期为500ms,可以从打印的结果来看,以上就是关于时间片轮询调度框架的一个构建,鉴于笔者能力有限,如有错误请积极指正。

源码地址:GitHub - yh2004915/stm32- · GitHub

Logo

免费领 150 小时云算力,进群参与显卡、AI PC 幸运抽奖

更多推荐