更新:
原文已经搬运至网站:https://www.link2sea.com/archives/386,后续也将在该网站进行更新。
查看博主更多文章请前往:https://www.link2sea.com/。
下面是原文:
原文:
哈哈,开个玩笑,谈不上是操作系统,算是个程序时间分片控制的程序(控制每段程序的执行时间间隔),没有中断,每个任务没有栈,没有优先级,没有信号量、邮箱、互斥,更没有内存管理。也是去年写的程序,跑在STM32上的,用的 hal 库,不过也可以移植。程序很简单,就是个链表完成任务的创建,因为没用到任务的删除,所以就没写。
最初的需求是这样的:我有3个程序块(下文以函数代替)需要执行,每个执行的时间间隔是不一样的,比如我要7ms执行函数A,30ms执行一次函数B, 50ms执行一次函数C。每个函数执行时间都很短,肯定是远小于7ms的。
于是乎,便有了下边的程序,先是测试的example.c,一个是task.c,一个是task.h。
example.c 这个文件是临时写的,为了方便看懂任务的使用方法,一定注意每个任务函数都不是死循环,不能被阻塞。
//文件名:example.c
#include "task.h"
void MAIN_A_TASK(void);
void MAIN_B_TASK(void);
void MAIN_C_TASK(void);
int main(void)
{
TASK_LinkCreat();
TASK_Creat(7, MAIN_A_TASK); // 时间为 7 ms,函数为 MAIN_A_TASK
TASK_Creat(30, MAIN_B_TASK); // 时间为 30 ms,函数为 MAIN_B_TASK
TASK_Creat(50, MAIN_C_TASK); // 时间为 50 ms,函数为 MAIN_C_TASK
while(1)
{
TASK_Switching();
}
}
void MAIN_A_TASK(void)
{
// 添加 A 任务代码,注意不要 while(1),要可以顺序执行完,不能阻塞
}
void MAIN_B_TASK(void)
{
// 添加 B 任务代码,注意不要 while(1),要可以顺序执行完,不能阻塞
}
void MAIN_C_TASK(void)
{
// 添加 C 任务代码,注意不要 while(1),要可以顺序执行完,不能阻塞
}
void TASK_IDLE(void)
{
// 添加 空闲状态 任务代码,注意不要 while(1),要可以顺序执行完,不能阻塞
// 注意 此函数可以不需要,在 task.c 中有定义,若需要则注意此函数名不能改变
}
接下来是task.c
/**
******************************************************************************
* 文件: task.c
* 作者: SUST 陶亚凡
* 版本: V1.0
* 时间: 2017-4-17
* 摘要: 任务控制文件
******************************************************************************
* 说明: 对多任务并行执行的一点理解和尝试,比较青涩
*
*
******************************************************************************
*
******************************************************************************
*/
#include "task.h"
#include <stdlib.h>
task_link_p task_h = NULL;
/**
* 摘要: 任务链表创建
* 输入: 无
* 返回: 任务链表头指针
* 说明: 创建的链表有一个空闲任务,任务链表为循环链表,即最后一个指向第一个
*/
void TASK_LinkCreat(void)
{
task_h = malloc(sizeof(task_link_t));
task_h->start_time = CURRENT_TIME();
task_h->interval_time = 0;
task_h->fun_p = TASK_IDLE;
task_h->next = task_h;
}
/**
* 摘要: 空闲任务
* 输入: 无
* 返回: 无
* 说明: 此处不需要更改,若需要可在主程序中定义
*/
__weak void TASK_IDLE(void)
{
return;
}
/**
* 摘要: 创建任务
* 输入: interval_time: 执行的时间间隔(ms)
funp: 任务执行函数(返回值为void,输入值为void)
* 返回: 无
* 说明:
*/
void TASK_Creat(uint32_t interval_time, void(*fun_p)(void))
{
task_link_p p_task = task_h;
while(p_task->next != task_h)
p_task = p_task->next;
p_task->next = malloc(sizeof(task_link_t));
p_task->next->start_time = CURRENT_TIME();
p_task->next->interval_time = interval_time;
p_task->next->fun_p = fun_p;
p_task->next->next = task_h;
}
/**
* 摘要: 任务切换
* 输入: 无
* 返回: 无
* 说明: 任务循环执行
*/
void TASK_Switching(void)
{
static task_link_p p_task = NULL;
uint32_t tick = 0;
p_task = p_task==NULL ? task_h : p_task;
tick = CURRENT_TIME();
if(tick - p_task->start_time >= p_task->interval_time)
{
p_task->fun_p();
p_task->start_time = tick;
}
p_task = p_task->next;
}
接着是task.h,这里有一点要注意,就是define这一句话,在HAL库中得到的是以ms为精度的时间,所以创建任务的时间即为ms为单位的~若移植到其他平台,需要把HAL_GetTick()改成别的获取当前时间的函数。
#ifndef TASK_H_
#define TASK_H_
#include "stm32f4xx_hal.h"
#define CURRENT_TIME() HAL_GetTick()
typedef struct tasklink
{
uint32_t start_time;
uint32_t interval_time;
void (*fun_p)(void);
struct tasklink * next;
}task_link_t, *task_link_p;
extern task_link_p task_h;
void TASK_LinkCreat(void);
void TASK_IDLE(void);
void TASK_Creat(uint32_t interval_time, void(*fun_p)(void));
void TASK_Switching(void);
#endif /* TASK_H_ */
好了,也是一篇怀旧篇的博客。去年做 robomaster 时我做的基地,当时需要的几个任务分别是50ms打印一次调试信息,7ms接受一次遥控器发过来的数据,并对基地的移动做一次控制,30ms做一次云台控制。我做的基地最后也算发挥了一下作用吧,最后还是小组都没出现,还是很遗憾了,几年都没有好成绩,导致今年学校干脆不然参加比赛了。。