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); //死循环。定时器中断发生后,任务开始调度 } /////////////////////////////////////////////////////////////////////////////////////////////////