51单片机操作系统.docx
《51单片机操作系统.docx》由会员分享,可在线阅读,更多相关《51单片机操作系统.docx(15页珍藏版)》请在冰豆网上搜索。
![51单片机操作系统.docx](https://file1.bdocx.com/fileroot1/2023-4/18/cac5b217-71bb-4c57-abd8-808983455524/cac5b217-71bb-4c57-abd8-8089834555241.gif)
51单片机操作系统
嵌入式实时操作系统,可以充分的利用单片机的资源,提高CPU使用效率。
操作系统最主要就是实现任务的调度、管理。
同时对于实时操作系统来说响应时间很重要。
操作系统编写最主要就是用到了堆栈SP于RET指令。
这两个东西怎么用呢?
其实在我们每次调用函数的时候都会自动将函数的断点地址(执行函数调用时的PC)压入到SP中,而从函数中返回时其实是利用RET指令将断点弹回到PC(程序指针)中。
所以利用堆栈和RET指令就可以实现简单的任务的切换。
这么说肯定挺模糊的,接下来一步一步解释。
首先,要知道任务是一个死循环。
如下面所示,可以看出两个任务都是死循环,按照以往的情况,程序是跳不出来的,只能在while
(1)中无限执行。
那怎么才可以实现从task0到task1的切换呢?
其实如果我们能够改变PC的值是不是就可以改变程序执行顺序了。
任务的调度切换就是利用改变PC的值来改变程序执行顺序的。
其次,就是要解决如何实现PC值的正确变换问题,如何让PC指向我们需要执行的地方。
这就是通过堆栈来实现的。
我们可以为每个任务建立一个堆栈用于保存任务PC的值,以及任务寄存器的值。
这样每次进行任务切换时只要从相应的堆栈中取出PC和寄存器的值就可以实现任务的调度了。
在程序中于寄存器相关的程序使用在C语言中嵌入汇编来实现的。
因为直接使用C语言不能直接控制寄存器。
在本程序中,入栈和出栈是通过汇编实现的。
一个简单的操作系统如下所示,只能实现简单的任务调度,延时。
必须注意,空闲任务(Idle)必须建立,否则会出错。
#include
#defineOSEnterCritical()EA=0
#defineOSExitCritical()EA=1
#defineEnterInt()EA=0;
#defineuintunsignedshortint
#defineucharunsignedchar
#defineMAX_Tasks3
#defineFalse0
#defineTure1
#defineMaxPrio2
#defineIdlePrioMaxPrio
#defineOS_Task_Create_Error1
#defineOS_Delet_Task_Error2
#defineOS_Delet_Task_Not_Exit3
#defineOS_Resume_Idle_Error4
#defineOS_Resume_Task_Error5
typedefstruct
{
ucharOSStackTop;//SP
ucharOSSuspend;
ucharOSTCBDly;//delaytime
}OSTCB;
ucharcodeOSMapTbl[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
OSTCBOSTCBTbl[MAX_Tasks];
volatileucharOSRdyTbl;
volatileucharOSIntNesting;//用于中断锁死
volatileucharOSSchNesting;//任务切换上锁
volatileucharOSRuning=False;
volatileucharOSStartStack[MAX_Tasks][20];
volatileucharOSPoint[MAX_Tasks][2];
volatileucharOSPrioCur;
//volatileucharOSTaskPend;
OSInit()
{
//uchari;
EA=0;
ET0=1;
TMOD=0x01;
TH0=0xB1;
TL0=0xE0;
OSRdyTbl=0;
OSIntNesting=0;
OSSchNesting=0;
}
//PCL,PCH,ACC,B,DPL,DPH,PSW,R0-R7
uchar*OSStackInit(uinttask,uchar*ptr,ucharOSPrio)
{
uchar*stk;
stk=ptr;
OSPoint[OSPrio][0]=task;
OSPoint[OSPrio][1]=task>>8;
*(stk++)=OSPoint[OSPrio][0];
*(stk++)=OSPoint[OSPrio][1];
*(stk++)=0x00;//ACC
*(stk++)=0x00;
*(stk++)=0x00;
*(stk++)=0x00;
*(stk++)=0x00;
*(stk++)=0x00;
*(stk++)=0x00;
*(stk++)=0x00;
*(stk++)=0x00;
*(stk++)=0x00;
*(stk++)=0x00;
*(stk++)=0x00;
*(stk)=0x00;
returnstk;
}
ucharOSTaskCreate(uinttask,uchar*ptr,ucharOSPrio)
{
uchar*psp;
OSEnterCritical();
if(OSPrio<=MaxPrio)//创建的任务优先级有效
{
psp=OSStackInit(task,ptr,OSPrio);//初始化堆栈
OSRdyTbl|=OSMapTbl[OSPrio];
OSTCBTbl[OSPrio].OSStackTop=psp;
OSTCBTbl[OSPrio].OSSuspend=0;
OSTCBTbl[OSPrio].OSTCBDly=0;
}
else
{
OSExitCritical();
returnOS_Task_Create_Error;
}
OSExitCritical();
}
/*=====================================================
任务调度函数
入口参数:
无
函数说明:
进入函数后,先进行堆栈保护,然后查找最高优先
级任务运行
======================================================*/
voidOSSchedule()
{
uchari;
OSEnterCritical();
#pragmaasm
PUSHACC
PUSHB
PUSHDPH
PUSHDPL
PUSHPSW
PUSH0
PUSH7
PUSH1
PUSH2
PUSH3
PUSH4
PUSH5
PUSH6
#pragmaendasm
OSTCBTbl[OSPrioCur].OSStackTop=SP;
if(OSRdyTbl)//如果就续表中有任务
{
for(i=0;i{
if((OSRdyTbl&OSMapTbl[i])&&(!
OSTCBTbl[i].OSSuspend))//任务优先级最高且未被挂起
{
OSPrioCur=i;
break;
}
}
}
SP=OSTCBTbl[OSPrioCur].OSStackTop;
#pragmaasm
POP6;
POP5;
POP4;
POP3;
POP2;
POP1;
POP7;
POP0;
POPPSW;
POPDPL;
POPDPH;
POPB;
POPACC;
#pragmaendasm
OSExitCritical();
}
voidOSStart()
{
TR0=1;
EA=1;
while
(1);
}
/*=========================================================
延时若干个系统时钟
入口参数:
延时系统时间个数
===========================================================*/
voidOSDelay(uchartime)
{
if(time==0)//延时为0,返回
return;
OSEnterCritical();
OSTCBTbl[OSPrioCur].OSTCBDly=time;
OSTCBTbl[OSPrioCur].OSSuspend=1;
OSExitCritical();
OSSchedule();
}
/*=========================================================
任务删除函数
入口参数:
为被删除任务优先级
函数说明:
将任务从就绪表中删除
===========================================================*/
ucharOSTaskDelet(ucharpriority)
{
OSEnterCritical();
if(priority>=IdlePrio)
{
OSExitCritical();
returnOS_Delet_Task_Error;
}
if(!
(OSRdyTbl&OSMapTbl[priority]))
{
OSExitCritical();
returnOS_Delet_Task_Not_Exit;
}
OSRdyTbl&=~(OSMapTbl[priority]);
OSExitCritical();
if(priority{
OSSchedule();
}
}
/*=========================================================
任务恢复函数
入口参数:
恢的任务优先级
函数说明:
恢复被OSTaskDelet()删除的任务
===========================================================*/
ucharOSTaskResume(ucharpriority)
{
OSEnterCritical();
if(priority==IdlePrio)//恢复的任务不能为空闲任务,为空闲任务返回错误标志
{
OSExitCritical();
returnOS_Resume_Idle_Error;
}
if((!
(OSRdyTbl&OSMapTbl[priority]))&&(priority>=0))
{
OSRdyTbl|=(OSMapTbl[priority]);
}
else//返回的任务不存在,返回错误标志
{
OSExitCritical();
returnOS_Resume_Task_Error;
}
OSExitCritical();
if(priority{
OSSchedule();
}
}
/*===============================================================
定时器0用于产生系统时钟,这里每过20ms中断一次。
===============================================================*/
voidtimer0()interrupt1
{
uchari;
EA=0;
TR0=0;
TH0=0xB1;
TL0=0xE0;
if(OSRuning==Ture)//如果不是第一次调度则保护任务堆栈,有部分堆栈进入中断时自动完成
{//定时器自动保护的堆栈可通过反汇编查看,以此确定堆栈的安排顺序
__asmPUSH1
__asmPUSH2
__asmPUSH3
__asmPUSH4
__asmPUSH5
__asmPUSH6
OSTCBTbl[OSPrioCur].OSStackTop=SP;
}
else//第一次进入则将OSRuning置位
{
OSRuning=Ture;
}
if(OSRuning==Ture)//如在运行,
{
for(i=0;i{
if((OSRdyTbl&OSMapTbl[i])&&OSTCBTbl[i].OSTCBDly)//如果任务需要延时,将任务延时参数减一
{
OSTCBTbl[i].OSTCBDly--;
if(OSTCBTbl[i].OSTCBDly==0)
{
OSTCBTbl[i].OSSuspend=0;
}
}
}
for(i=0;i{
if((OSRdyTbl&OSMapTbl[i])&&(!
OSTCBTbl[i].OSSuspend))//查找优先级最高的且未挂起的任务
{
OSPrioCur=i;
break;
}
}
SP=OSTCBTbl[OSPrioCur].OSStackTop;
#pragmaasm
POP6;
POP5;
POP4;
POP3;
POP2;
POP1;
/*POP7;
POP0;
POPPSW;
POPDPH;
POPDPL;
POPACC;*/
#pragmaendasm
}
TR0=1;
EA=1;
}
voidIdle()
{
while
(1);
}
voidtask0()
{
uchartemp=0x01,i;
while
(1)
{
for(i=0;i<8;i++)
{
P1=~temp;
temp<<=1;
OSDelay(10);
}
temp=0x01;
}
}
voidtask1()
{
uchari=0,j=0;
while
(1)
{
for(i=0;i<16;i++)
{
P3=j;
OSDelay(20);
j++;
}
j=0;
}
}
intmain()
{
OSInit();
OSTaskCreate(&Idle,&OSStartStack[2],IdlePrio);
OSTaskCreate(&task1,&OSStartStack[1],1);
OSTaskCreate(&task0,&OSStartStack[0],0);
OSStart();
}