⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 os_core.c

📁 实时系统的正确性不仅依耐系统计算的逻辑结果
💻 C
字号:
/*******************************************************
*************基于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 "STC516.h"
//#include<reg51.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,从低位到高位分别标志8个任务
 OS_En_Cr_Count=0;          //进入临界段0次
}
///////////////////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////创建一个任务////////////////////////////////////////////
//////////////////////////////           Task_Priority  任务优先级     /////////////////////////
///////////////////////////////          Task_p    任务入口地址       //////////////////////////
///////////////////////////////          Msg_p     消息起始地址       ///////////////////////////
//创建任务成功:在OS_Task_List的空闲位Task_ID处作标志
//				该任务分配堆栈段OS_Stack[Task_ID],在RAM的idata区
//				OS_pcb[Task_ID].Task_SP指向该堆栈段,且指向栈顶
//				OS_Stack[Task_ID]堆栈处,从栈低开分别保存任务的入口地址(低8位,高8位)
//										 13个字节的寄存器状态保存
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); 
 
}
/////////////////////////////////////////////////////////////////////////////////////////////////

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -