实现简单的多任务轮询(C语言)

  • 前言
  • 总体思路
  • 实现过程
  • 调用示例
  • 完整代码

前言

好久没有做MCU的项目了,最近因为工作需要接手一个STM32的项目,因为项目要求比较简单,也就没有用到操作系统,而是用了简单的状态机+任务轮询的方式。闲暇之余写下这篇简短的博客,记录一下自己的所知所想,也希望对那些刚进入MCU的新手们,能有些许的帮助。

总体思路

利用状态机的方式,在一个循环中不停的去判断每一个任务的执行标识,当判断标识为真时,则执行响应的任务,任务执行结束后及时的清除任务标识。

实现过程

先定义一个任务的结构体,结构体中包含任务的执行函数和是否需要执行的标识。

typedef struct __TASK{int (*func)(void *);       //任务执行的函数,执行时会传入下面的参数void *arg;                      //任务执行时带入的参数int flag;
} task_t;

在定义一个任务组用于管理这些需要被轮询的任务:

typedef struct __TASK_GRP{task_t *task_list;         //需要执行任务集合int list_size;                //list的大小
}taskGrp_t;

下面定义两个宏用于定义和初始化一个任务列表和任务组。注意下面的方法在有些编译器中不支持,目前我知道的就是在keil下的C89就不支持这种方式。

#define TASK_LIST_INIT(name,size)    task_t name[size]={0};
#define TASK_GPR_INIT(name,list,size) \
struct __TASK_GRP name={ \.task_list = list, \.list_size = size, \
};

有些人看到这个肯定有点懵!其实上面的方式就是利用在定义变量时对变量进行初始化,然后再用宏把这个过程包装起来就行,在使用的时候只需要调用宏并传入响应的参数就行。例如:TASK_GPR_INIT(task_group,task_list,TASK_SIZE);
等价于
struct __TASK_GRP task_group={
.task_list = task_list,
.list_size = TASK_SIZE,
};
然后定义几个函数用于对任务组和任务进行操作:

初始化一个任务组,目的和上面提高的两个初始化相同。两种方式调用哪个都可以。

void task_grop_init(taskGrp_t *grp,task_t *list,int size)
{grp->task_list = list;grp->list_size = size;memset(list,0,sizeof(task_t)*size);
}

将要执行的操作函数添加到任务组中相应的任务中。flag标识用于是否默认激活任务。

void task_add_to_list(taskGrp_t *grp,int index,int (*func)(void *),void *arg,int flag)
{grp->task_list[index].func = func;grp->task_list[index].arg = arg;grp->task_list[index].flag = flag;
}

激活索引为index的任务,让其能参与轮询。

void activate_task(taskGrp_t *grp,int index)
{grp->task_list[index].flag = 1;
}

开始任务轮询操作,里面是一个大循环,会一直查找任务状态并执行相应任务。当判断到任务的返回值为1时则认为任务一次执行完成,将关闭任务,只有等待下一次重新激活后,才重新执行相应任务。

void start_polling(struct __TASK_GRP *grp)
{int i=0;if(grp->task_list != NULL){while(1){for(i=0;i<grp->list_size;i++){if((grp->task_list[i].flag)&&(grp->task_list[i].func != NULL)){grp->task_list[i].flag = grp->task_list[i].func(grp->task_list[i].arg) ? 0 : 1;}else{grp->task_list[i].flag = 0;}          }}}
}

调用示例

enum{TASK_1,TASK_2,TASK_3,TASK_SIZE
}TASK_INDEX;TASK_LIST_INIT(task_list,TASK_SIZE);
TASK_GPR_INIT(task_group,task_list,TASK_SIZE);int task1_func(void *arg)
{int retval=0;static int step=0;switch(step){case 0:printf("%s step %d\n",__func__,step);step=1;break;case 1:printf("%s step %d\n",__func__,step);step=2;break;case 2:printf("%s step %d\n",__func__,step);step=0;retval=1;break;}return retval;
}int task2_func(void *arg)
{int retval=0;static int step=0;switch(step){case 0:printf("%s step %d\n",__func__,step);step=1;break;case 1:printf("%s step %d\n",__func__,step);step=2;break;case 2:printf("%s step %d\n",__func__,step);step=0;retval=1;break;}return retval;
}
int task3_func(void *arg)
{int retval=0;static int step=0;switch(step){case 0:printf("%s step %d\n",__func__,step);step=1;break;case 1:printf("%s step %d\n",__func__,step);step=2;break;case 2:printf("%s step %d\n",__func__,step);step=0;retval=1;break;}return retval;
}int main(void)
{task_add_to_list(&task_group,TASK_1,task1_func,NULL,1);task_add_to_list(&task_group,TASK_2,task2_func,NULL,1);task_add_to_list(&task_group,TASK_3,task3_func,NULL,1);start_polling(&task_group);
}

