好久没有做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;ilist_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
#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;ilist_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
#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);
}