单片机-基于消息的优先级任务系统

本文主要介绍,飞思卡尔单片机框架内使用的具有消息、优先级的小型任务系统


任务系统思想:

任务系统本质就是将【优先级,消息,消息处理函数】绑定在一起,之后在一个无限循环中,根据优先级顺序检测是否有消息产生,如果发生消息,则调用相应的消息处理函数


具体实现:

该系统主要有三个源文件组成

    TS_Interface.h 该文件主要是任务系统接口的描述,以及一些系统配置描述。

    TS_kernel.h 该文件主要是系统的头文件。

    TS_kernel.c 该文件主要是任务系统的实现。


主要实现:

// 任务最大数量

#define gTsMaxTasks_c   10

// 信号量

typedef uint16_t event_t;

// 空闲任务ID

#define gTsIdleTaskID_c     (( tsTaskID_t )  0 )

// 无效任务ID

#define gTsInvalidTaskID_c  (( tsTaskID_t ) -1 )

// 空闲任务的优先级

#define gTsIdleTaskPriority_c       (( tsTaskPriority_t )  0 )

// 无效的优先级

#define gTsInvalidTaskPriority_c    (( tsTaskPriority_t ) -1 )

// 任务消息函数指针

typedef void ( *pfTsTaskEventHandler_t )( event_t );

// 计算数组元素个数

#define NumberOfElements(array)     ((sizeof(array) / (sizeof(array[0]))))

// 任务运行表声明

typedef struct tsTaskTableEntry_tag {
  event_t events;
  tsTaskPriority_t priority;
  pfTsTaskEventHandler_t pfTaskEventHandler;
} tsTaskTableEntry_t;
// 定义任务运行表

tsTaskTableEntry_t maTsTaskTable[gTsMaxTasks_c];

// 定义任务优先级表

tsTaskID_t maTsTaskIDsByPriority[NumberOfElements(maTsTaskTable)];

// 空闲任务ID

tsTaskID_t gIdleTaskID;


// 清除任务事件标志

void TS_ClearEvent
  (
  tsTaskID_t taskID,
  event_t events
  )
{
  uint8_t ccr;

  IrqControlLib_BackupIrqStatus(ccr);  // 备份当前的程序状态字
  IrqControlLib_DisableAllIrqs();	// 关总中断
  maTsTaskTable[taskID].events &= ~events;  // 清标志位,置0
  IrqControlLib_RestoreIrqStatus(ccr);  // 还原程序状态字
}

// 初始化任务

/* Initialize the task scheduler. */
void TS_Init(void) {
  FLib_MemSet(maTsTaskTable, gTsInvalidTaskPriority_c, sizeof(maTsTaskTable));   // 清除任务表为无效
  FLib_MemSet(maTsTaskIDsByPriority, gTsInvalidTaskID_c, sizeof(maTsTaskIDsByPriority));  // 清除优先级表为无效

  gIdleTaskID = TS_CreateTask(gTsIdleTaskPriority_c, IdleTask);
}                                       /* TS_Init() */

// 创建任务

/****************************************************************************/

/* Add a task to the task table.
 * Return the task ID, or gTsInvalidTaskID_c if the task table is full.
 *
 * taskPriority == 0 is reserved for the idle task, and must never be specified
 * for any other task. TS_CreateTask() does not check for this.
 *
 * Note that TS_CreateTask() does not prevent a given event handler function
 * pointer from being added more than once to the task table.
 *
 * Note that if TS_CreateTask() is called with a taskPriority that is the
 * same as the priority of a task that is already in the task table, the
 * two tasks will end up in adjacent slots in the table. Which one is
 * called first by the scheduler is not specified.
 */
tsTaskID_t TS_CreateTask
  (
  tsTaskPriority_t taskPriority,
  pfTsTaskEventHandler_t pfTaskEventHandler
  )
{
  index_t i;
  index_t freeSlot;
  index_t sizeofTaskId = sizeof(maTsTaskIDsByPriority[0]);

  /* Try to find a free slot in the task table. 发现任务表的空闲位置,索引保存到freeSlot*/
  for (i = 0, freeSlot = gTsInvalidTaskID_c;
       (i < NumberOfElements(maTsTaskTable));
       ++i) {
    if (maTsTaskTable[i].priority == gTsInvalidTaskPriority_c) {
      freeSlot = i;
      break;
    }
  }                                     /* for (i = 0, freeSlot = 0xFF; ... */

  if (freeSlot == gTsInvalidTaskID_c) {
    return gTsInvalidTaskID_c;  // 任务表已满
  }

  // 初始化任务条目
  maTsTaskTable[freeSlot].events = 0;
  maTsTaskTable[freeSlot].pfTaskEventHandler = pfTaskEventHandler;
  maTsTaskTable[freeSlot].priority = taskPriority;

  /* maTsTaskIDsByPriority is maintained in sorted order, so 1) find the */
  /* place where this new task should go; 2) move everything up; and 3) add */
  /* the new task. */
  /* 优先级从小到到,等级从高到低 */
  for (i = 0; i < NumberOfElements(maTsTaskIDsByPriority); i++) {
    /* If the end of the table is reached, just add the new task. */
    if (maTsTaskIDsByPriority[i] == gTsInvalidTaskPriority_c) {
      break;  // 如果里面存入的是非法的优先级,则说明结束
    }

    /* If all tasks from this point on have lower priorities than the task */
    /* being added, move the rest up and insert the new one. */
    /* 找到优先级比其大的第一个索引,之后将该索引(包含自己)后的数据都后移,空闲出此位置 */
    if (maTsTaskTable[maTsTaskIDsByPriority[i]].priority < taskPriority) {
      FLib_MemInPlaceCpy(&maTsTaskIDsByPriority[i + 1],
                         &maTsTaskIDsByPriority[i],
                         (NumberOfElements(maTsTaskIDsByPriority) - i - 1) * sizeofTaskId);
      break;
    }
  }                                     /* for (i = 0; ... */
  maTsTaskIDsByPriority[i] = freeSlot;  // 插入上面找到的索引位置

  return freeSlot;
}                                       /* TS_CreateTask() */