完整代码

task.h

#ifndef __TASK_H__
#define __TASK_H__#define TASK_LIST_INIT(name,size)     task_t name[size]={0};
#define TASK_GPR_INIT(name,list,size) \
struct __TASK_GRP name={ \.task_list = list, \.list_size = size, \
};  typedef struct __TASK{int (*func)(void *);void *arg;                        //任务执行时带入的参数int flag;
} task_t;typedef struct __TASK_GRP{task_t *task_list;           //需要执行任务表int list_size;             //list的大小
}taskGrp_t;extern void task_grop_init(taskGrp_t *grp,task_t *list,int size);
extern void task_add_to_list(taskGrp_t *grp,int index,int (*func)(void *),void *arg,int flag);
extern void activate_task(taskGrp_t *grp,int index);
extern void start_polling(struct __TASK_GRP *grp);
#endif /* __TASK_H__ */

task.c

#include <string.h>
#include "task.h"void task_grop_init(taskGrp_t *grp,task_t *list,int size)
{grp->task_list = list;grp->list_size = size;memset(list,0,sizeof(task_t)*size);
}void task_add_to_list(taskGrp_t *grp,int index,int (*func)(void *),void *arg,int flag)
{grp->task_list[index].func = func;grp->task_list[index].arg = arg;grp->task_list[index].flag = flag;
}void activate_task(taskGrp_t *grp,int index)
{grp->task_list[index].flag = 1;
}void start_polling(struct __TASK_GRP *grp)
{int i=0;if(grp->task_list != NULL){while(1){for(i=0;i<grp->list_size;i++){if((grp->task_list[i].flag)&&(grp->task_list[i].func != NULL)){grp->task_list[i].flag = grp->task_list[i].func(grp->task_list[i].arg) ? 0 : 1;}else{grp->task_list[i].flag = 0;}          }}}
}

main.c

#include <stdio.h>
#include "task.h"enum{TASK_1,TASK_2,TASK_3,TASK_SIZE
}TASK_INDEX;TASK_LIST_INIT(task_list,TASK_SIZE);
TASK_GPR_INIT(task_group,task_list,TASK_SIZE);int task1_func(void *arg)
{int retval=0;static int step=0;switch(step){case 0:printf("%s step %d\n",__func__,step);step=1;break;case 1:printf("%s step %d\n",__func__,step);step=2;break;case 2:printf("%s step %d\n",__func__,step);step=0;retval=1;break;}return retval;
}int task2_func(void *arg)
{int retval=0;static int step=0;switch(step){case 0:printf("%s step %d\n",__func__,step);step=1;break;case 1:printf("%s step %d\n",__func__,step);step=2;break;case 2:printf("%s step %d\n",__func__,step);step=0;retval=1;break;}return retval;
}
int task3_func(void *arg)
{int retval=0;static int step=0;switch(step){case 0:printf("%s step %d\n",__func__,step);step=1;break;case 1:printf("%s step %d\n",__func__,step);step=2;break;case 2:printf("%s step %d\n",__func__,step);step=0;retval=1;break;}return retval;
}int main(void)
{task_add_to_list(&task_group,TASK_1,task1_func,NULL,1);task_add_to_list(&task_group,TASK_2,task2_func,NULL,1);task_add_to_list(&task_group,TASK_3,task3_func,NULL,1);start_polling(&task_group);
}

