前面寫了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;
}
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
Switch
+關注
關注
1文章
532瀏覽量
58161 -
RTOS
+關注
關注
21文章
809瀏覽量
119433 -
結構體
+關注
關注
1文章
130瀏覽量
10833
發布評論請先 登錄
相關推薦
單片機工程師是程序員嗎
程師做的工作就是程序開發,使用C語言來驅動單片機的硬件資源,以及完成一個邏輯任務,實現一定的功能的過程。但是單片機工程師又不是嚴格意義上的程序員,因為程序員是純粹在電腦上寫代碼的一個職
發表于 11-09 09:14
多個任務時,如何保證單片機工作效率及每個任務完成的及時性?資料下載
電子發燒友網為你提供多個任務時,如何保證單片機工作效率及每個任務完成的及時性?資料下載的電子資料下載,更有其他相關的電路圖、源代碼、課件教程、中文資料、英文資料、參考設計、用戶指南、解決方案等資料,希望可以幫助到廣大的電子工程師
發表于 04-12 08:41
?3次下載
單片機工程師是程序員嗎?真實的月薪到底有多少?
程師做的工作就是程序開發,使用C語言來驅動單片機的硬件資源,以及完成一個邏輯任務,實現一定的功能的過程。但是單片機工程師又不是嚴格意義上的程序員,因為程序員是純粹在電腦上寫代碼的一個職
發表于 11-04 17:36
?16次下載
單片機工控事件
單片機工控通常有延時,電機狀態,傳感器狀態等通用耗時操作,業務程序查詢這些狀態,就會產生大量的冗余代碼,不簡潔.使用事件則是把這些通用操作丟給系統去處理,系統操作完成后,則運行業務程序的下一個Step.
評論