单片机工控实现任务执行管理

描述

前面写了switch case做任务调度的应用,这边写一下如何实现.像一般的RTOS一样都有一个任务控制块(TCB)列表来管理所有的任务,所以这里也需要一个结构体来管理动作任务,这里叫做ACB吧.

动作任务管理结构体

这个结构体用来记录当前动作任务的当前步骤,函数地址,事件处理函数的函数地址,动作名称,运行时间等.

typedef struct _ACB
{
  uint8_t nStep;          // 分支动作步骤 
  uint8_t nChildID;       //子动作ID
  uint32_t nDelay;          // 延时
  uint32_t nStartTime;  
  uint32_t nUsedTime;
  uint32_t nStatus;          //当前状态
  
  ActionEvent EventQueue[4];    //动作事件队列
  uint8_t nEventCnt;            //事件数量和个数
  
  void (*AppCallBack)();        //业务动作函数指针
  void (*EventCallback)();      //事件处理函数指针
  void (*ActionCallback)();     //当前运行的函数指针 
  
  char ActionParam[10];          //动作参数
  //17
  char* pActionName;             //动作名称
  char* pErrorInfo;              //错误信息
  //8
  struct _ACB* next;             //上一个控制块 便于删除添加到就绪队列
  struct _ACB* prev;             //下一个控制块 便于添加删除到就绪队列
} ACB;

动作任务创建

//将OpApp业务函数指针和ACB结构体绑定
void AddAction(int nID,void (*OpApp)(),const char* pActionName)
{
  if(nID<90)
  {
    mOS.ActionPool[nID].AppCallBack = OpApp;
    mOS.ActionPool[nID].EventCallback = EventAction;
    mOS.ActionPool[nID].ActionCallback = OpApp;
    mOS.ActionPool[nID].nStatus = 0xff;
    mOS.ActionPool[nID].nEventCnt = 0;
    mOS.ActionPool[nID].nUsedTime = 0;
    mOS.ActionPool[nID].nStartTime = 0;
    mOS.ActionPool[nID].pActionName = (char*)pActionName;
  }
}

动作任务执行

1.动作结构体初始化,添加到就绪队列

//根据ID启动动作任务
int8_t StartAction(uint8_t ActionId)
{
  if(ActionId>90)
  {
    return false;  
  }
  ACB* pAction = &mOS.ActionPool[ActionId];
  pAction->ActionStartTime =   mOS.SystemTime;
  
  pAction->nStep = STEP1;
  pAction->nEventCnt = 0;
  pAction->nUsedTime = 0;
  pAction->nChildID = 0;
  pAction->EventCallback = EventAction;
  pAction->ActionCallback = pAction->AppCallBack;//先指向业务函数指针  
  AddReadyActionToTail(pAction);    //把当前的控制块添加到就绪队列
  return true;
}
//将要运行的动作添加到就绪运行队列
void AddReadyActionToTail(ACB * pAction)
{
  pAction->nStaus = 0;
  pAction->next = NULL;
  pAction->prev = mOS.tail;  //

  if(mOS.head==NULL)
  {
    mOS.head = pAction;
  }

  if(mOS.tail!=NULL) //当就绪链表没有动作时 tail为空 
  {
    mOS.tail->next = pAction;
  }


  mOS.tail = pAction;  //移动尾部指针
}

2.就绪队列遍历

inline void AppLoop()
{
  mOS.current = mOS.head;

    while(mOS.current!=NULL)
    {
      mOS.current->ActionCallback();
      DelFinishAction();  //需要把完成的任务从就绪队列删除
      mOS.current = mOS.current->next;
    }  
  }

  //动作完成后,并计算动作使用时间,从链表删除
inline void DelFinishAction()
{
  if(mOS.current->nStatus==0)  //动作任务正在运行
  {  
    return ;
  }
  //统计任务耗时    
   mOS.current->nUsedTime = mOS.SystemTime - mOS.CurrentAction->nStartTime;   //当前时间减去开始时间
   if(mOS.head==mOS.tail)  //只有一个元素 
   {
      mOS.head= NULL;
      mOS.tail = NULL;
      return ;
    }

  if(mOS.current==mOS.head)  //头部删除,需要将头部指针往后移动
  {
    mOS.head = mOS.current->next;
    return ;
  }

  if(mOS.current==mOS.tail)  //尾部删除,需要将尾部指针往前移动
  {
    mOS.tail = mOS.current->prev;
    mOS.tail->next = NULL;
    return ;
  }
//中间删除
   mOS.current->prev->next = mOS.current->next;  
   mOS.current->next->prev = mOS.current->prev;
}
打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分