单片机时间片轮询任务调度的实现方法

单片机时间片轮询任务调度的实现方法

编码文章call10242025-09-11 15:45:482A+A-

这是一个非常实用的单片机时间片轮询任务的程序,在51 stc等小容量单片机上也能非常好的执行。每新增一个任务,仅需要新增6个字节的变量来管理,非常小巧。

具有新增任务和删除任务的功能。

新增任务具有一次执行和循环执行两种模式。

//  TASKPROCES.h  头文件

#ifndef __TASKPROCES_H__
#define __TASKPROCES_H__


#define TASKS_MAX    10   //最大可运行任务数

typedef  void (*TaskHook)(void);

void TaskRemarks(void);
void TaskProcess(void);
void Create_Task(uint16_t Time_Cnt,uint16_t Reload, TaskHook task);
void Delete_Task(TaskHook   task);
void Init_TaskList(void);
#endif

在头文件中有一个地方需要注意

#define TASKS_MAX 10 //最大可运行任务数

通过这个宏可以设置本程序可以执行最大多少个任务。

接下来就是 TASKPROCES.c 文件,对这几个函数的具体实现了

//  TASKPROCES.c  C文件
typedef struct 
{
    uint8_t   Run;               // 程序运行标记:0-不运行,1运行  置1时可以运行程序了
    uint16_t  Timer;             // 计时器计数值,看定时器调度时间
    uint16_t  TimeReset;         // 为0时不能重复调用
    TaskHook  task_handle;       // 要运行的任务函数
} TASK_COMPONENTS;               // 别名

TASK_COMPONENTS    TaskComps[ TASKS_MAX ];

/*******************************************************************************
函 数 名:  void Init_TaskList(void)
输入参数:  
返回参数:  
功能描述:  初始化任务结构体
*******************************************************************************/
void Init_TaskList(void)
{
	  uint8_t id = 0;
	  for (id = 0;id < TASKS_MAX; id++)
	  {
			 TaskComps[id].Run = FALSE;         // 首先停止
			 TaskComps[id].Timer = 0;           // 计数值
			 TaskComps[id].TimeReset = 0;       // 重装值
			 TaskComps[id].task_handle = 0;     // 函数名,指针类型
		}
}
/*******************************************************************************
函 数 名:  void Create_Task(uint16_t Time_Cnt,uint16_t Reload, TaskHook task)
输入参数:  
返回参数:  
功能描述:  创建定时任务。
*******************************************************************************/
void Create_Task(uint16_t Time_Cnt,uint16_t Reload, TaskHook task)
{
	 uint8_t id;
	 for (id = 0;id < TASKS_MAX; id++)
	 {
		  if (TaskComps[id].task_handle == 0) 
			{ id += 99;}
	 }
	 id -= 100;
	 TaskComps[id].Run = FALSE;         // 首先停止
	 TaskComps[id].Timer = Time_Cnt;    // 计数值
	 TaskComps[id].TimeReset = Reload;  // 重装值
	 TaskComps[id].task_handle = task;  // 函数名,指针类型
}
/*******************************************************************************
函 数 名:  void Delete_Task(TaskHook   task)
输入参数:  
返回参数:  
功能描述:  删除(取消)定时任务。
*******************************************************************************/
void Delete_Task(TaskHook   task)
{
	 uint8_t id = 0;
	
	 if (task == 0)
		 return;
	 
	 for (id = 0;id < TASKS_MAX; id++)
	 {
	    if (TaskComps[id].task_handle == task)
				 id += 99;
	 }
	 if (id < 100)  //没有匹配的任务
       return;
     id -= 100;	 
	 TaskComps[id].Run = FALSE;         // 首先停止
	 TaskComps[id].Timer = 0;           // 计数值
	 TaskComps[id].TimeReset = 0;       // 重装值
	 TaskComps[id].task_handle = 0;     // 函数名,指针类型
	 
	 while ((id + 1) < TASKS_MAX)
	 {
		 TaskComps[id].Run = TaskComps[id + 1].Run;        
		 TaskComps[id].Timer = TaskComps[id + 1].Timer;         
		 TaskComps[id].TimeReset = TaskComps[id + 1].TimeReset;    
		 TaskComps[id].task_handle = TaskComps[id + 1].task_handle;    
	   id++;
	 }
}


