www.pudn.com > 51_00_OS.rar > OS_core.c, change:2006-02-25,size:10311b


/******************************************************* 
*************基于51内核的圈圈操作系统***************** 
本程序只供学习使用,未经作者许可,不得用于其它任何用途 
 
OS_core.c file 
 
Created by Computer-lov 
Date: 2005.10.27 
 
Edit date:2006.2.24 
 
Version V1.0 
Copyright(C) Computer-lov 2005-2015 
All rigths reserved 
 
******************************************************/ 
 
#include "at89x52.h" 
 
#include "OS_core.h" 
#include "task_switch.h" 
#include "MAIN.H" 
 
#include "UART.H" 
 
 
//OS运行标志 
volatile unsigned char OS_Running; 
 
//运行时间 
volatile unsigned int OS_Run_Time; 
 
//程序控制块 
idata volatile PCB OS_pcb[MAX_TASK]; 
 
//当前运行任务的ID号 
volatile unsigned char OS_Current_ID; 
 
//用来统计使用了多少次OS_Enter_Critical 
//以判断使用OS_Exit_Critical退出临界段时是否需要真的退出 
//如果没有这样的判断,当OS_Enter_Critical被嵌套使用时, 
//会因为中间的OS_Exit_Critical退出临界段,而导致后半部分得不到保护 
volatile unsigned char OS_En_Cr_Count; 
 
 
//一字节,用位来表志是否存在一个任务 
// 例如,0000 0101 表示0号跟2号任务存在 
volatile unsigned char OS_Task_List; 
 
 
//堆栈申请。堆栈被分成5个块。每个块大小为0x1B(即27字节) 
//在os_core.h中修改S_DEPTH宏可修改堆栈的大小 
//在os_core.h中修改MAX_TASK可改变最大任务数,注意:现在最多可支持8个任务 
unsigned char idata OS_Stack[MAX_TASK][S_DEPTH]; 
 
 
///////////////////////////////////挂起任务 //////////////////////////////////////////////// 
void OS_Suspend(void) 
{ 
 OS_Enter_Critical();          //进入临界段 
 if(OS_Current_ID==0)              //任务0不能挂起!!! 
  { 
   OS_Exit_Critical(); 
   return; 
  } 
 OS_pcb[OS_Current_ID].Suspend=1;    //任务挂起 
 OS_Exit_Critical();           //退出临界段 
 OS_Task_Switch();                //任务切换 
} 
//////////////////////////////////////////////////////////////////////////////////////////// 
 
