前言

  这个任务调度模块的实现是形成于毕设项目中的,用在STM32中,断断续续跨度2个月实现了一些基本功能,可能后面再做其他项目时会一点点完善起来,也会多学习相关知识来强化模块的实用性和高效性,毕竟用自己自主实现出来的功能还是蛮舒心的。

任务调度模式结构

  整体上的结构属于线性结构,结合链表定时器来实现,我使用的是sysTick这个滴答时钟,1ms的频率,功能比较简单,容易理解。

分片

  分片的模式,主要体现在函数分片时间分片在我之前就有使用在函数中,主要的思路是,把函数功能切片,分为几个小部分,每次执行时按次序执行小部分,对于没有时序要求的函数来说,可以把一个占用CPU大的功能分摊开来实现,从而避免有些地方耗时长的问题。对于时间分片,其实就是定时器的一种应用,实际上,函数分片在执行的时候已经是一种时间分片了,不过现在加上人为的控制在里面了。

  下面是函数分片的一般结构:

void func(char *fos,...){
static char step=0;//顺序控制变量,自由度比较高,可乱序,可循环,可延迟执行
switch(step){
case 0:{
//...
step++;
break;
}
case 1:{
//...
step++;
break;
}
//...
default:{
//step++;//可以借助default实现延时的效果,即跳过几次空白step
break;
} }
return;
}

其中添加的参数变量*fos必要的,因为就是通过传入每个任务的这个标志位来判断是否运行结束,而其他的参数,就得基于具体任务做不一样的处理了。

轮询

  • 运行框图

  可以看到这个框图是一个头尾相连闭环结构,从头节点依次运行到尾节点后再从头循环往复执行下去。

  • 轮询函数
