具有任务优先级的单片机任务调度器

这是一个模仿RTOS内核的非抢占式任务调度器,最大32级优先级(可自定义级数)、每级最大256个任务;集成软定时器功能(需要一个硬定时器支持),分为定时单位10us和1ms两种,每种最大为256个任务进行定时,当没有任务需要定时时,硬定时器处于关闭状态。通过以下4个函数进行对任务的操作:

  1. Task_Start(s_Task *Task);//启动任务–执行任务

  2. Task_Hangup(s_Task *Task);//挂起任务 避免在中断中挂起任务

  3. Task_Timer_10us(s_Task *Task,my_u16 Tim,my_u16 Circle);//任务微秒定时Circle循环定时时间到自动唤醒任务

  4. Task_Timer_ms(s_Task *Task,my_u16 Tim,my_u16 Circle);//任务毫秒定时

占用空间大小:keil5、1级优化,10级优先级,72M,两任务切换时间3us

Program Size: Code=5510 RO-data=362 RW-data=36 ZI-data=1764 //系统占用带1个空任务,接口函数无内容

Program Size: Code=5562 RO-data=362 RW-data=40 ZI-data=1768 //增加1个空任务,接口函数无内容

现附上源码:

一、头文件:

#ifndef __MYCORE_H
#define __MYCORE_H
#include "stm32f1xx_hal.h"

//功能:重定义系统数据结构
typedef uint8_t my_u8;
typedef uint16_t my_u16;
typedef uint32_t my_u32;

//----------------------------------此处为调度器配置处---------------------------------------------------
#define Pri_level 10 //优先级层数 最大32级 0--31 0为最高优先级

//以下宏定义是对软定时器组件用到的定时器配置
extern TIM_HandleTypeDef htim3;//使用硬定时器3

#define SetVal_ms_Timer 1000  //1ms
#define SetVal_us_Timer 10    //10us
#define Close_Timer __HAL_TIM_DISABLE(&htim3)
#define Open_Timer __HAL_TIM_ENABLE(&htim3)
#define CNT_Timer htim3.Instance->CNT //定时器的计数寄存器

//宏定义多条语句:中间用逗号或百分号,两头加大括号
#define SetVal_Timer(Val) {htim3.Instance->ARR = Val -1,CNT_Timer = 0;}//设置定时值 

//-------------------------------------------------------------------------------------------------------------------

//系统节点
typedef struct sNormNode  //通用节点
{
    struct sNormNode *ProNode;//指向前节点
    struct sNormNode *NextNode;//指向后节点
}s_NormNode;

typedef struct sList_Norm  //通用链表
{
    s_NormNode Node_Head;//头节点
    my_u8 Node_Count;  //任务节点数量
}s_ListNorm;

typedef struct sTask  //创建任务
{
    s_NormNode TaskNode;//任务节点 --需要创建
    s_NormNode TimerNode;//定时节点 --需要创建
    my_u8 state;//任务状态 位0:=1 运行态/1:=1 定时态 || /7:=1 毫秒定时链表
    void (*pFon)(void);//任务接口函数 --需要创建
    my_u8 *p;//接口函数参数
    my_u8 TaskPri;//任务优先级 --0为最高优先级
    my_u16 Time;//定时时间
    my_u16 Circle_Time;//循环定时时间
}s_Task;

//应用程序 ---先要创建一个任务

s_Task *Task_Creat(void (*pFon)(void),my_u8 *p,my_u8 TaskPri);//创建任务 1--任务接口函数,2--接口函数参数。3--任务优先级
void Task_Start(s_Task *Task);//启动任务--执行任务
void Task_Hangup(s_Task *Task);//挂起任务 避免在中断中挂起任务
void Task_Timer_10us(s_Task *Task,my_u16 Tim,my_u16 Circle);//任务微秒定时 Circle循环定时 时间到自动唤醒任务 
void Task_Timer_ms(s_Task *Task,my_u16 Tim,my_u16 Circle);//任务毫秒定时 Circle循环定时
void Soft_Timer(void);//延时任务链表处理-----放硬件定时器中断函数中
my_u8 Task_Sched(void);//任务调度-----放main的while 中无任务执行返回0
void TaskList_Init(void);//系统链表初始化----在main中初始化

