实现简单的多任务轮询(C语言)
实现简单的多任务轮询(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语言)相关推荐
- 实现一个简单的长轮询
分析一下长轮询的实现方式 现在各大中间件都使用了长轮询的数据交互方式,目前比较流行的例如Nacos的配置中心,RocketMQ Pull(拉模式)消息等,它们都是采用了长轮询方的式实现.就例如Naco ...
- 在verto_communicator中添加视频floor轮询功能
只是实现了简单的视频轮询功能,还需要修改完善!!! 1.在src/partials/chat.html中添加 <div><p>{{num}}</p><butt ...
- 多个ajax分别实现实现长轮询,ajax长轮询、轮询应用和介绍
####什么是轮询 轮询是指客户端定时向服务器发送ajax请求,服务器接到请求后马上返回响应信息并关闭连接. ####轮询的简单实现 仅仅是说出定义来,好像很模糊,代码更加直观一些,下面就简单写一下轮 ...
- mysql长轮询_【系列一】ajax长轮询、轮询应用和介绍
前言 本文是系列文章,主要介绍客户端浏览器和服务器端的通信,当然,客户端和服务器端通信有很多方式.本系列文章主要是讲不间断通信方式!不间断通信就是通信没有停止,一直进行.系列一文章主要是讲轮询和长轮询 ...
- 单片机开发-软件架构与系统设计(工程实现使用的也是轮询系统、前后台系统和多任务系统)
目录 单片机开发1 轮询系统: 概述 详述 前后台系统 概述 详述 单片机开发1 单片机开发可以分为程序裸跑与多任务. 在单片机的工程使用中,可以分为裸机系统和多任务系统. 裸机系统一般被叫做裸跑,大 ...
- 嵌入式操作系统专题《基础概念1@轮询系统、前后台系统、多任务系统的区别》
轮询系统:即在裸机编程时,先初始化相关硬件,让主程序在一个死循环里面不断循环,顺序地处理各种事件.不能说轮询是低端的,轮询系统是一种非常简单的软件结构,但适用于仅需要顺序执行代码且不需要外部事件来驱动 ...
- php pcntl 进程池_PHP 进程池与轮询调度算法实现多任务的示例代码
phper 请了解进程调度策略,CPU 时间片,进程控制[创建,销毁,回收,进程信号]与及进程运行流程和基本的进程组,信号中断原理,以及进程之间的关系. 关于进程的更多内容可参考本人前面撸过的文章或是 ...
- 基于PHP实现一个简单的在线聊天功能(轮询ajax )
基于PHP实现一个简单的在线聊天功能(轮询ajax ) 一.总结 1.用的轮询ajax 二.基于PHP实现一个简单的在线聊天功能 一直很想试着做一做这个有意思的功能,感觉复杂的不是数据交互和表结构,麻 ...
- mysql 长轮询_基于HTTP长轮询实现简单推送
应用场景:设备为安卓.PC以及服务器,要求PC端能够单向给移动端发送消息指令,安卓端解析消息,进行后续处理动作.其中安卓端为基于Phonegap开发,说白了,就是HTML+JS. 规模:正常应用为20 ...
最新文章
- Nature:新聘“诺奖级泰斗”研究揭示大脑中执行不同认知功能环路之间的协同作用
- 三星专业级360度视频拍摄设备登场,能直接传输3D VR视频
- Tecplot云图锯齿状边界解决办法
- Solr的学习使用之(三)IKAnalyzer中文分词器的配置
- 一文了解Innodb中的锁
- ctype.h(c标准库)
- windows2008不能显示图片缩略图设置
- CentOS 7.4 安装Teamviewer 14
- CC2530射频通信
- 修改hosts文件并保存
- 远程桌面无法复制粘贴问题
- MOS管、IGBT、BJT的区别
- 免费金融数据API(基金,股票),基金股票网格交易模拟服务
- Android 国内集成使用谷歌地图
- 安卓开发必须会的技能!Android性能优化最佳实践,知乎上转疯了!
- 安卓开机自启动app
- html 怎么检测ie浏览器的最高版本,检测是否为IE浏览器及IE浏览器的版本
- 组件的生命周期,小程序如何引入第三方ui框架
- 邹小强老师的个人目标管理分享课
- 普通话测试范读作品14号-和时间赛跑