简易可移植的多任务轮询

TaskStruct

时间片轮询系统

时间片轮询法是一种比较简单易用的系统架构之一,它对于系统中的任务调度算法是分时处理。核心思路是把 CPU 的时间分时给各个任务使用。我们常用的定时方法是定时器,把调度器放在定时中,可以简单的实现时间片轮询法。

需要注意的是,这种方法的前提是执行的 每个任务都是短小精悍的,要不然一个任务执行的时间过长,大于其它任务设置的时间片值,那其它任务就无法保证按它预设的时间片来执行。

尤其需要注意任务中延时的使用,可能会产生不可预料的结果。如果任务内部需要延时的时候,或者说单个任务过长,需要保存任务执行到一半的状态,建议使用状态机切割长任务。

文件结构

polling.c
polling.h

源码

polling.c

#include "polling.h"

/*******************申明区***************************/

static TaskStruct task_list[];//任务组

/*******************可修改区***************************/
/*
简 要:创建任务区
详 细:无
*/
void task1()
{
		static int i=0;
		i++;
		printf("执行任务%d\n",i);
		if(i==10)
		{
				task_ONorOFF(1);
		}
		if(i==20)
		{
				task_ONorOFF(1);
				i=0;
		}
}

void task2()
{
		LED1=~LED1;
}

/*
简 要:创建任务组
详 细:无
*/
static TaskStruct task_list[]=
{
		{1 , 1000, 0, 1000, task1},
		{1 , 500, 0, 500, task2},
		//添加任务
};

/*******************不可修改区***************************/

/*
简 要:任务数量
详 细:无
*/
#define TASKS_MAX 		sizeof(task_list)/sizeof(task_list[0])

/*
简 要:任务调度器
详 细:设置一个1ms的定时器,将函数放置在中断函数里
参 数:无
返回值:无
*/
void task_schedule(void)
{
		for(uint8_t i = 0 ; i < TASKS_MAX ; i++)//逐个任务时间处理,TASKS_MAS任务总数
		{
				if(task_list[i].timer)//距离下一次任务执行时间非0
				{
						task_list[i].timer--;//减去一个时间节拍
						if(task_list[i].timer == 0)	//距离下一次任务执行时间为0
						{
								task_list[i].timer = task_list[i].interval_time;	//重装载任务间隔时间
								task_list[i].run = 1;//任务就绪
						}
				}
		}
}

/*
简 要:任务执行器
详 细:放置mian函数中的whlie循环中,while循环中仅此函数
参 数:无
返回值:无
*/
void task_process(void)
{
		for(uint8_t i = 0 ; i<TASKS_MAX ; i++)//逐个任务处理
		{
				if(task_list[i].enable_flay)//是否为使能任务
				{
						if(task_list[i].run)//是否为就绪态
						{
								task_list[i].run = 0;//就绪态复位
								task_list[i].task();//运行任务函数
						}
				}
		}
}

/*
简 要:开启或关闭一个任务
详 细:无
参 数:任务编号
返回值:无
*/
void task_ONorOFF(uint8_t coding)
{
		if(task_list[coding].enable_flay == 1)//判断是否为开启状态
		{
				task_list[coding].enable_flay = 0;
		}
		else//如果为关闭状态
		{
				task_list[coding].enable_flay = 1;
		}
}

polling.h

#ifndef __POLLING_H
#define __POLLING_H
#include "sys.h"

/*
时间片轮询1.0
作者:nanqi
*/


/*
简 要:任务结构体
详 细:无
*/
typedef struct
{
		uint8_t enable_flay;//任务使能标志位,0不需要运行,1需要运行
		uint16_t timer;//还差多少时间就需要调度这个任务
		uint8_t	run;//任务是否就绪,0未就绪,就绪态
		uint16_t	interval_time;//任务运行的间隔问题,即每隔多久调度一次
		void (*task)(void);//任务回调函数,即要运行的任务函数
}TaskStruct;


/*
简 要:函数申请区
详 细:无
*/
void task_process(void);//任务调度器
void task_schedule(void);//任务执行器
void task_ONorOFF(uint8_t coding);//开启或关闭一个任务

						
#endif

使用说明

task_schedule()

task_schedule():放置于对于型号单片机的中断中,建议设定定时器1ms延时

//定时器9中断服务函数
void TIM1_BRK_TIM9_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM9,TIM_IT_Update)==SET) //溢出中断
	{
			task_schedule();
	}
	TIM_ClearITPendingBit(TIM9,TIM_IT_Update);  //清除中断标志位
}

task_process()

task_process():放置入main函数的while中

int main(void)
{ 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	delay_init(168);		//延时初始化 
	uart_init(115200);	//串口初始化波特率为115200
	TIM9_Int_Init(1000-1,168-1);
	LED_Init();		  		//初始化与LED连接的硬件接口  

	while(1)
	{
		task_process();
	}
}

任务创建

在这里申明出任务的属性,越靠前的任务优先级越高

/*
简 要:创建任务组
详 细:无
*/
static TaskStruct task_list[]=
{
		{1 , 1000, 0, 1000, task1},
		{1 , 500, 0, 500, task2},
		//添加任务
};

任务属性参照

/*
简 要:任务结构体
详 细:无
*/
typedef struct
{
		uint8_t enable_flay;//任务使能标志位,0不需要运行,1需要运行
		uint16_t timer;//还差多少时间就需要调度这个任务
		uint8_t	run;//任务是否就绪,0未就绪,就绪态
		uint16_t	interval_time;//任务运行的间隔问题,即每隔多久调度一次
		void (*task)(void);//任务回调函数,即要运行的任务函数
}TaskStruct;

然后在定义的任务中写出任务具体实现:

/*
简 要:创建任务区
详 细:无
*/
void task1()
{
		static int i=0;
		i++;
		printf("执行任务%d\n",i);
		if(i==10)
		{
				task_ONorOFF(1);
		}
		if(i==20)
		{
				task_ONorOFF(1);
				i=0;
		}
}

void task2()
{
		LED1=~LED1;
}
上一篇:stm32cubeMX配置串口


下一篇:NRF52832学习笔记(12)——UART串口使用