#endif

二、源文件:

#include "mycore.h"
#include "stdlib.h"//没有会导致malloc使用警告,表示引用的malloc函数不确定

//------------------------------功能:重定向printf----------------------------------------   

//int fputc(int ch, FILE* stream)  //重定向printf函数用于程序调试用,需要包含stdio.h头文件HAL库放在USART.C文件中
//  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 10);
// return  ch;

//------------------------------功能:由结构体成员地址推算结构体首地址-------------------------------

//#define Struct_Member_Adrees(s_Task,Struct_Member) (my_u32)&(s_Task->Struct_Member) //取结构体成员地址
#define Struct_Member_offset(Struct_type, Struct_Member) ((my_u32)&((Struct_type *)0)->Struct_Member) //取结构体成员偏移量
#define Struct_Adrees(Struct_Member_Adrees, Struct_type, Struct_Member) ((Struct_type *)(Struct_Member_Adrees -Struct_Member_offset(Struct_type,Struct_Member))) //由成员偏地址得到结构体首地址

//------------------------------功能:链表组件--------------------------------------------------
#define First_Node  Node_Head.NextNode//链表头结点
#define Last_Node   Node_Head.ProNode//链表尾节点

//void Node_InsFirst(s_ListNorm *List,s_NormNode *newNode)//在链表头部插入节点
//{
// newNode->NextNode = List->First_Node;
// newNode->ProNode = &List->Node_Head;
// List->First_Node->ProNode = newNode;
// List->First_Node = newNode;
// List->Node_Count ++;
//}

void Node_InsEnd(s_ListNorm *List,s_NormNode *newNode)//在链表尾部插入节点
{
	  List->Last_Node->NextNode = newNode;
	  newNode->ProNode = List->Last_Node;
	  newNode->NextNode = &List->Node_Head;
	  List->Node_Head.ProNode = newNode;
	  List->Last_Node = newNode;
	  List->Node_Count ++;
}

void Node_InsFront(s_ListNorm *List,s_NormNode *nNode,s_NormNode *newNode)//在某节点前面插入节点
{
	  newNode->NextNode = nNode;
	  newNode->ProNode = nNode->ProNode;
	  nNode->ProNode->NextNode = newNode;
	  nNode->ProNode = newNode;
	  List->Node_Count ++;
}

//s_NormNode *Node_GetFirst(s_ListNorm *List)//取链表第一个节点地址
//{
//  return List->Node_Head.NextNode;
//}

void Node_Del(s_ListNorm *List,s_NormNode *Node)//删除链表某节点
{
	  Node->ProNode->NextNode = Node->NextNode;
	  Node->NextNode->ProNode = Node->ProNode;
	  List->Node_Count --;
}

//----------------------------------------------------------------------------------------------------------------
s_ListNorm Pri_List[Pri_level] ={0};//优先级就绪链表---等待执行
s_ListNorm Timer_ms_List;//延时链表
s_ListNorm Timer_10us_List;//延时链表

void sList_Init(s_ListNorm *List)//链表初始化
{
	  List->Node_Head.NextNode = &List->Node_Head;//头节点指向自己,注意:头结点是链表中的一环
	  List->Node_Head.ProNode  = &List->Node_Head;
	  List->Node_Count = 0;
}

void TaskList_Init(void)//链表初始化
{
	  for(my_u8 n = 0;n <Pri_level;n ++)
	  sList_Init(&Pri_List[n]);//
	  sList_Init(&Timer_ms_List);//
	  sList_Init(&Timer_10us_List);//
}

my_u8 Pri_Flg = 0;//任务优先级标志  每一位代表4个优先级 4*8 32个优先级 用于查找有任务的最高优先级链表

//--------------------------------任务处理组件------------------------------------------------------------------

s_Task *Task_Creat(void (*pFon)(void),my_u8 *p,my_u8 TaskPri)//创建任务 1--任务接口函数,2--接口函数参数。3--任务优先级
{
	  s_Task *Task = (s_Task*)malloc(sizeof(s_Task));
	  Task->state = 0;
	  Task->TaskPri = TaskPri;
	  Task->pFon = pFon;
	  Task->p = p;
	  Task->Time = 0;
	  Task->Circle_Time = 0;
	  return Task;
}