/*******************************************************************************
函 数 名:  void TaskRemarks(void)
输入参数:  
返回参数:  
功能描述:  在定时器中断中调用此函数
*******************************************************************************/
void TaskRemarks(void)
{
    uint8_t i;

    for (i=0; i < TASKS_MAX; i++)        // 逐个任务时间处理
    {
        if (TaskComps[i].Timer)          // 时间不为0
        {
           TaskComps[i].Timer--;         // 减去一个节拍
           if (TaskComps[i].Timer == 0)  // 时间减完了
           {
						 // 有值时才能继续赋值,产生下次触发
             TaskComps[i].Timer = TaskComps[i].TimeReset;    // 恢复计时器值,从新下一次
             TaskComps[i].Run = TRUE;                        // 任务可以运行
           }
        }
   }
}

/*******************************************************************************
函 数 名:  TaskProcess()
输入参数:  
返回参数:  
功能描述:  遍历任务标志
*******************************************************************************/
uint8_t task_cnt = 0;
void TaskProcess(void)
{
	if (TaskComps[task_cnt].Run == TRUE)     // 时间不为0
	{
			 TaskComps[task_cnt].task_handle();  // 运行任务
			 TaskComps[task_cnt].Run = FALSE;    // 标志清0
	}
	if (++task_cnt > TASKS_MAX)
		task_cnt = 0;
     
}

//Delete_Task 删除(取消)定时任务。函数中的for循环说明

for (id = 0;id < TASKS_MAX; id++)

{

if (TaskComps[id].task_handle == task)

id += 99; //使id 大于TASKS_MAX 不满足循环条件

}

if (id < 100) //没有匹配的任务

return;

id -= 100; //减去100,可以知道id循环到几的时候if成立的


假设TASKS_MAX定义可以运行任务数量小于100(超过之后需要改变一些写法了)这是前提。

1.在for循环中,if条件成立时,对变量id加上99,目的是让它立即退出循环,进行下一步动作。

而for循环退出时,会对变量id再次自加“id++”之后判断“id < TASKS_MAX”。这就是之后“i-=100”

的原因。

2.退出for循环之后,如果id变量没有超过100,那就是之前for循环中if条件一直没能成立,退出当前函数

3.如果大于100了,那就说明在for循环中if条件成立过了,

id减去100就可以知道是循环第几次的时候if条件成立的

4.这样就能通过id的值知道if条件是否成立以及成立时的id值了

//Create_Task 创建任务函数中的for循环说明

for (id = 0;id < TASKS_MAX; id++)

{

if (TaskComps[id].task_handle == 0)

{ id += 99;}

}

id -= 100;

TaskComps[id].Run = FALSE; // 首先停止

TaskComps[id].Timer = Time_Cnt; // 计数值

TaskComps[id].TimeReset = Reload; // 重装值

TaskComps[id].task_handle = task; // 函数名,指针类型


创建任务和删除定时任务的for循环逻辑一样,创建任务时需要确定当前结构体数组有没有空位

if (TaskComps[id].task_handle == 0) 查找没有被赋予指针的位置,只有当这个函数指针

为空时才表示可以使用。

如果这个TaskComps[0],TaskComps[1],TaskComps[2]均已赋值,TaskComps[3],TaskComps[4]...

没有赋值if条件就会一直成立,id会一直自加直到“id < TASKS_MAX”条件不成立而退出。

所以

1.当id循环一旦查找到空指针位置时,自加99(for循环的i++还会加1)后退出循环

2.接下来直接将id减去100可以知道id在for循环中值为多少时if条件成立的,即此编号指针为空

3.对该空指针赋值,实现添加任务



以下是主程序中的内容,注释已经非常详细,不再赘述。

需要注意的是,一定要将TaskRemarks();放在定时器中断中去执行,将定时器中断

配置为1ms,当然也可以是其它值。

void fun1(void)
{
	LED = ~LED;
}
void fun2(void)
{
	//放置需要进行的任务
}
/*******************************************************************************
函 数 名:  void main(void)
输入参数:  
返回参数:  
功能描述:  遍历任务标志
*******************************************************************************/
void main(void)
{
	Sys_Bsp_Init();           //初始化一个1ms的定时器  定时器中调用TaskRemarks();
	Init_TaskList();          //初始化任务结构体
	Create_Task(200,200,fun1);//fun1任务 200ms后执行 执行后按照200ms周期持续运行
	Create_Task(100,0,fun2);  //fun2任务 100ms后执行,仅执行一次
	//Delete_Task(fun2);      //可以删除任务,将结构体空间腾出,方便新增其它临时任务
	while(1)
	{
	  TaskProcess();  //查询就绪的函数
	}		
}
点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4