打印
[疑难问答]

将16个按键按照4*4排列,矩阵键盘的每一行分别连接P3.0~P3.3;矩阵键盘的每一列连接P3.4~P3...

[复制链接]
222|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
10299823|  楼主 | 2024-10-27 22:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
具有任务优先级的单片机任务调度器

       这是一个模仿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  

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

29

主题

3283

帖子

1

粉丝