void Task_Start(s_Task *Task)//启动任务--执行任务
{
	  if(Task->state &(1<<0)) return;//前次任务还没执行
	  my_u8 TaskPri = Task->TaskPri;
	  Node_InsEnd(&Pri_List[TaskPri],(s_NormNode *)Task);//在链表尾部插入节点
	  Task->state |= (1<<0);//任务准备执行
	  Pri_Flg |= (1 <<(TaskPri/4));//每一位代表4个优先级 4*8 32个优先级
}

void Task_Hangup(s_Task *Task)//挂起任务 避免在中断中挂起任务
{
	  if(Task->state &(1<<0))//任务链表中删除
	  {
	      Node_Del(&Pri_List[Task->TaskPri],(s_NormNode *)Task);//删除链表某节点
	      Task->state &= ~(1<<0);
	  }
	  if(Task->state &(1<<1))//定时链表中删除
	  {
		  s_ListNorm *TimerList = NULL;
		  Task->Time = 0;
		  if(Task->state &(1<<7)) TimerList = &Timer_ms_List;
		     else TimerList = &Timer_10us_List;
		  Node_Del(TimerList,&(Task->TimerNode));//删除链表某节点
		  Task->Circle_Time = 0;
		  Task->state &= ~(1<<1);
	  }
}

my_u8 Task_Sched(void)//任务调度
{
	my_u8 TaskPri = 4;
	if(Pri_Flg == 0) return 0;//无任务执行
	if(Pri_Flg &0x0f)//2分缩小范围 高优先级 0000 1111
	TaskPri = 0;
	while(1)//查找最高优先级任务
	{
		if(Pri_Flg &(1<<TaskPri)) break;
		TaskPri ++;
	}
	TaskPri *= 4;//每一位代表4个优先级 4*8 32个优先级
	while(1)
	{
		if(TaskPri >=Pri_level) {Pri_Flg = 0;return 0;}//超限
		if(Pri_List[TaskPri].Node_Count !=0)
		{
			s_Task *Task = (s_Task *)(Pri_List[TaskPri].Node_Head.NextNode);//取任务节点  此时挂起任务会导致程序出错
			Node_Del(&Pri_List[TaskPri],(s_NormNode *)Task);//删除链表某节点
			Task->state &= ~(1<<0);
			(*Task->pFon)();//执行任务接口函数
			while(1)//
			{
				if(Pri_List[TaskPri].Node_Count ==0) TaskPri ++;
				else
				return 1;//本组优先级还有任务执行
				if(((TaskPri/4) ==0)||(TaskPri >=Pri_level))//本组优先级无任务执行
				{
					Pri_Flg &= ~(1 <<((TaskPri -1)/4));//每一位代表4个优先级 4*8 32个优先级  去本组优先级置位标识
					return 1;
				}
			}
		}
		else
          TaskPri ++;
    }
}

//------------------------------功能:软定时器组件----------------------------------------------------------
my_u8 Timer_us_Isopen = 0;//定时器中断为10微秒标志
void Timer_List(s_ListNorm *List)//定时处理
{
	my_u8 n = List->Node_Count;
	s_Task *Task = NULL;
	s_NormNode *TimerNode = NULL;
	my_u32 TimerNode_Adess = 0;
	if(n ==0) return;//空闲
		TimerNode = (List->Node_Head.NextNode);//取第一个定时节点
	while(n--)
	{
		TimerNode_Adess = (my_u32)TimerNode;
		Task = Struct_Adrees(TimerNode_Adess, s_Task, TimerNode);//由构体成员偏地址得到结构体首地址
		TimerNode = TimerNode->NextNode;
		Task->Time --;
		if(Task->Time == 0)//延时时间到
		{
			Node_Del(List,(s_NormNode *)TimerNode_Adess);//删除链表某节点
			Task_Start(Task);//唤醒任务--执行任务
			if(Task->Circle_Time)//循环定时
			{
				Task->Time = Task->Circle_Time;
				Node_InsEnd(List,(s_NormNode *)TimerNode_Adess);//在链表尾部插入节点
			}
			else
		    	Task->state &= ~(1<<1);
		}
	}
}

