本文主要介绍,飞思卡尔单片机框架内使用的具有消息、优先级的小型任务系统
任务系统思想:
任务系统本质就是将【优先级,消息,消息处理函数】绑定在一起,之后在一个无限循环中,根据优先级顺序检测是否有消息产生,如果发生消息,则调用相应的消息处理函数
具体实现:
该系统主要有三个源文件组成
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() */