tiny rtos for 8051 part2

Posted by: 邱小新 at 下午2:08 in , ,

經過反覆測試,發現將 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<MAX_TASKS; i++) { *sp-- = ((unsigned int)(task_func[i])) / 256; *sp-- = ((unsigned int)(task_func[i])) % 256; rtos_stack[i] = sp + 15; sp += size; rtos_stack_IBP[i] = sp; sp += 2; } ?C_IBP = rtos_stack_IBP[0]; // timer0 init TMOD = (TMOD & 0xF0) | 0x01; TH0 = 0; TL0 = 0; TF0 = LOW; ET0 = HIGH; TR0 = HIGH; }

接下來二個 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 了。

1 意見

版大您好,請問Keil C的optimizer的9個等級到底是什麼意思,就算我看文字說明也不是很懂,可以請您舉例說明嗎?

張貼留言