my_u16 Timer_usUp = 0;//10微秒中断次数

void Task_Timer_10us(s_Task *Task,my_u16 Tim,my_u16 Circle)//任务微秒定时 Circle循环定时
{
	Task->Time = Tim;
	if(Circle) 
		Task->Circle_Time = Tim;
	else 
		Task->Circle_Time = 0;
	if(Task->state &(1<<1))//处于定时状态
	{
		if(!(Task->state &(1<<7))) return;//在微秒定时链表
		else Node_Del(&Timer_ms_List,&(Task->TimerNode));//删除链表某节点
	}
	Node_InsEnd(&Timer_10us_List,&(Task->TimerNode));//在链表尾部插入节点
	Task->state |= (1<<1);
	Task->state &= ~(1<<7);//处于微秒延时链表
	if(Timer_us_Isopen == 0)//
	{
		Close_Timer;//关闭本定时器
		Timer_usUp = CNT_Timer/SetVal_us_Timer;
		SetVal_Timer(SetVal_us_Timer);//设置定时值
		Open_Timer;
		Timer_us_Isopen = 1;
	}
}

void Task_Timer_ms(s_Task *Task,my_u16 Tim,my_u16 Circle)//任务毫秒定时  Circle循环定时
{
	Task->Time = Tim;
	if(Circle) Task->Circle_Time = Tim;
	else Task->Circle_Time = 0;
	if(Task->state &(1<<1))//处于定时状态
	{
		if(Task->state &(1<<7)) return;//在毫秒定时链表
		else Node_Del(&Timer_10us_List,&(Task->TimerNode));//删除链表某节点
	}
	Node_InsEnd(&Timer_ms_List,&(Task->TimerNode));//在链表尾部插入节点
	Task->state |= (1<<1);
	Task->state |=(1<<7);//处于毫秒延时链表
	if(Timer_us_Isopen == 0)
	{
		Close_Timer;//关闭本定时器
		SetVal_Timer(SetVal_ms_Timer);//设置定时值
		Open_Timer;
	}
}

const my_u16 ms_us_val = SetVal_ms_Timer/SetVal_us_Timer;//避免频繁的除法运算
void Soft_Timer(void)//延时任务链表处理 放硬件定时器
{
	if(Timer_us_Isopen)
	{
		Timer_List(&Timer_10us_List);//定时处理
		Timer_usUp ++;
		if((Timer_usUp >= ms_us_val)&&(Timer_ms_List.Node_Count != 0))
		{
			Timer_usUp = 0;
			if(Timer_10us_List.Node_Count == 0)
			{
				Close_Timer;//关闭本定时器
				SetVal_Timer(SetVal_ms_Timer);//设置定时值
				//CNT_Timer = SetVal_ms_Timer -1; //目的--消除切换误差
				Open_Timer; //启动毫秒定时
				Timer_us_Isopen = 0;
			}
			Timer_List(&Timer_ms_List);//定时处理
		}
	}
	else
    	Timer_List(&Timer_ms_List);//定时处理
	if((Timer_ms_List.Node_Count ==0)&&(Timer_us_Isopen ==0))
	  Close_Timer;//关闭本定时器
}

使用方法:

a.创建一个任务并返回任务地址

  1.定义一个全局变量

      s_Task *Task1;//

  2.在main中或其它地方创建一个任务

     Task1 = Task_Creat(AA,NULL,2);//创建任务 1--任务接口函数,2--接口函数参数。3--任                                                                   务优先级

b.对这个任务进行 唤醒、挂起、延时等操作

  1.Task_Start(Task1);//任务启动 等待执行

  2.Task_Hangup(Task1);//挂起任务 ---在任务执行(或定时)链表队列中被剔除

  3.Task_Timer_10us(Task1,10,1);//任务微秒定时----Task1每定时100us后被执行

  4.Task_Timer_ms(Task1,5,0);//任务毫秒定时----Task1定时5ms后被执行一次

c.调度器根据当时任务优先级的大小,执行优先级最高的那个任务,任务切换时间3us

软仿真结果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值