單片機下最小多任務程序

任務函數的書寫:  
void 函數名(void){//任務函數必須定義爲無參數型 
while(1){//任務函數不得返回,必須爲死循環
 //....這裏寫任務處理代碼  
 task_switch();//每執行一段時間任務,就釋放CPU一下,讓別的任務有機會運行. 
 } 
 } 
 
 任務裝載:  
 task_load(函數名,任務槽號)   
 裝載函數的動作可發生在任意時候,但通常是在main()中.
 要注意的是,在本例中由於沒考慮任務換出, 
 所以在執行os_start()前必須將所有任務槽裝滿.
 之後可以隨意更換任務槽中的任務.
 
啓動任務調度器: os_start(任務槽號)   調用該宏後,
將從參數指定的任務槽開始執行任務調度.
本例爲每切換一次任務需額外開銷個機器週期,用於遷移堆棧


#include <reg51.h>  
/*============================以下爲任務管理器代碼============================*/   
#define MAX_TASKS 3//任務槽個數.在本例中並未考慮任務換入換出,所以實際運行的任務有多少個,就定義多少個任務槽,不可多定義或少定義   
unsigned char idata task_sp[MAX_TASKS];   //任務的棧指針           
#define MAX_TASK_DEP 12 //最大棧深.最低不得少於個,保守值爲.     
//預估方法:以爲基數,每增加一層函數調用,加字節.如果其間可能發生中斷,則還要再加上中斷需要的棧深.       
//減小棧深的方法:1.儘量少嵌套子程序2.調子程序前關中斷. 
unsigned char idata task_stack[MAX_TASKS][MAX_TASK_DEP];//任務堆棧.   
unsigned char task_id;//當前活動任務號


//任務切換函數(任務調度器) 
void task_switch()
{  
task_sp[task_id] = SP;   
if(++task_id == MAX_TASKS)  
task_id = 0;   
SP = task_sp[task_id]; 



//任務裝入函數.將指定的函數(參數)裝入指定(參數)的任務槽中.如果該槽中原來就有任務,則原任務丟失,但
系統本身不會發生錯誤.  
void task_load(unsigned int fn, unsigned char tid)
{  
task_sp[tid] = task_stack[tid] + 1;  
task_stack[tid][0] = (unsigned int)fn & 0xff;  
task_stack[tid][1] = (unsigned int)fn >> 8; 
}   
//從指定的任務開始運行任務調度.調用該宏後,將永不返回.  
#define os_start(tid) {task_id = tid,SP = task_sp[tid];return;}


/*============================以下爲測試代碼============================*/   
 unsigned char stra[3], strb[3];//用於內存塊複製測試的數組.      
 //測試任務:複製內存塊.每複製一個字節釋放CPU一次 
 void task1()
 {  //每複製一個字節釋放CPU一次,控制循環的變量必須考慮覆蓋  
static unsigned char i;//如果將這個變量前的static去掉,會發生什麼事?  
i = 0;   
while(1){//任務必須爲死循環,不得退出函數,否則系統會崩潰  
stra[i] = strb[i];  
if(++i == sizeof(stra))    
i = 0;    //變量i在這裏跨越了task_switch(),因此它必須定義爲靜態(static),否則它將會被其它進程修改,因爲在另一個進程裏也會用到該變量所佔用的地址.  
task_switch();//釋放CPU一會兒,讓其它進程有機會運行.如果去掉該行,則別的進程永遠不會被調用到 

 }   //測試任務:複製內存塊.每複製一個字節釋放CPU一次. 
 void task2()
 {  //每複製一個字節釋放CPU一次,控制循環的變量必須考慮覆蓋  
static unsigned char i;//如果將這個變量前的static去掉,將會發生覆蓋問題.task1()和task2()會被編譯器分配到同一個內存地址上,當兩個任務同時運行時,i的值就會被兩個任務改來改去 
i = 0;   
while(1){//任務必須爲死循環,不得退出函數,否則系統會崩潰  
stra[i] = strb[i];   if(++i == sizeof(stra))   
i = 0;    //變量i在這裏跨越了task_switch(),因此它必須定義爲靜態(static),否則它將會被其它進程修改,因爲在另一個進程裏也會用到該變量所佔用的地址.  
task_switch();//釋放CPU一會兒,讓其它進程有機會運行.如果去掉該行,則別的進程永遠不會被調 用到 

 }   //測試任務:複製內存塊.複製完所有字節後釋放CPU一次. 
 void task3()
 {  //複製全部字節後才釋放CPU,控制循環的變量不須考慮覆蓋 
 unsigned char i;//這個變量前不需要加static,因爲在它的作用域內並沒有釋放過CPU   
 while(1){//任務必須爲死循環,不得退出函數,否則系統會崩潰   
i = sizeof(stra);   
do{  
stra[i-1] = strb[i-1];  
}while(--i);    //變量i在這裏已完成它的使命,所以無需定義爲靜態.你甚至可以定義爲寄存器型(regiter) 
task_switch();//釋放CPU一會兒,讓其它進程有機會運行.如果去掉該行,則別的進程永遠不會被調用到 

 }   
 void main()
 {  //在這個示例裏並沒有考慮任務的換入換出,所以任務槽必須全部用完,否則系統會崩潰. 
//這裏裝載了三個任務,因此在定義MAX_TASKS時也必須定義爲 
task_load(task1, 0);//將task1函數裝入號槽 
task_load(task2, 1);//將task2函數裝入號槽  
task_load(task3, 2);//將task3函數裝入號槽   
os_start(0);//啓動任務調度,並從號槽開始運行.參數改爲,則首先運行號槽.   
//調用該宏後,程序流將永不再返回main(),也就是說,該語句行之後的所有語句都不被執行到.
 }    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章