void loop_task(void){
static Task_Obj *tasknode; tasknode=task_curnode->next;//repoint the curnode to the next
if(tasknode==NULL){//tasknode is null,only the headnode have the attr
return;//express the task space is none
}
else if(tasknode->task_type==TYPE_HEAD){//tasknode is headnode
task_curnode=tasknode;
return;
}
else{
if(tasknode->run_type == RUN_WAIT){
//等待型任务,通过ready标志来确定是否执行,否则就跳过
if(!tasknode->ready){
if(task_curnode->next !=NULL){
task_curnode=task_curnode->next;
return;
}
}
}
if(tasknode->task_status==STATUS_INIT){ tasknode->tickstart=HAL_GetTick();//获取tick
tasknode->task_status=STATUS_RUN; }
else if(tasknode->task_status==STATUS_RUN){
if((HAL_GetTick() - tasknode->tickstart) > (uint32_t)tasknode->task_tick){
tasknode->task_name(&(tasknode->task_fos));//run the step task,transfer the fos
tasknode->tickstart+=(uint32_t)tasknode->task_tick;//update the tickstart
}
} }
if(tasknode->task_fos==FOS_FLAG){ tasknode->ready=0;
if(tasknode->waittask!=NULL){
//置位该任务绑定的等待的任务准备运行标志位,标识可以准备运行了
tasknode->waittask->ready=1;
}
//运行结束就删掉该任务
delete_task(tasknode);
}
else if(tasknode->task_fos==FOC_FLAG){
//循环运行该任务
tasknode->task_status=STATUS_INIT;//continue running from start
tasknode->task_fos=0;//RESET fos }
if(task_curnode->next !=NULL){
if(task_curnode->next->run_type==RUN_FORCE) return;//force-type's task else task_curnode=task_curnode->next; } }

其中有几个运行态和标志位

#define FOS_FLAG 99//运行结束标志
#define FOC_FLAG 100//运行结束后再次执行,相当于循环运行
#define TYPE_NOMAL 0//标识一般任务类型
#define TYPE_HEAD 1//标识头任务类型
#define TYPE_END 2//标识尾任务类型
#define RUN_NORMAL 0//一般轮询模式
#define RUN_FORCE 1//强制运行该任务,运行结束才继续下一个任务
#define RUN_WAIT 2//等待指定的任务结束,才可以被运行
#define STATUS_INIT 0//任务的准备阶段,用于获取起始时间
#define STATUS_RUN 1//任务运行阶段
#define STATUS_UNVAILED 2//无效状态

运行时对时间间隔tick的把握还有点问题,这个等待后面有机会优化下。

调度实现

  • 任务链表结构
typedef struct TASK_CLASS{
void (*task_name)(char *taskfos,...);//任务函数
int task_tick;//任务的时间分片间隔
uint32_t tickstart;//起始时间点,每次执行完须加上一个tick
char task_fos;//运行结束标志
char task_type;//任务类型变量
char task_status;//任务状态
char run_type;//运行状态
char ready;//准备运行标志位
struct TASK_CLASS *next;//下一任务
struct TASK_CLASS *waittask;//等待执行的任务
} Task_Obj;
  • 添加任务

    • add_task
    void add_task(void (*taskname)(char *,...),int tasktick,int runtype){//可变参,这里未做处理
    Task_Obj *tasknode,*tmpnode;
    char i; tasknode = (Task_Obj*)malloc(sizeof(Task_Obj)); tasknode->task_name=taskname;
    tasknode->task_tick=tasktick;
    tasknode->task_fos=0;
    tasknode->task_status=STATUS_INIT;//initial status
    tasknode->task_type=TYPE_END; //set the new node to endnode
    tasknode->run_type=runtype;
    tasknode->next=&task_headnode;//the endnode point to the headnode tmpnode=&task_headnode;
    if(task_num==0){
    tmpnode->next=tasknode;
    task_num++;
    return;
    }
    for(i=0;i<task_num;i++){
    tmpnode=tmpnode->next;//reach the endnode
    }
    tmpnode->task_type=TYPE_NOMAL;//turn the last endnode to the normal node
    tmpnode->next=tasknode;
    task_num++;
    }
    • add_wait_task
    void add_wait_task(void (*taskname)(char *),void (*waitname)(char *),int tasktick){
    Task_Obj *tmpnode,*tasknode;
    char i,pos; tmpnode=&task_headnode;
    for(i=0;i<task_num;i++){
    tmpnode=tmpnode->next;//reach the endnode
    if(tmpnode->task_name==taskname){
    pos=i;//获取要等待任务的位置
    break;
    }
    } tasknode = (Task_Obj*)malloc(sizeof(Task_Obj)); tasknode->task_name=waitname;
    tasknode->task_tick=tasktick;
    tasknode->task_fos=0;
    tasknode->task_status=STATUS_INIT;//initial status
    tasknode->task_type=TYPE_END; //set the new node to endnode
    tasknode->run_type=RUN_WAIT;//任务为等待运行
    tasknode->ready=0;
    tasknode->next=&task_headnode;//the endnode point to the headnode tmpnode->waittask=tasknode;//获取新建的等待执行的任务地址,在运行结束后把等待执行的任务的准备运行标志位置1 tmpnode=&task_headnode;
    if(task_num==0){
    tmpnode->next=tasknode;
    task_num++;
    return;
    }
    for(i=0;i<task_num;i++){
    tmpnode=tmpnode->next;//reach the endnode
    }
    tmpnode->task_type=TYPE_NOMAL;//turn the last endnode to the normal node
    tmpnode->next=tasknode;
    task_num++; }
  • 删除任务

    • delete_task(局限性大,只针对当前运行的任务而言)
    void delete_task(Task_Obj *taskobj){
    if(task_curnode->task_type==TYPE_HEAD && task_num < 2){//if curnode is headnode,and tasknum=1
    task_curnode->next=NULL;
    }
    else{
    task_curnode->next=taskobj->next;//repoint the curnode next
    }
    free(taskobj);//free the space of where the taskobj pointed task_num--; }
    • delete_task_withname(删除指定任务名的任务)
    void delete_task_withname(void (*taskname)(char *)){
    Task_Obj *tmpnode,*tmpnode2;
    char i,pos; tmpnode=&task_headnode;
    for(i=0;i<task_num;i++){
    tmpnode=tmpnode->next;//reach the endnode
    if(tmpnode->task_name==taskname){
    pos=i;
    break;
    }
    }
    if(i==task_num) return;
    tmpnode=&task_headnode;
    for(i=0;i<pos+1;i++){
    tmpnode2=tmpnode;
    tmpnode=tmpnode->next;
    }
    if(tmpnode->next==NULL){//if tmpnode is endnode
    tmpnode2->next=&task_headnode;
    }
    else{
    tmpnode2->next=tmpnode->next;//repoint the curnode next
    }
    task_num--;
    free(tmpnode);
    }
  • 初始化任务空间

void non_task(char *taskfos){
return;
} void init_taskspace(void){
task_headnode.task_name=non_task;
task_headnode.task_type=TYPE_HEAD;
task_headnode.task_status=STATUS_UNVAILED;
task_headnode.next=NULL;
task_curnode=&task_headnode;//头节点是没有任务需要执行的
task_num=0;
}
  • 调用实例
add_task(task1,500,RUN_NORMAL);//500ms执行一次task1任务
add_wait_task(task1,task2,500);//task2等待task1结束才会执行,运行的时间间隔为500ms
delete_task_withname(task1);//删除task1任务 while(1){
//...
loop_task();//任务轮询
}

结语

  整体实现说难不难,说简单不简单,但也是我第一次尝试这种偏向系统级应用的代码,而且都没有参照任何其他的资料和代码,完全以自己的对任务的理解和具体项目的需求来一点点实现,希望后面会把这个调度的代码进一步完善成一个通用型的调度方式,也方便后面项目的使用了。

自用纯C语言实现任务调度(可用于STM32、C51等单片机)的更多相关文章

  1. geek青年的状态机,查表,纯C语言实现

    geek青年的状态机,查表,纯C语言实现 1. 问题的提出.抽象 建一,不止是他,不少人跟我讨论过这种问题:怎样才干保证在需求变更.扩充的情况下.程序的主体部分不动呢? 这是一个很深刻和艰难的问题.在 ...

  2. 纯C语言INI文件解析

    原地址:http://blog.csdn.net/foruok/article/details/17715969 在一个跨平台( Android .Windows.Linux )项目中配置文件用 IN ...

  3. 经典数独游戏+数独求解器—纯C语言实现

    "心常乐数独小游戏"(下面简称"本软件")是一款windows平台下的数独游戏软件. 本软件是开源.免费软件. 本软件使用纯C语言编写,MinGW编译,NSIS ...

  4. 不好意思啊,我上周到今天不到10天时间,用纯C语言写了一个小站!想拍砖的就赶紧拿出来拍啊

    花10天时间用C语言做了个小站 http://tieba.yunxunmi.com/index.html 简称: 云贴吧 不好意思啊,我上周到今天不到10天时间,用纯C语言写了一个小站!想拍砖的就赶紧 ...

  5. FastDFS是纯C语言实现,只支持Linux,适合以中小文件为载体的在线服务,还可以冗余备份和负载均衡

    一.理论基础 FastDFS比较适合以中小文件为载体的在线服务,比如跟NGINX(APACHE)配合搭建图片服务器. 分布式文件系统FastDFS FastDFS是纯C语言实现,只支持Linux.Fr ...

  6. 异想家纯C语言矩阵运算库

    Sandeepin最近做的项目中需要在嵌入式芯片里跑一些算法,而这些单片机性能不上不下,它能跑些简单的程序,但又还没到上Linux系统的地步.所以只好用C语言写一些在高级语言里一个函数就解决的算法了, ...

  7. <Win32_20>纯c语言版的打飞机游戏出炉了^_^

    经过昨天的苦战,终于完成了纯C版的打飞机游戏——使用微信打飞机游戏的素材,不过玩法有些不同,下面会有详述 一.概述游戏的玩法.实现效果 1. 游戏第一步,简单判断一下,给你一个准备的时间: 2.选择& ...

  8. 华为OJ机试题目:两个大整数相乘(纯C语言实现两个大整数相乘,两种方法实现大数相乘)

    题目描述: 输出两个不超过100位的大整数的乘积. 输入: 输入两个大整数,如1234567 123 输出: 输出乘积,如:151851741 样例输入: 1234567 123 样例输出: 1518 ...

  9. 关于linux内核用纯c语言编写的思考

    在阅读linux2.6 版本内核的虚拟文件系统和驱动子系统的时候,我发现内核纯用c语言编写其实也是有一点不方便,特别是内核中大量存在了对象的概念,比如说文件对象,描述起来使用对象描述,但是对象在c语言 ...

  10. 纯C语言实现简单封装继承机制

    0 继承是OO设计的基础 继承是OO设计中的基本部分,也是实现多态的基础,C++,C#,Objective-C.Java.PHP.JavaScript等为OO而设计的语言,其语言本身对实现继承提供了直 ...

随机推荐

  1. arduino问题记录

    1.tx.rx只能写,不能读 2.Arduino中文社区

  2. python 循环 类型转换

  3. Unity学习笔记——坐标转换(3)

    通过Transform.Translate移动物体         6个重载:         public void Translate(float x, float y, float z, [De ...

  4. Matlab %陆

    第六章 MATLAB IN ENGINEERING Polynomial Differentiation多项式微分  %幂级数 f(x) = x^3-2x-5; p = [1 0 -2 -5]  %自 ...

  5. 003Java的诞生

    003Java的诞生 1.计算机语言发展史 (1)第一代语言 机器语言 我们都知道计算机的基本计算方式都是基于二进制的方式. 二进制:010111001010110010110100 这种代码是直接输 ...

  6. 【javascript】关于charCodeAt()方法

    在做算法题目leetcode 2283时,看见某些答案会使用charCodeAt(),因为自己没用过,所以作此纪录 描述在 JavaScript 中,charCodeAt() 是一种字符串方法,用于检 ...

  7. 2021.01.08 oss is not defined

    背景: 视频点播使用阿里云的oss(Object storage services),然后总是报错oss is not defined, 在网上搜索了一些文章,基本上都是一模一样的,我也就不吐槽啦(这 ...

  8. 2020.11.14 typeScript声明空间

    在ts中存在两种声明空间: 类型声明空间和变量声明空间. 类型声明空间: 1. class People {} 2. interface People {} 3. type People = {} 变 ...

  9. arcengine标注转注记

    只是将在arcmap中添加注记的方式模拟了一遍,因此,首先显示标注(Label),而后将其转换为注记(Annotation)(Convert Label To Annotation) /******* ...

  10. MySQLdb安装

    yum seach MySQL-Python sudo yum install MySQL-python.x86_64 import MySQLdb