以前曾經發(fā)布過一篇http://www.zg4o1577.cn/mcu/1616.html 這個是改進版,修正了幾個小問題.
//說明本源碼來自網絡(DIY超輕量級多任務操作系統(tǒng)一文)
//============================================================================
//51實用多任務源碼,歡迎引用改進,有新改進功能請回發(fā)一份給我謝謝!(請發(fā)郵箱)
//改進為定時中斷內切換任務
//任務內可以設定時間片長短,通過改定時器0初置的方法實現
//置定時器0 TL0=0xFF;的方法可以讓出CPU使用權
//七彩驚云改進,QQ540953860 13880880726 胥先生
//采用本源碼請保留各改進人的聯(lián)系信息,以便共享和完善,請將各改進前版本備注在代碼后面以便了解發(fā)展
//步驟和各種不同檔次單片機下的靈活引用。
//請對每一句代碼進行備注謝謝!
//============================================================================
//============================================================================
//你的改進說明寫這兒
//============================================================================
#include <reg51.h>
#define MAX_TASKS 2 //任務槽個數.必須和實際任務數一至
#define MAX_TASK_DEP 12 //最大棧深.最低不得少于2個,保守值為12.
//根據程序嵌套層數調整該值大小,同時要算一下會不會溢出,這里的設置很重要。
//還有就是重入問題,局部變量在任務切換時有可能被另外的任務改寫。
//#define MAX_TASK_DEP 24 //最大棧深.最低不得少于2個,24.
unsigned char idata task_stack[MAX_TASKS][MAX_TASK_DEP];//任務堆棧數組.
unsigned char task_id; //當前活動任務號
unsigned char idata task_sp[MAX_TASKS];//棧指標存放數組
bit RWCH_BZ=0;//任務切換標志變量
/*
//任務切換函數(任務調度器)
void task_switch(){ //本子程序可以用來讓出CPU使用權
task_sp[task_id] = SP; //存當前任務SP的值
if(++task_id == MAX_TASKS) //任務號++并比較,到最大置0以便重復切換任務
task_id = 0;
SP = task_sp[task_id]; //讀取下一任務SP值,
} */
//任務裝入函數.將指定的函數(參數1)裝入指定(參數2)的任務槽中.如果該槽中原來就有任務,則原任務丟失,但系統(tǒng)本身不會發(fā)生錯誤.
void task_load(unsigned int fn, unsigned char tid){
task_sp[tid] = task_stack[tid] + 1; //裝入任務SP數據
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;}
//這里其實就是以改寫SP指針的方法,返回時不再返回調用本子程序的地方,而返回被新設定的SP指針指向的任務1首地址處運行。
/*============================以下為測試代碼============================*/
void task1(){ //任務1
static unsigned char i;
while(1){
i++;
}
}
void task2(){//任務2
static unsigned char j;
while(1){
j+=2;
TL0=0xFF;//用置TL0的辦法來進行讓定時中斷動作從而進行任務切換,讓出CPU使用權給下一任務的方法更好
}
}
void main(){
//這里裝載了兩個任務,因此在定義MAX_TASKS時也必須定義為2
//=============================================================
//單片機初始化
// mov tmod,#20h ;串口通訊設置 串口方式3 波特9600 晶振11.59適用
//TMOD=0x20;//定時器1方式2
TMOD=0x22;//定時器0方式2,定時器1方式2
// mov Tl1,#0fdh ;
TL1=0xfa;
// mov th1,#0fdh ; TEL:028-89951522 轉載請勿刪除,謝謝!
TH1=0xfa;
// mov pcon,#128d ;QQ:540953860
//PCON=128;
PCON=0x80;
// mov sp,#60h
//SP=0x60;
IP=16;//串口中斷設為高優(yōu)先級
// mov scon,#0e0h
SCON=0xf0;//為e0時禁止接收數據
//setb tr1
TR1=1;//開啟定時器1
TR0=1;//開啟定時器0
ET0=1;//開定時器0中斷
TL0=0x50;//定時器0初值設定
TH0=0x50;//在中斷中設置它可實現時間片調整
// setb ea
//=============================================================
task_load(task1, 0);//將task1函數裝入0號槽
task_load(task2, 1);//將task2函數裝入1號槽
EA=1;//開中斷
os_start(0); //進入任務1
}
ckzd() interrupt 4 using 1//串行中斷入口
{
}
timer0zd() interrupt 1 using 2//定時器0中斷入口
{
// clr tr1 ;關閉定時器
TR0=0;
// clr et1 ;關閉定時中斷
ET0=0;
// task_switch();//切換任務
//===========================================
//切換任務
task_sp[task_id] = SP;
if(++task_id == MAX_TASKS)
{
task_id = 0;
RWCH_BZ=1;//當task_id==0時說明所有任都切換了一次,置標志不再對棧進行調整。
}
SP = task_sp[task_id];
if(RWCH_BZ==0)
{//棧調整代碼
SP+=2;//第一次切換程序時原棧沒有(POP PSW 和POP ACC 數據調整一下,為什么請查匯編代碼)
//為什么要加上面代碼的分析
//中斷中其實隱含了以下代碼
//PUSH ACC
//PUSH PSW
//----------------
//中斷內的實際代碼
//----------------
//下面兩句的數據在每個任務第一次切換時任務棧內其實并沒有它的數據,如果不調整,這兩句將會把返回地址數據給POP掉
//所以進行SP+2處理才會正常返回切換后的任務,從而騙過CPU
//POP PSW
//POP ACC
//RET
}
//============================================
// setb et1
ET0=1;//開中斷
// setb tr1
TR0=1;//開定時器
}
//===================================
//=======================================================================
/*
//網絡原碼
#include <reg51.h>
#define MAX_TASKS 2 //任務槽個數.必須和實際任務數一至
#define MAX_TASK_DEP 12 //最大棧深.最低不得少于2個,保守值為12.
unsigned char idata task_stack[MAX_TASKS][MAX_TASK_DEP];//任務堆棧.
unsigned char task_id; //當前活動任務號
unsigned char idata task_sp[MAX_TASKS];
//任務切換函數(任務調度器)
void task_switch(){
task_sp[task_id] = SP;
if(++task_id == MAX_TASKS)
task_id = 0;
SP = task_sp[task_id];
}
//任務裝入函數.將指定的函數(參數1)裝入指定(參數2)的任務槽中.如果該槽中原來就有任務,則原任務丟失,但系統(tǒng)本身不會發(fā)生錯誤.
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;}
void task1(){
static unsigned char i;
while(1){
i++;
task_switch();//編譯后在這里打上斷點
}
}
void task2(){
static unsigned char j;
while(1){
j+=2;
task_switch();//編譯后在這里打上斷點
}
}
void main(){
//這里裝載了兩個任務,因此在定義MAX_TASKS時也必須定義為2
task_load(task1, 0);//將task1函數裝入0號槽
task_load(task2, 1);//將task2函數裝入1號槽
os_start(0);
}
*/
//=======================================================================