初学时期写的代码,比较乱,希望对阅读本文的读者有所帮助。
代码是撇开了效率问题,为了方便理解任务切换过程,故都尽可能的使用了c实现的,而非汇编。
main.c
#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define TaskNumSize 3
#define RamSize 255
uchar idata Wait[TaskNumSize+2];
uchar TaskRdy=0xff,CurTask,NxtTask;
uchar IntNestNum,CurTaskIsIdle,IntRetBit=0;
void IntCtxSw(uchar f);
void WaitDly(uint dly);
extern void RetiIns();
extern void PopIns();
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void taskA()
{
static uchar temp,i;
while(1)
{
temp=0x01;
for(i=0;i<8;i++)
{
P1=temp;
temp=temp<<1;
WaitDly(10);
}
}
}
void taskB()
{
static uchar temp;
uchar i; //该局部变量不是局部静态变量,使该任务为不可重入函数
P2=0;
while(1)
{
/* temp=0x01;
for(i=0;i<8;i++)
{
P2=temp;
temp=temp<<1;
WaitDly(20);
}
*/
P2=0;
if(i++>0x0f) i=0;
P2=P2|i;
WaitDly(30);
if(temp++>0x0f) temp=0;
P2=P2|(temp<<4);
WaitDly(30);
}
}
void taskC()
{
static uchar temp,i;//各任务的局部变量设置为静态变量,使各任务的局部变量不受其它任务变量的影响而具有可重入性。
uchar t; //该局部变量会和taskB中的局部变量i覆盖,从而t的值会影响taskB中的i值
while(1)
{
temp=0x01;
for(i=0;i<8;i++)
{
P3=temp;
temp=temp<<1;
WaitDly(50);
P3=0;
WaitDly(5);
t++;
P3=t;
WaitDly(50);
P3=0;
WaitDly(5);
}
}
}
void InitTimer0()
{
TMOD=0x01;//方式1,16位模式,不会自动清零。
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TR0=1;
ET0=1;
EA=0;
}
void * const func[TaskNumSize]={taskA,taskB,taskC};
uchar idata *stk[TaskNumSize+1];
void InitStartTask()
{
uchar idata *sspp,i;
sspp = (uchar idata *)SP+1;
stk[0] = (uchar idata *)SP+1;
stk[TaskNumSize] = (uchar idata *)RamSize;
*sspp++ = ((uint)(func[0]))%256;
*sspp = ((uint)(func[0]))/256;
SP = (uchar)sspp;
sspp = (uchar idata *)(RamSize-1);
for(i=TaskNumSize-1;i>0;i--)
{
*sspp--=((uint)(func[i]))/256;
stk[i]=sspp;
*sspp--=((uint)(func[i]))%256;
}
}
main()
{
InitTimer0();
InitStartTask();
// while(1);
}
void IdleTask()
{
while(1)
{
PCON = PCON | 0x01; /* CPU进入休眠状态 */
}
}
void IntCtxSw(uchar f)
{
uchar idata *sp1,idata *sp2;
uchar temp,i;
uchar svsp;
temp=TaskRdy;
for(NxtTask=0;NxtTask<TaskNumSize;NxtTask++)
{
if((temp & 0x80)!=0)
break;
temp=temp<<1;
}
if(CurTaskIsIdle) SP=SP-19;
svsp=(uchar)SP;
if(!CurTaskIsIdle) //如果当前任务不是空闲任务时,才去设置中断返回标志位
{
if(f)
IntRetBit |= (0x80>>CurTask);
else
IntRetBit &= ~(0x80>>CurTask);
}
if(NxtTask<TaskNumSize)
{
sp1=(uchar *)SP+1;
sp2=stk[CurTask+1];
temp=(uchar)stk[NxtTask+1];
if(NxtTask>CurTask)
{
while(sp2!=(uchar idata *)temp)
{
*sp1++=*sp2++;
}
SP=(uchar)sp1-1;
temp=stk[CurTask+1]-(uchar idata *)svsp-1;
for(i=CurTask+1;i<NxtTask+1;i++)
{
stk[i]-=temp;
}
}
if(NxtTask<CurTask)
{
sp1--;sp2--;
while(sp1!=((uchar idata *)temp-1))
{
*sp2--=*sp1--;
}
SP=(uchar)stk[NxtTask+1]-1;
temp=stk[CurTask+1]-(uchar idata *)svsp-1;
for(i=NxtTask+1;i<CurTask+1;i++)
{
stk[i]+=temp;
}
}
if(NxtTask==CurTask)
SP=svsp;
CurTask=NxtTask;
CurTaskIsIdle=0;
/*下面为4种不同的函数返回方式*/
EA=1;
if(f)
{
if(IntRetBit & (0x80>>CurTask))
return;
else
RetiIns();
}
else
{
if(IntRetBit & (0x80>>CurTask))
{
SP=SP-4;
PopIns();
}
else
return;
}
}
CurTaskIsIdle=1;
*((uchar idata *)++SP)=(uint)IdleTask%256;
*((uchar idata *)++SP)=(uint)IdleTask/256;
EA=1;
if(f) RetiIns();
}
void WaitDly(uint dly)
{
Wait[CurTask]=dly;
while(Wait[CurTask]!=0)
{
TaskRdy &= ~(0x80>>CurTask);
EA=0;
IntCtxSw(0);
}
}
void Tick()
{
uchar prio;
for(prio=0;prio<TaskNumSize;prio++)
{
if(Wait[prio]>0)
{
Wait[prio]--;
if(Wait[prio]==0)
TaskRdy |= (0x80>>prio);
}
}
}
void IntExitSw()
{
if(IntNestNum>0)
IntNestNum--;
if(IntNestNum==0)
IntCtxSw(1);
}
void EnterInt()
{
if(IntNestNum<255)
IntNestNum++;
}
void timer0() interrupt 1
{
EA=0;
EnterInt();
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
Tick();
IntExitSw();
}
int.s
NAME EX_ASM
?PR?RETIINS?EX SEGMENT CODE
?PR?POPINS?EX SEGMENT CODE
PUBLIC RETIINS
PUBLIC POPINS
RSEG ?PR?RETIINS?EX
RetiIns:
MOV A,#(-2)
ADD A,SP
MOV SP,A
RETI
RSEG ?PR?POPINS?EX
PopIns:
MOV A,#(-2)
ADD A,SP
MOV SP,A
POP 7
POP 6
POP 5
POP 4
POP 3
POP 2
POP 1
POP 0
POP PSW
POP DPL
POP DPH
POP B
POP ACC
RET
END