單片機下最小多任務程序
任務函數的書寫:
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(),也就是說,該語句行之後的所有語句都不被執行到.
}
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(),也就是說,該語句行之後的所有語句都不被執行到.
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.