📄 os_core.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 + -