STC15分時內核中函數指針的使用問題

    基於先後臺設計的系統隨着功能的遞增變得愈來愈難以維護, 因此決定爲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};
相關文章
相關標籤/搜索