// 移除任务

/* Remove a task from the task table. */
void TS_DestroyTask
  (
  tsTaskID_t taskID
  )
{
  index_t i;
  index_t sizeofTaskId = sizeof(maTsTaskIDsByPriority[0]);

  if (maTsTaskTable[taskID].priority == gTsInvalidTaskPriority_c) {
    return;
  }

  /* Mark this slot in the task descriptor table as unused. */
  /* 清除任务表中的记录 */
  maTsTaskTable[taskID].priority = gTsInvalidTaskPriority_c;

  /* Remove this task's ID from the priority table. Find it's position */
  /* in the table, and shift everything else down. */
  /* 找到优先级中的索引,将后面的索引前移,并将最后一个位置的索引标记为无效 */
  for (i = 0; i < NumberOfElements(maTsTaskIDsByPriority); i++) {
    if (maTsTaskIDsByPriority[i] == taskID) {
      FLib_MemCpy(&maTsTaskIDsByPriority[i],
                  &maTsTaskIDsByPriority[i + 1],
                  (NumberOfElements(maTsTaskIDsByPriority) - i - 1) * sizeofTaskId);

      /* Note that exactly one entry was removed. */
      maTsTaskIDsByPriority[NumberOfElements(maTsTaskIDsByPriority) - 1] = gTsInvalidTaskID_c;
      break;
    }
  }

  return;
}                                       /* TS_DestroyTask() */

 

// 查找是否有信号事件

bool_t TS_PendingEvents(void) {
  index_t i;

  for (i = 0; i < NumberOfElements(maTsTaskTable); ++i) {
    if (( maTsTaskTable[i].priority != gTsInvalidTaskPriority_c)
        && maTsTaskTable[i].events) {
      return TRUE;
    }
  }

  return FALSE;
}


// 发送信号事件

/* Send events to a task. */
void TS_SendEvent
  (
  tsTaskID_t taskID,
  event_t events
  )
{
  uint8_t ccr;

  IrqControlLib_BackupIrqStatus(ccr);  // 备份程序标志
  IrqControlLib_DisableAllIrqs();	// 关中断
  maTsTaskTable[taskID].events |= events;
  IrqControlLib_RestoreIrqStatus(ccr);
}                                       /* TS_SendEvent() */

// 任务轮询函数,在主循环中调用

void TS_Scheduler(void) {
  index_t activeTask;
  uint8_t ccr;
  event_t events;
  index_t i;
  index_t taskID;

  /* maTsTaskIDsByPriority[] is maintained in task priority order. If there */
  /* are fewer than the maximum number of tasks, the first gInvalidTaskID_c */
  /* marks the end of the table. */
  for (;;) {
    /* Look for the highest priority task that has an event flag set. */
    activeTask = gTsIdleTaskID_c;  // 如果未找到有效的信号事件,则调用空闲函数
    for (i = 0; i < NumberOfElements(maTsTaskIDsByPriority); ++i) {
      taskID = maTsTaskIDsByPriority[i];
      if (taskID == gTsInvalidTaskID_c) {
        break;
      }

      if (maTsTaskTable[taskID].events) {
        activeTask = taskID;	// 找到有信号事件的任务ID
        break;
      }
    }

    /* If there are no outstanding events, call the idle task. */
    IrqControlLib_BackupIrqStatus(ccr);  // 备份程序字
    IrqControlLib_DisableAllIrqs();	// 关中断
    events = maTsTaskTable[activeTask].events; // 取出信号
    maTsTaskTable[activeTask].events = 0;  // 情况原始信号
    IrqControlLib_RestoreIrqStatus(ccr);  // 还原程序字

    (*maTsTaskTable[activeTask].pfTaskEventHandler)(events); // 调用对用的事件函数
  }                                     /* for (;;) */
}                                       /* TS_Scheduler() */



你可能感兴趣的:(单片机)