具有任务优先级的单片机任务调度器
这是一个模仿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_** = 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_** |= (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_** == 0) return 0;//无任务执行
if(Pri_** &0x0f)//2分缩小范围 高优先级 0000 1111
TaskPri = 0;
while(1)//查找最高优先级任务
{
if(Pri_** &(1<<TaskPri)) break;
TaskPri ++;
}
TaskPri *= 4;//每一位代表4个优先级 4*8 32个优先级
while(1)
{
if(TaskPri >=Pri_level) {Pri_** = 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_** &= ~(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
|
|