基於先後臺設計的系統隨着功能的遞增變得愈來愈難以維護, 因此決定爲STC15F2K單片機編寫一個基於時分的非搶佔式內核,方便進行任務模塊的開發。bash
內核TCB結構定義以下:框架
typedef struct os_tcb { void(*task)(void *); //任務處理函數 INT32U cpu_load; //任務分配CPU時間片 INT32U cpu_run; //任務當前運行CPU時間片 INT8U status; //任務狀態 INT8U id; //任務ID void *pd; //任務參數,方便數據共享交互 } OS_TCB;
經過STC的內部定時器0產生系統的tick,在定時器0的ISR中輪詢TCB列表並對cpu_run進行計數,在main主循環中,輪詢tcb中status爲Ready的task,並進行調用。下面是簡單的框架代碼:函數
void timer0_isr (void) interrupt 1 { OSSched(); } void OSSched() { INT8U i; for (i = 0; i < OS_TASK_NUM; i++) { if ((OSTCBList[i].task != 0u) && (OSTCBList[i].status == OS_STAT_PEND)) { OSTCBList[i].cpu_run++; if (OSTCBList[i].cpu_run >= OSTCBList[i].cpu_load) { OSTCBList[i].cpu_run = 0u; OSTCBList[i].status = OS_STAT_RDY; } } } } void main() { OSStart(); } void OSStart() { INT8U i; EA = 1; while (OS_TRUE) { for (i = 0; i < OS_TASK_NUM; i++) { if ((OSTCBList[i].task != 0u) && (OSTCBList[i].status == OS_STAT_RDY)) { OSTCBList[i].task(OSTCBList[i].pd); OSTCBList[i].status = OS_STAT_PEND; } } } }
在實際使用中我建立了APPLedTask和APPKeyTask兩個Task,每一個Task單獨運行功能都正常,但只要同時開啓這兩個Task,那麼每一個Task功能都會異樣,有時候刪除一行代碼就正常,但我以爲問題以爲不出如今被刪除代碼處,因此懷疑是出現個函數指針Overlay的問題。spa
查看問題代碼編譯生成的m51文件設計
?PR?APPINIT?MAIN ----- ----- +--> ?PR?BSPGPIOINIT?GPIO +--> ?PR?BSPLEDINIT?LED ?PR?APPTASKINIT?MAIN ----- ----- +--> ?PR?_APPKEYTASK?APP_KEY <--- 錯誤處 +--> ?PR?_OSTASKCREATE?OS +--> ?PR?_APPLEDTASK?APP_LED <--- 錯誤處 ?PR?_APPKEYTASK?APP_KEY 0029H 0003H <--- 錯誤處 +--> ?PR?BSPKEYSTATUS?KEY ?PR?_OSTASKCREATE?OS 0029H 0008H ?PR?_APPLEDTASK?APP_LED 0029H 0003H <--- 錯誤處 +--> ?PR?_BSPLEDLIGHT?LED +--> ?PR?_BSPLEDDISPLAY?LED ?PR?_BSPLEDDISPLAY?LED ----- ----- +--> ?PR?_SEND_595?LED +--> ?PR?UPDATE_595?LED ?PR?UPDATE_595?LED ----- ----- +--> ?CO?LED +--> ?PR?_SEND_595?LED BL51 BANKED LINKER/LOCATER V6.22 08/01/2017 14:01:54 PAGE 3 ?PR?OSSTART?OS 0029H 0001H <--- 錯誤處
你們能夠看到我標記出來的錯誤處。BL51錯誤的認爲在函數: APPTASKINIT中調用了APPKeyTask, APPLedTask(實際上我只是對於函數指針進行賦值), 因而BL51把OSStart、APPKeyTask、APPLedTask都鏈接到了相同的Data memory地址0x0029,這就會致使在OSStart中調用Task函數時出現異常。指針
解決方案的話,在BL51 Misc的Overlay框中構建正確的調用樹code
?PR?APPTASKINIT?MAIN ~ ?PR?_APPKEYTASK?APP_KEY, ?PR?APPTASKINIT?MAIN ~ ?PR?_APPLEDTASK?APP_LED, ?PR?OSSTART?OS ! ?PR?_APPKEYTASK?APP_KEY, ?PR?OSSTART?OS ! ?PR?_APPLEDTASK?APP_LED // ~: 刪除調用關係 !: 插入調用關係
觀察更新後m51文件,兩個task已經被OSStart調用,並與OSStart處於不一樣的Data memory地址上對象
?PR?APPTASKINIT?MAIN ----- ----- +--> ?PR?_OSTASKCREATE?OS ?PR?_OSTASKCREATE?OS 0029H 0008H <----- ?PR?OSSTART?OS 0029H 0001H +--> ?PR?_APPKEYTASK?APP_KEY +--> ?PR?_APPLEDTASK?APP_LED ?PR?_APPKEYTASK?APP_KEY 002AH 0003H <----- +--> ?PR?BSPKEYSTATUS?KEY ?PR?_APPLEDTASK?APP_LED 002AH 0003H <----- +--> ?PR?_BSPLEDLIGHT?LED +--> ?PR?_BSPLEDDISPLAY?LED
另一種解決方案就是建立一個const code的函數指針對象,由於在code區,而BL51對於code區是另外對待的,因此不存在Overlay的狀況,這樣也省去了修改調用樹的麻煩。開發
typedef struct os_task { void(*task[OS_TASK_NUM])(void *); } OS_TASK; OS_TASK const code OSTaskList = {APPKeyTask, APPLedTask};