經過反覆測試,發現將 interrupt 全改寫成 assembly 會造成不明原因輸出錯誤,這個原始碼不要用喔,後面有解決方法。
原始碼下載
在這次的實驗裏要解決 reentrant 函數的問題,其實也很簡單,就是把 reentrant 的 stack 變數依照每個 task 儲存起來,執行該 task 時,再回復其值就好了。程式碼如下,都是用 c 語法做說明,實際程式碼很多都改成 assemble 語法,主要是因為 Keil C51 的 reentrant stack 是存在 ?C_IBP,而 C 語法不允許變數有 ? 符號,所以就改成用 asseble 來寫。
void rtos_isr(void) interrupt 1
{
// save current stack
rtos_stack[rtos_task_id] = SP;
rtos_stack_IBP[rtos_task_id] = ?C_IBP;
// load next stack
if (++rtos_task_id >= MAX_TASKS) rtos_task_id = 0;
SP = rtos_stack[rtos_task_id];
?C_IBP = rtos_stack_IBP[rtos_task_id];
}
void rtos_start(void)
{
xdata unsigned char i, size;
xdata unsigned char idata *sp;
// variable init
rtos_task_id = 0;
// stack init
size = (256 - SP + 2) / MAX_TASKS;
sp = (unsigned char idata *)SP;
for (i=0; i
接下來二個 test tasks 就全改成 reentrant,如此就不會有 data overlaying 的問題,而且 Code Optimization Level 也可以調到 7:Extended Index Access Optimizing。執行結果就會看到數字跟英文字母相互出現。
void task1(void) reentrant
{
unsigned char i=0x30;
while(1)
{
if (++i>=0x3a) i=0x31;
putchar(i);
delay_1ms(100);
}
}
void task2(void) reentrant
{
unsigned char j=0x60;
while(1)
{
if (++j>=0x6a) j=0x61;
putchar(j);
delay_1ms(100);
}
}
寫到這裏也許有人會覺得奇怪,為什麼 Code Optimization Level 沒有調到預設值 8:Reuse of Common Entry Code?主要是因為在 rtos_start 裏,我利用 LCALL 的特性把 stack 裏的返回位址改成 task1 的位址,而 level 8 會把 main 函數裏的 LCALL rtos_start 改成 LJMP rtos_start,造成程式無法執行。當然只要一個小修改就可以修正掉這個 bug 了。
版大您好,請問Keil C的optimizer的9個等級到底是什麼意思,就算我看文字說明也不是很懂,可以請您舉例說明嗎?