|
看大家都在學(xué)操作系統(tǒng),我也想學(xué)學(xué)。所以想用51寫一個(gè)來玩玩,發(fā)現(xiàn)比較郁悶。
弄了幾下,不想再弄了,51弄這個(gè)沒啥意思。我用的89S52,除了速度慢,RAM資源太少之外,其它都還過得去。弄了一點(diǎn)代碼出來,放在那也沒啥用,不如拿上來給新手看看,一個(gè)任務(wù)調(diào)度的雛形是什么樣子的~~~~~~~~~這些代碼沒有經(jīng)過優(yōu)化, 我只求實(shí)現(xiàn)任務(wù)切換的功能。
利用定時(shí)器2產(chǎn)生10mS的定時(shí)中斷作為時(shí)鐘節(jié)拍,任務(wù)切換時(shí)保存工作寄存器等操作 嵌入了匯編指令,因此Task_Switch.C文件要做相應(yīng)的設(shè)置才能編譯通過。受硬件資源和編譯器的限制,有很多無奈。程序只好這樣寫了,不管怎么說,到底是能調(diào)度起來了。
注:這里是老版本,后面又改動(dòng)的新版本。
/******************************************************* 本程序只供學(xué)習(xí)使用,未經(jīng)作者允許,不能用于其它任何用途
AT89S52 MCU 使用24M晶振 時(shí)鐘節(jié)拍設(shè)置為10mS
main.c file
Created by Computer-lov. Date: 2005.10.27
Copyright(C) Computer-lov 2005-2015 All rigths reserved
******************************************************/
#include <at89x52.h> #include "task_switch.h" #include "MAIN.H"
//燈 #define LED1 P1_7 #define LED2 P1_6 #define LED3 P1_5 #define LED4 P1_4 #define LED5 P0_1 #define LED6 P3_7
#define ON_LED1() LED1=0 #define OFF_LED1() LED1=1
#define ON_LED2() LED2=0 #define OFF_LED2() LED2=1
#define ON_LED3() LED3=0 #define OFF_LED3() LED3=1
#define ON_LED4() LED4=0 #define OFF_LED4() LED4=1
#define ON_LED5() LED5=0 #define OFF_LED5() LED5=1
#define ON_LED6() LED6=0 #define OFF_LED6() LED6=1
//按鈕 #define KEY1 P1_0 #define KEY2 P1_1 #define KEY3 P1_2 #define KEY4 P1_3
//OS運(yùn)行標(biāo)志 unsigned char OS_running;
//堆棧申請(qǐng) unsigned char idata Stack[MAX_TASK][S_DEPTH];
//運(yùn)行時(shí)間 unsigned int Running_Time;
//程序控制塊 PCB pcb[MAX_TASK];
//當(dāng)前運(yùn)行任務(wù)的ID號(hào) unsigned char Current_ID;
/////////////////////////////////////調(diào)用該函數(shù)使任務(wù)延時(shí)t個(gè)時(shí)鐘節(jié)拍//////////////////////// ///////////////////////////////////// 輸入?yún)?shù):0<t<256 ////////////////////////////// ///////////////////////////////////// 一個(gè)時(shí)鐘節(jié)拍為10mS /////////////////////////////// void OS_Delay(unsigned char t) { EA=0; //關(guān)中 pcb[Current_ID].Suspend=1; //任務(wù)掛起 pcb[Current_ID].Delay=t; //設(shè)置延遲節(jié)拍數(shù) EA=1; //開中 task_switch(); //任務(wù)切換 } ////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////掛起任務(wù) //////////////////////////////////////////////// /*void OS_Suspend(void) { EA=0; pcb[Current_ID].Suspend=1; //任務(wù)掛起 EA=1; task_switch(); //任務(wù)切換 }*/ ////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////創(chuàng)建一個(gè)任務(wù)//////////////////////////////////////////// ///////////////////////////////函數(shù)入口:Task_ID 分配給任務(wù)的唯一ID號(hào) ////////////////////////// ////////////////////////////// Task_Priority 任務(wù)優(yōu)先級(jí) ///////////////////////// /////////////////////////////// Task_p 任務(wù)入口地址 /////////////////////////////// Stack_p 任務(wù)堆棧棧低地址 /////////////////////////// void Task_Create(unsigned char Task_ID,unsigned char Task_Priority,unsigned int Task_p,unsigned char Stack_p) { unsigned char i;
for(i=0;i<S_DEPTH;i++) { ((unsigned char idata *)Stack_p)[i]=0; //初始化清空堆棧 }
((unsigned char idata *)Stack_p)[0]=Task_p; //將任務(wù)入口地址保存在堆棧 ((unsigned char idata *)Stack_p)[1]=Task_p>>8;
pcb[Task_ID].Task_SP=Stack_p+Num_PUSH_bytes+1; //設(shè)置好堆棧指針 pcb[Task_ID].Priority=Task_Priority; //設(shè)置任務(wù)優(yōu)先級(jí) pcb[Task_ID].Suspend=0; //任務(wù)初始不掛起 pcb[Task_ID].Delay=0; //任務(wù)初始不延時(shí) } /////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////空閑任務(wù),優(yōu)先級(jí)最低/////////////////////////////////// ////////////////////////////////////二個(gè)LED不停的閃爍 ////////////////////////////////////// void task_idle(void) { static unsigned long int i; //使用static申明局部變量,避免臨時(shí)變量使用相同地址 while(1) { ON_LED1(); //LED1亮 for(i=0;i<0x2000;i++) //延遲 { } OFF_LED1(); //LED1關(guān) for(i=0;i<0x2000;i++) { ON_LED6(); //LED6閃爍很快,看起來是一直亮的 OFF_LED6(); } } } //////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////任務(wù)1 檢測(cè)按鈕1 并控制LED2亮滅////////////////////////// void task_1(void) { // static unsigned int j; while(1) { ON_LED2(); while(KEY1)OS_Delay(6); //等待KEY1按鍵按下 while(!KEY1)OS_Delay(6); //等待KEY1釋放 OFF_LED2(); while(KEY1)OS_Delay(6); while(!KEY1)OS_Delay(6); } } ////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////任務(wù)2 檢測(cè)按鈕2 并控制LED3亮滅////////////////////////// void task_2(void) { // static unsigned int j; while(1) { ON_LED3(); while(KEY2)OS_Delay(5); while(!KEY2)OS_Delay(5); OFF_LED3(); while(KEY2)OS_Delay(5); while(!KEY2)OS_Delay(5); } } ////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////任務(wù)3 檢測(cè)按鈕3 并控制LED4亮滅////////////////////////// void task_3(void) { // static unsigned int j; while(1) { ON_LED4(); while(KEY3)OS_Delay(5); while(!KEY3)OS_Delay(5); OFF_LED4(); while(KEY3)OS_Delay(5); while(!KEY3)OS_Delay(5); } } ////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////任務(wù)4 控制LED5每秒閃一次////////////////////////// void task_4(void) { // static unsigned int j; while(1) { ON_LED5(); OS_Delay(100); //LED5每隔1S閃一次 OFF_LED5(); OS_Delay(100); } } ////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////主函數(shù)////////////////////////////////////////////////////// void main(void) { EA=0; //關(guān)中 ET2=1; //定時(shí)器2開中斷
T2CON=0x00; //定時(shí)器自動(dòng)重裝模式 T2MOD=0x00; //如果提示這里編譯通不過,可將本行刪除;或自己將定義添上 //因?yàn)閗eil自帶的at89x52.h中沒有T2MOD的定義 RCAP2H=0xB1; RCAP2L=0xE0; //定時(shí)時(shí)間為10ms
Task_Create(0,5,(unsigned int)(void *)(&task_idle),(unsigned char)Stack[0]); //任務(wù)0初始化 Task_Create(1,4,(unsigned int)(void *)(&task_1),(unsigned char)Stack[1]); //任務(wù)1初始化 Task_Create(2,3,(unsigned int)(void *)(&task_2),(unsigned char)Stack[2]); //任務(wù)2初始化 Task_Create(3,2,(unsigned int)(void *)(&task_3),(unsigned char)Stack[3]); //任務(wù)3初始化 Task_Create(4,1,(unsigned int)(void *)(&task_4),(unsigned char)Stack[4]); //任務(wù)4初始化
OS_running=0; //任務(wù)未開始運(yùn)行
Current_ID=MAX_TASK-1; //當(dāng)前任務(wù)為最后一個(gè)任務(wù)
pcb[Current_ID].Task_SP-=Num_PUSH_bytes; //調(diào)整任務(wù)堆棧指針,因?yàn)檫@時(shí)任務(wù)還未開始調(diào)度 //第一次進(jìn)入中斷時(shí),會(huì)壓棧。所以先將堆棧指針 //往下調(diào)Num_PUSH_bytes個(gè)字節(jié),避免堆棧溢出 //調(diào)整后的SP緊接著的兩個(gè)字節(jié)就是最后一個(gè)任務(wù)的入口地址 //在第一次中斷發(fā)生時(shí),返回地址被壓入SP后面的兩個(gè)地址 //在第一次進(jìn)入中斷后,將SP往前調(diào)整兩字節(jié),這樣程序返回時(shí), //將返回到最后一個(gè)任務(wù),而不再返回主函數(shù)
SP=pcb[Current_ID].Task_SP; //修改堆棧指針。使其指向任務(wù)當(dāng)前任務(wù)的堆棧段
TR2=1; //啟動(dòng)定時(shí)器2 EA=1; //開中斷
while(1); //死循環(huán)。定時(shí)器中斷發(fā)生后,任務(wù)開始調(diào)度 |