/////////////////////////////////////调用该函数使任务延时t个时钟节拍//////////////////////// 
///////////////////////////////////// 输入参数:0<t<256       ////////////////////////////// 
/////////////////////////////////////  一个时钟节拍为10mS    /////////////////////////////// 
void OS_Delay(unsigned char t) 
{ 
 if(t==0)return;                     //如果t=0,则不延迟 
 OS_Enter_Critical();                 //进入临界段 
 if(OS_Current_ID==0)              //任务0不能延时!!! 
  { 
   OS_Exit_Critical(); 
   return; 
  } 
 OS_pcb[OS_Current_ID].Suspend=1;    //任务挂起 
 OS_pcb[OS_Current_ID].Delay=t;      //设置延迟节拍数 
 OS_Exit_Critical();                 //退出临界段 
 OS_Task_Switch();                  //任务切换 
} 
//////////////////////////////////////////////////////////////////////////////////////////// 
 
 
//////////////////////////////// 等待消息  ///////////////////////////////////////////////// 
////////////////////////////////入口参数:等待超时时间 0-255 ////////////////////////////// 
///////////////////////////////返回:0-超时  1-不超时 ////////////////////////////////////// 
unsigned char OS_Wait_Msg(unsigned char time_out) 
{ 
 if(time_out==0)         //如果超时时间设置为0 
  { 
   OS_Suspend();         //则无限等待 
   return 1;               //返回 
  } 
 OS_Delay(time_out);             //等待直到超时或者被其它任务唤醒 
 OS_Enter_Critical();            //进入临界段 
 if(OS_pcb[OS_Current_ID].Delay==0)    //如果是因为由于时间到了而被唤醒,则超时 
  { 
   OS_Exit_Critical();           //退出临界段 
   return 0;                     //返回0,表示等待超时 
  } 
 else                            //如果等待时间未到而被唤醒,则没有超时 
  { 
   OS_pcb[OS_Current_ID].Delay=0;      //将多余的时间清0 
   OS_Exit_Critical();           //退出临界段 
   return 1;                     //返回1,表示等待消息成功,不超时 
  } 
} 
//////////////////////////////////////////////////////////////////////////////////////////// 
 
 
///////////////////////////////////////  OS初始化 ///////////////////////////////////////// 
void OS_Init(void) 
{ 
 OS_Running=0;              //任务未开始运行 
 OS_Run_Time=0;             //运行时间为0             
 OS_Task_List=0;            //任务列表为0 
 OS_En_Cr_Count=0;          //进入临界段0次 
} 
/////////////////////////////////////////////////////////////////////////////////////////// 
 
 
/////////////////////////////////////////创建一个任务//////////////////////////////////////////// 
//////////////////////////////           Task_Priority  任务优先级     ///////////////////////// 
///////////////////////////////          Task_p    任务入口地址       ////////////////////////// 
///////////////////////////////          Msg_p     消息起始地址       /////////////////////////// 
unsigned int OS_Task_Create(unsigned char Task_Priority,unsigned int Task_p,unsigned char Msg_p) 
{ 
 static unsigned char i; 
 static unsigned char OK_flag; 
 static unsigned char Task_ID; 
 static unsigned char Stack_p; 
 
 OS_Enter_Critical();    //由于需要在运行过程中动态增加任务,所以需要临界段保护 
  
 OK_flag=0;              //创建成功标志初始化为0,表示失败 
 for(i=0;i<MAX_TASK;i++)   //查找资源 
  { 
   if((OS_Task_List&(0x01<<i))==0)  //如果找到可用资源 
    { 
     Task_ID=i;                   //则保存当前资源号 
     OS_Task_List|=0x01<<i;       //并标志该资源被占用 
     OK_flag=1;                   //标志创建成功 
     break;                       //退出查找 
    } 
  } 
 
 if(!OK_flag)                  //如果所有资源都被占用 
  { 
   OS_Exit_Critical();         //退出临界段保护 
   return OS_Resource_Lack;    //返回错误代码--资源不足 
  } 
  
 Stack_p=(unsigned char)OS_Stack[Task_ID];   //根据分配到的资源使用堆栈段 
  
 for(i=0;i<S_DEPTH;i++) 
  { 
   ((unsigned char idata *)Stack_p)[i]=0;         //初始化清空堆栈 
  } 
 
 
 OS_pcb[Task_ID].Task_SP=Stack_p;                   //将该任务的堆栈栈低地址保存 
 ((unsigned char idata *)Stack_p)[0]=Task_p;        //将任务入口地址保存在堆栈,压入低8位 
 OS_pcb[Task_ID].Task_SP++;                         //压入一个后,堆栈加1,因为51的堆栈是往上生长的 
 ((unsigned char idata *)Stack_p)[1]=Task_p>>8;     //压入高8位 
 
 OS_pcb[Task_ID].Task_SP+=Num_PUSH_bytes;   //设置好堆栈指针 
                                    //即任务开始进入时,堆栈要模仿成被切换返回时的样子 
                                    //这时寄存器是被压栈的,且是压入了Num_PUSH_bytes个 
 
 
 OS_pcb[Task_ID].Priority=Task_Priority;             //设置任务优先级 
 
 OS_pcb[Task_ID].Delay=0;                            //任务初始不延时 
 
 OS_pcb[Task_ID].MSG=Msg_p;                          //消息指针 
  
  
  
 
  
 if(OS_Running) 
  { 
   OS_pcb[Task_ID].Suspend=0;                       //如果在运行中建立的任务,则不挂起 
  } 
 else 
  { 
#ifdef CPU_STAT 
 
 OS_pcb[Task_ID].Suspend=1;                          //如果需要CPU使用率统计,则任务初始挂起 
 
#else 
 
 OS_pcb[Task_ID].Suspend=0;                          //如果不需要CPU使用率统计,则任务初始不挂起 
 
#endif 
 
   OS_Current_ID=Task_ID;                          //在开始运行之前建立的任务,要保存其ID号 
  } 
 OS_Exit_Critical();             //退出临界段保护 
 
 return OS_Successful+Task_ID;   //返回创建成功及创建的任务ID号 
} 
///////////////////////////////////////////////////////////////////////////////////////////// 
 
 
/////////////////////////////////  释放资源  //////////////////////////////////////////////// 
/////////////////// 当一个任务被删除时,需要释放其占有的资源,否则别的任务不能使用  ///////// 
void OS_Release_Resource(unsigned char Task_ID) 
{ 
 release_printer(Task_ID);  //因为我们这里只有打印机资源,所以只释放打印机,及消息接收标志 
 if(Task_ID==Msg_1_Receiver)  //如果需要接收消息的任务被删除,则需要告诉发消息者,无任务接收消息 
  { 
   Msg_1_Receiver=0;     // 
  } 
                       //如果有多个独占资源,在任务被删除时,一定要记得检查是否需要释放 
                       //将释放资源的代码添加到此 
} 
///////////////////////////////////////////////////////////////////////////////////////////// 
 
 
///////////////////////////////// 删除一个任务  ////////////////////////////////////////////// 
unsigned int OS_Task_Kill(unsigned char Task_ID) 
{ 
 OS_Enter_Critical();       //进入临界段保护 
 if(Task_ID==0)             //如果任务ID为0,即空闲任务,则 
  { 
   OS_Exit_Critical();      //退出临界段保护 
   return OS_Task_Cannot_Be_Killed+Task_ID;   //返回错误代码---该任务不能被删除 
  } 
 if(Task_ID>=MAX_TASK)       //如果该ID号比MAX_TASK大,则说明该任务不可能存在 
  { 
   OS_Exit_Critical(); 
   return OS_Task_Not_Exist+Task_ID;  //返回错误代码---该任务不存在 
  } 
 if(OS_Task_List&(0x01<<Task_ID))  //如果所要删除的任务存在 
  { 
   OS_pcb[Task_ID].Suspend=1;      //则先将其挂起 
   OS_Task_List&=~(0x01<<Task_ID); //从任务列表中删除之 
   OS_Release_Resource(Task_ID);   //并释放该任务所占用的资源 
   OS_Exit_Critical();             //退出临界段保护 
   if(Task_ID==OS_Current_ID)     //如果删除的是自己,则 
    { 
     OS_Task_Switch();            //任务切换 
    } 
   return OS_Successful+Task_ID;   //返回删除成功及被删除的任务的ID号 
  } 
 else 
  { 
   OS_Exit_Critical();             //如果所要删除的任务不存在 
   return OS_Task_Not_Exist+Task_ID;  //则返回错误代码---该任务不存在 
  } 
} 
///////////////////////////////////////////////////////////////////////////////////////////// 
 
////////////////////////////////// OS 开始启动/////////////////////////////////////////////// 
void OS_Start(void) 
{ 
 OS_pcb[OS_Current_ID].Task_SP-=Num_PUSH_bytes;    //调整任务堆栈指针,因为这时任务还未开始调度 
                                             //第一次进入中断时,会压栈。所以先将堆栈指针 
                                             //往下调Num_PUSH_bytes个字节,避免堆栈溢出 
                                             //调整后的SP紧接着的两个字节就是最后一个任务的入口地址 
                                             //在第一次中断发生时,返回地址被压入SP后面的两个地址 
                                             //在第一次进入中断后,将SP往前调整两字节,这样程序返回时, 
                                             //将返回到最后一个任务,而不再返回到主函数 
 
 SP=OS_pcb[OS_Current_ID].Task_SP;                   //修改堆栈指针。使其指向任务当前任务的堆栈段 
 
 TR2=1;             //启动定时器2 
 EA=1;              //开中断 
 
 while(1);          //死循环。定时器中断发生后,任务开始调度 
} 
/////////////////////////////////////////////////////////////////////////////////////////////////