寵物任務的詳細流程(探討多任務下餵狗的方式)
2023-11-08 08:40:03
寵物任務的詳細流程? 一直以來,我不斷的探索RTOS的使用方法,以UC/OS-II為基礎當然努力的結果是逐漸形成了一個可以使用的軟體平臺但我意識到如果沒有相應文檔的支持或許這個東西也許只有我自己能使用了另外提高的空間有限所以今天就從這個困擾我許久的問題入手,慢慢的介紹我這兩年來努力的成果,我來為大家科普一下關於寵物任務的詳細流程?以下內容希望對你有幫助!

寵物任務的詳細流程
一直以來,我不斷的探索RTOS的使用方法,以UC/OS-II為基礎。當然努力的結果是逐漸形成了一個可以使用的軟體平臺。但我意識到如果沒有相應文檔的支持或許這個東西也許只有我自己能使用了。另外提高的空間有限。所以今天就從這個困擾我許久的問題入手,慢慢的介紹我這兩年來努力的成果。
關於多任務下如何才能有效的使用看門狗這個問題其實也不是很難。關鍵是在於餵狗的策略。你沒辦法像以前一樣。在程序的開頭初始化看門狗,然後在程序中的某一點調用餵狗指令,清除看門狗計數器。因為你要明白,你想要清楚的知道每一個任務都必需有條不紊的工作的。任何一個任務死掉就得停止餵狗。這就是問題的關鍵了。所以你不可以在每個任務裡直接調用餵狗指令。那是混亂的沒有實際意義。
那麼不能直接餵狗,自然就想到間接餵狗的方式了。如何才能做到間接餵狗。我使用了軟體看門狗的方式。給每個任務一個軟體模擬出來的看門狗計數器。然後在適當的時候定時的查詢每一個軟體看門狗的餵狗情況,由此決定是否調用餵狗指令,清除看門狗計數器。如果發現有任何一個軟體看門狗溢出,就停止餵狗,讓系統復位。
如何定時查詢軟體看門狗的餵狗情況? UC/OS-II系統時間節拍鉤子函數是個不錯的選擇。隨後再給出具有體的實現。
void OSTimeTickHook (void)
{ SoftWdtISR; //定時查詢每一個軟體看門狗餵狗狀況。
}
軟體看門狗是一個什麼樣的東西??從數據結構上來說,它是這樣子的:
typedef struct soft_wach_dog_timer{
uint16 watchDogTimeOut; //看門狗計數超時初值
uint16 watchDogTime; //看門狗定時器
uint8 watchDogCountBack; //上一次看門餵狗計數器
uint8 watchDogCount; //看門狗餵狗計數器
SWDT_STAT watchDogState; //看門狗定時器狀態
uint8 NOUSE8;
}SOFT_WATCH_DOG_TIMER;
好吧,我來一個個介紹,才幾個變量而以,很容易的。先講第二個成員吧,uint16 watchDogTime; 這個就是軟體看門狗的定時器了,每當調用SoftWdtISR的時候如果相應看門狗沒有餵狗操作該值會被減去1,否則將從第一個成員uint16 watchDogTimeOut複製一份拷貝。所以第一個成員變量叫做看門狗計數超時初值。那麼第三個和第四個成員變量是幹嗎用的呢,這兩個就是用來判斷是否有餵狗操作。第五個成員是表示軟體看門狗狀態的。總共有三種狀態。
typedef enum{ SWDT_STAT_IDLE, //軟體看門狗空閒
SWDT_STAT_SUSPEN, //軟體看門狗掛起
SWDT_STAT_RUN //軟體看門狗運行
}SWDT_STAT; 接下來看看SoftWdtISR的實現吧。
void SoftWdtISR(void){
SOFT_WATCH_DOG_TIMER *SoftWatchDogTimerPtr = SoftWatchDogTimerList;
uint8 i = 0;
if(StopWDTFedMake == TRUE){
return;
}
for(i=0; iwatchDogState == SWDT_STAT_RUN){
//軟體看門狗有餵食,重裝看門狗計數上限
if(SoftWatchDogTimerPtr->watchDogCount != SoftWatchDogTimerPtr->watchDogCountBack){
SoftWatchDogTimerPtr->watchDogCountBack = SoftWatchDogTimerPtr->watchDogCount;
SoftWatchDogTimerPtr->watchDogTime = SoftWatchDogTimerPtr->watchDogTimeOut;
}else if(--SoftWatchDogTimerPtr->watchDogTime == 0){ //沒有餵狗,看門狗計時器減一操作 //其中任一個運行著的看門狗超時停止餵硬體看門狗
StopWDTFedMake = TRUE;
return;
}
}
SoftWatchDogTimerPtr ;
}//調用硬體餵狗
FeedDog;
}
SoftWdtISR函數隻對狀態為運行的軟體看門狗定時器進行檢查,每次都要判斷watchDogCountBack 是否等於watchDogCount,相等就表示該軟體看門狗沒有調用餵狗操作,然後執行軟體看門狗計數watchDogTime值減一操作。如果不相等就把watchDogCount的值賦給watchDogCountBack,。並且把watchDogTimeOut的值賦給watchDogTime,清除看門狗計數器。
當watchDogTime值為0,表示軟體看門狗溢出,需要復位系統。這有些曲折和複雜了,以後會改進。到時會去掉watchDogCountBack 、watchDogCount,這兩個成員。那麼該如何使用看門狗呢,我們要知道總共有幾個任務,為每個任務分配一個軟體看門狗,為每個看門狗分配一個ID。然後要清空所有軟體看門狗和初始化硬體看門狗:
typedef enum{//往這裡添加軟體看門狗ID
KEY_TASK_SWDT_ID,
MP3_TASK_SWDT_ID,
MAX_SWDT_ID,
}SWDT_ID;
//軟體看門狗定時器數組
SOFT_WATCH_DOG_TIMER SoftWatchDogTimerList[MAX_SWDT_ID] = {0};
void SoftWDTInit(void){
OS_MEMSET(SoftWatchDogTimerList, 0, sizeof(SOFT_WATCH_DOG_TIMER)*MAX_SWDT_ID); StopWDTFedMake = 0; //初始化硬體看門狗
WatchDogInit(1000,1);
}
軟體看門狗的使用:
Void KeyBoardTask(void *pdata){
//任務開始的地方,初始化軟體看門狗
SoftWdtInit(KEY_TASK_SWDT_ID,2000);
While(1){
const DEV_FUN* Device = NULL;
HAL_ERR_CODE err;
uint8 key_value[2] = {0};
uint8 data_addr = 0; /* 讀取一按鍵 */
SoftWdtFed(KEY_TASK_SWDT_ID); //任務主循環中餵狗
Device = DeviceOpen(I2C0_ID,&err);
……………………………..//以下代碼省略。
DeviceClose(&Device);
}
}
首先就是在任務開始的地方調用SoftWdtInit(KEY_TASK_SWDT_ID,2000);設置軟體看門狗溢出時間,單位mS. 然後在任務的主循環中調用SoftWdtFed(KEY_TASK_SWDT_ID);餵狗.接下來看看軟體看門狗初始化,和餵狗的實現。軟體看門狗的初始化:
//初始化軟體看門狗
BOOL SoftWdtInit(SWDT_ID SwdtId, uint16 TimerTop){
SOFT_WATCH_DOG_TIMER *SoftWatchDogTimerPtr = SoftWatchDogTimerList;
uint16 osTick = 0;
if(SwdtId >= MAX_SWDT_ID){
return 0;
}
if(SoftWatchDogTimerPtr->watchDogState == SWDT_STAT_IDLE){
SoftWatchDogTimerPtr = SwdtId;
osTick = MsToOSTicks(TimerTop);//將mS時間換算成系統時鐘節拍
SoftWatchDogTimerPtr->watchDogTimeOut = osTick;
SoftWatchDogTimerPtr->watchDogTime = osTick;
SoftWatchDogTimerPtr->watchDogState = SWDT_STAT_RUN;
return 1;
}else{
return 0;
}
}
這裡就沒什麼好說的,從軟體看門狗定時器數組裡,根據ID找到相應的軟體看門狗,然後初始化watchDogTimeOut,置watchDogState狀態為運行。
餵狗: //軟體看門狗餵食
void SoftWdtFed(SWDT_ID SwdtId){
SOFT_WATCH_DOG_TIMER *SoftWatchDogTimerPtr = SoftWatchDogTimerList; if(SwdtId >= MAX_SWDT_ID){
return;
}
SoftWatchDogTimerPtr = SwdtId;
OS_ENTER_CRITICAL;
SoftWatchDogTimerPtr->watchDogCount ;
//保證這兩個值使終不相等 if(SoftWatchDogTimerPtr->watchDogCount == SoftWatchDogTimerPtr->watchDogCountBack){
SoftWatchDogTimerPtr->watchDogCount ;
}
OS_EXIT_CRITICAL;
}
這個也很簡單,根據ID找到相應的軟體看門狗,然後執行SoftWatchDogTimerPtr->watchDogCount ;並保證SoftWatchDogTimerPtr->watchDogCount 不等於SoftWatchDogTimerPtr->watchDogCountBack多餘的部分:
之前說過watchDogCount 、watchDogCountBack這兩個是多餘的所以將來會改成: void SoftWdtFed(SWDT_ID SwdtId){
SOFT_WATCH_DOG_TIMER *SoftWatchDogTimerPtr = SoftWatchDogTimerList;
if(SwdtId >= MAX_SWDT_ID){
return; }
SoftWatchDogTimerPtr = SwdtId;
OS_ENTER_CRITICAL;
SoftWatchDogTimerPtr->watchDogTime = SoftWatchDogTimerPtr->watchDogTimeOut;
OS_EXIT_CRITICAL;
}
相應的SoftWdtISR也需要簡化。
最後介紹兩個函數: void SuspenWdt(SWDT_ID SwdtId); //掛起軟體看門狗。void RunWdt(SWDT_ID SwdtId); //恢復運行軟體看門狗。
,