实现简单的多任务轮询(C语言)相关推荐

  1. 实现一个简单的长轮询

    分析一下长轮询的实现方式 现在各大中间件都使用了长轮询的数据交互方式,目前比较流行的例如Nacos的配置中心,RocketMQ Pull(拉模式)消息等,它们都是采用了长轮询方的式实现.就例如Naco ...

  2. 在verto_communicator中添加视频floor轮询功能

    只是实现了简单的视频轮询功能,还需要修改完善!!! 1.在src/partials/chat.html中添加 <div><p>{{num}}</p><butt ...

  3. 多个ajax分别实现实现长轮询,ajax长轮询、轮询应用和介绍

    ####什么是轮询 轮询是指客户端定时向服务器发送ajax请求,服务器接到请求后马上返回响应信息并关闭连接. ####轮询的简单实现 仅仅是说出定义来,好像很模糊,代码更加直观一些,下面就简单写一下轮 ...

  4. mysql长轮询_【系列一】ajax长轮询、轮询应用和介绍

    前言 本文是系列文章,主要介绍客户端浏览器和服务器端的通信,当然,客户端和服务器端通信有很多方式.本系列文章主要是讲不间断通信方式!不间断通信就是通信没有停止,一直进行.系列一文章主要是讲轮询和长轮询 ...

  5. 单片机开发-软件架构与系统设计(工程实现使用的也是轮询系统、前后台系统和多任务系统)

    目录 单片机开发1 轮询系统: 概述 详述 前后台系统 概述 详述 单片机开发1 单片机开发可以分为程序裸跑与多任务. 在单片机的工程使用中,可以分为裸机系统和多任务系统. 裸机系统一般被叫做裸跑,大 ...

  6. 嵌入式操作系统专题《基础概念1@轮询系统、前后台系统、多任务系统的区别》

    轮询系统:即在裸机编程时,先初始化相关硬件,让主程序在一个死循环里面不断循环,顺序地处理各种事件.不能说轮询是低端的,轮询系统是一种非常简单的软件结构,但适用于仅需要顺序执行代码且不需要外部事件来驱动 ...

  7. php pcntl 进程池_PHP 进程池与轮询调度算法实现多任务的示例代码

    phper 请了解进程调度策略,CPU 时间片,进程控制[创建,销毁,回收,进程信号]与及进程运行流程和基本的进程组,信号中断原理,以及进程之间的关系. 关于进程的更多内容可参考本人前面撸过的文章或是 ...

  8. 基于PHP实现一个简单的在线聊天功能(轮询ajax )

    基于PHP实现一个简单的在线聊天功能(轮询ajax ) 一.总结 1.用的轮询ajax 二.基于PHP实现一个简单的在线聊天功能 一直很想试着做一做这个有意思的功能,感觉复杂的不是数据交互和表结构,麻 ...

  9. mysql 长轮询_基于HTTP长轮询实现简单推送

    应用场景:设备为安卓.PC以及服务器,要求PC端能够单向给移动端发送消息指令,安卓端解析消息,进行后续处理动作.其中安卓端为基于Phonegap开发,说白了,就是HTML+JS. 规模:正常应用为20 ...

最新文章

  1. Nature:新聘“诺奖级泰斗”研究揭示大脑中执行不同认知功能环路之间的协同作用
  2. 三星专业级360度视频拍摄设备登场,能直接传输3D VR视频
  3. Tecplot云图锯齿状边界解决办法
  4. Solr的学习使用之(三)IKAnalyzer中文分词器的配置
  5. 一文了解Innodb中的锁
  6. ctype.h(c标准库)
  7. windows2008不能显示图片缩略图设置
  8. CentOS 7.4 安装Teamviewer 14
  9. CC2530射频通信
  10. 修改hosts文件并保存
  11. 远程桌面无法复制粘贴问题
  12. MOS管、IGBT、BJT的区别
  13. 免费金融数据API(基金,股票),基金股票网格交易模拟服务
  14. Android 国内集成使用谷歌地图
  15. 安卓开发必须会的技能!Android性能优化最佳实践,知乎上转疯了!
  16. 安卓开机自启动app
  17. html 怎么检测ie浏览器的最高版本,检测是否为IE浏览器及IE浏览器的版本
  18. 组件的生命周期,小程序如何引入第三方ui框架
  19. 邹小强老师的个人目标管理分享课
  20. 普通话测试范读作品14号-和时间赛跑

热门文章

  1. 水果店行业前景分析,水果店好干吗
  2. MES生产效率:实现智能制造的关键技术
  3. android手机时间自动同步
  4. 圣诞节快到啦,我可以有python圣诞树词云吗?(中英文版及代码)
  5. 【python圣诞树】圣诞节来了,还不快给女友来画一棵属于她的圣诞树
  6. Informatica PowerCenter 简介(二)
  7. 核密度估计python_核密度估计丨数析学院
  8. MySQL系列---事务与锁详解
  9. 简述DAS,NAS,SAN
  10. 【文献阅读】 Deep Learning-Based Channel Estimation in OFDM Systems