原始碼下載
#define MAX_TASKS 2
unsigned char rtos_task_id;
unsigned char rtos_stack[MAX_TASKS];
void (* const task_func[MAX_TASKS])(void)={ task1, task2 };
void rtos_isr(void) interrupt 1
{
// save current stack
rtos_stack[rtos_task_id] = SP;
// load next stack
if (++rtos_task_id >= MAX_TASKS) rtos_task_id = 0;
SP = rtos_stack[rtos_task_id];
}
void rtos_start(void)
{
xdata unsigned char i, size;
xdata unsigned char idata *sp;
rtos_task_id = 0;
size = (256 - SP + 2) / MAX_TASKS;
sp = (unsigned char idata *)SP;
for (i=0; i
void task1(void)
{
xdata unsigned char i=0x30;
while(1)
{
if (++i>=0x3a) i=0x31;
putchar(i);
delay_1ms(50);
}
}
void task2(void)
{
xdata unsigned char j=0x60;
while(1)
{
if (++j>=0x6a) j=0x61;
putchar(j);
delay_1ms(50);
}
}
最近有空去研究了一下陳明計的 small rtos for 8051,看了老半天,還是看不懂他在寫什麼;尤其是他在 stack 的處理方式,實在是有看沒有懂。所以自己就自己來寫了一套 tiny rtos for 8051。沒有 semaphore,也沒有 task priority,什麼都沒有,只有簡單的時間分配,也就是所有工作時間都一致,current task 工作固定時間後,再換 next task 工作固定時間,如此循環工作。
工作原理也很簡單,如果有 n 個 tasks 就把 stack 分成 n 等份,讓每個 task 保有自己的 stack,不要互相干擾就可以。再利用 timer interrupt 來切換 task。很簡單吧,就如下面程式碼所列,並不會很難。
寫了二個測試函數,主要就是從 rs232 印出 1~9 及 a~i,如下所示。
但是結果卻不如預期,跑出來的東西都是亂碼,傻眼。最後,經過了二天的努力,總算把結果正確無誤的弄出來了。主要有下列幾個地方要修改。
- 把 C51 的 Code Optimization Level 降成 1:Dead code elimination。因為 Data overlaying 的關係,造成 task1 的 i 變數跟 task2 的 j 變數共用同樣的位址,所以讓印出來的值都在 1~9 跳動。
- 原本 data overlaying 問題想要利用 reentrant 指令來建立可重入函數去解決,但最後發現仍然是無效。因為 keil 把變數都放在一個 ?C_IBP 的位址,仍然會造成共用的問題,這個問題真是難解啊,以後如果要寫複雜的 multi-task 函數有一定的難度,必須克服可重入函數及 data overlaying 造成的問題。
- 在 rtos_isr 函數裏加入 push 及 pop 指令,把 R0~R7,ACC,B,PSW,DPH,DPL 都丟到 stack 裏去。因為 keil 都會利用這些暫存器做一些運算,在進入 interrupt 時,也會主動 push 一些在 interrupt 會用到的暫存器到 stack 裏,但其它沒用到的暫存器就沒有主動 push,造成切換到其它 task 再切回原來 task 時,那些暫存器裏的值都被變更了,而造成運算錯誤。
- 另外在加入 assembly code 時,需把 Generate Assembler SRC File 及 Assemble SRC File 都打勾才可以,缺一不可。
好強大阿~ 雖然我有看沒有懂 @@
有辦法指點迷津嗎 @@ 跪