时间片轮询法是一种比较简单易用的系统架构之一,它对于系统中的任务调度算法是分时处理。核心思路是把 CPU 的时间分时给各个任务使用。我们常用的定时方法是定时器,把调度器放在定时中,可以简单的实现时间片轮询法。
需要注意的是,这种方法的前提是执行的 每个任务都是短小精悍的,要不然一个任务执行的时间过长,大于其它任务设置的时间片值,那其它任务就无法保证按它预设的时间片来执行。
尤其需要注意任务中延时的使用,可能会产生不可预料的结果。如果任务内部需要延时的时候,或者说单个任务过长,需要保存任务执行到一半的状态,建议使用状态机切割长任务。
polling.c
polling.h
#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; } }
#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():放置于对于型号单片机的中断中,建议设定定时器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():放置入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; }