ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

小小调度器的优化版本:Tiny Macro OS for MCU

2022-02-21 19:06:30  阅读:319  来源: 互联网

标签:task os Macro void Tiny start 任务 printf OS


Tiny Macro OS

简介

Tiny Macro OS是借鉴了protothread思想的宏定义调度内核。
从各个论坛汲取代码汇总而成,
主要来自于阿莫论坛的smset率先提出的小小调度器,后经过多人优化修改:
https://www.amobbs.com/thread-5508720-2-1.html
本版本是个人在开发中结合自身使用习惯优化后的版本。
GitHub链接

ProtoThread机制

Protothread是专为资源有限的系统设计的一种耗费资源特别少并且不使用堆栈的线程模型,其特点是:

1.以纯C语言实现,无硬件依赖性;
2.极少的资源需求,每个Protothread仅需要2个额外的字节;
3.可以用于有操作系统或无操作系统的场合;
4.支持阻塞操作且没有栈的切换。

使用Protothread实现多任务的最主要的好处在于它的轻量级。
每个Protothread不需要拥有自已的堆栈,所有的Protothread共享同一个堆栈空间,对于RAM资源有限的系统尤为有利。
相对于操作系统下的多任务而言,每个任务都有自已的堆栈空间,这将消耗大量的RAM资源,而每个Protothread仅使用一个变量保存当前函数状态。

时间轮询机制

时间轮询机制是一种比较简单易用的系统架构之一,它对于系统中的任务调度算法是分时处理。核心思路是把 CPU 的时间分时给各个任务使用。
需要注意的是,这种方法的要保证每个任务都是短小精悍的,要不然一个任务执行的时间过长,那其它任务就无法保证按它预设的时间来执行。

tiny macro os

tiny macro os是结合了ProtoThread机制和时间轮询机制的调度内核,每个任务都有单独的时间变量和函数状态变量。
时间变量为全局变量,在软硬件定时器中更新。
函数状态变量为函数内部局部静态变量。只在函数内使用。

移植

移植首先需要在tiny-macro-os.h中修改下列宏定义:

#define TINY_MACRO_OS_TASKS_NUM           3U                //定义使用的主任务数量,最大255个任务
#define TINY_MACRO_OS_TIME_t              unsigned short    //定义时间计数变量的类型,根据最长延迟修改
#define TINY_MACRO_OS_LINE_t              unsigned short    //定义任务切换记录变量的类型,根据最大函数占用行数修改
#define os_SEM_t                          signed short      //信号量类型声明,必须为signed类型
#define os_SEC_TICKS                      1000              //定时器时钟更新频率,每秒钟多少个ticks

然后需要实现一个定时器更新时间变量:

void SysTick_Handler(void)
{
    os_UpdateTimers();
}

使用例子

无参数任务:

os_task os_task_test1(void)
{
    os_task_boot();
    os_task_start();
    static uint8_t i = 0;//任务中定义的会在任务切换前后都使用的局部变量需要使用static定义,不然变量会丢失
    //禁止在os_task_start和os_task_end中使用switch和return;
    while(1) {
        printf("os test1\n");
        os_task_WaitX(1000);
    }
    os_task_end();
}

带参数任务:

os_task os_task_test2(uint8_t params){
    os_task_boot();
    //os_task_boot到os_task_start之间的代码,每次执行任务都会运行,可以在此增加任务复位等功能退出下面正在等待中的小任务
    if(params){
        os_task_Reset();
    }
    os_task_start();
    //禁止使用switch
    while(1){
        printf("os test2:%d\n",params);
        os_task_WaitX(600);
    }
    os_task_end();
}

任务循环调用:

void main()
{
    os_InitTasks();
    while(1){
        os_RunTask(os_task_test1,0);
        os_RunTaskWithParam(os_task_test2,1,1);
        //    os_RunHpTask(os_task_test1,0);
        //    os_RunHpTaskWithParam(os_task_test2,1,1);
    }
}

信号量:

os_SEM_t test;

os_task os_sem_test(void){
    os_task_boot();
    os_task_start();
    os_InitSem(test);
    //禁止使用switch
    while(1){
        os_WaitSem(test,0);
        printf("uart rec\n");
        os_WaitSemX(test,10,1);//第三个参数最好不要为0,不然无法计算时间,变成看这个任务运行几次了。
        if(test == os_TIMEOUT){
            printf("uart timeout\n");
        } else {
            printf("uart rec\n");
        }
    }
    os_task_end();
}

void UART0_IRQHandler()
{
    if(RX){
        os_SendSem(test);
    }
}

子任务:

os_task os_child_task(void){
    os_task_boot();
    os_task_start();
    //禁止使用switch
    os_task_WaitX(500);
    printf("os_child_task 1\n");
    os_task_WaitX(500);
    printf("os_child_task 2\n");
    os_task_WaitX(500);
    printf("os_child_task 3\n");
    os_task_WaitX(500);
    os_task_end();
}

os_task os_father_task(void){
    os_task_boot();
    os_task_start();
    //禁止使用switch
    while(1){
        printf("os_father_task\n");
        os_CallSub(os_child_task);
    }
    os_task_end();
}

标签:task,os,Macro,void,Tiny,start,任务,printf,OS
来源: https://blog.csdn.net/mx1117/article/details/123053454

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有