51单片机的简易时间片任务调度器(类似操作系统?)

这段代码是我按照网上的内容修改的,主要是添加了任务通过延时提前放弃CPU的功能。

此系统的任务槽目前不可扩展,只有三个,对内存的保护也几乎没考虑,也没有优先级之类的功能。所以,一定要多用static防止变量被绿。

任务槽中前两个任务(taskA,taskB)是主任务,第三个(taskC)是空任务。

此系统的时间片实测约为1.1ms,在中断函数中,依次判断每一个主任务的延时是否已经为0。如果是,那么就执行这个任务;如果延时大于零,就减一;如果主任务延时都大于零,就执行空任务TaskC.

当然我不懂原来搞到的代码里面为什么初始化的时候要SP+10(我试了其他的值,都不行。),请大佬解答。

#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
#define taskNum 3
#define taskStackLen 13

int a;
sbit led0 = P2^0;
sbit led1 = P2^1;
sbit led2 = P2^2;
sbit led3 = P2^3;

uchar flag=0,num=0;
uchar *pstk[taskNum];
uchar temp,i;
uint delayList[3]={0,0,0};
uchar interruptedList[3]={0,0,0};

void osDelay(uint delayTime,uchar n){
	
    delayList[n]= delayTime*0.903; //这个相当于是乘以一个数,让它稍微小一点。
	interruptedList[n]=1;
   while(1){
	if(interruptedList[n]==0)	{
			break;
		}
	}
}

void delay(uint z)
{
 static unsigned int x,y;
 for(x=z;x>0;x--)
  for(y=110;y>0;y--);  //原来为110
}

int detect(){	//模拟的任务执行函数。比如……调用超声波。
	delay(2);
	led3=~led3;
	delay(2);
	return 0;
		
}
void InitTimer0(void)
{
	TMOD = 0x01;
    TH0 = 0x0FC;
    TL0 = 0x18;
    EA = 1;
    ET0 = 1;
    TR0 = 1;
}


void taskA()
{
 while(1)
 {

  temp=0x01;
  led0=~led0;
  osDelay(10,0); 
 }
}
void taskB()
{
static int b;
 while(1)
 {
  led1=~led1;
  b=detect();
  osDelay(1000,1);
 }
}

void taskC()
{
 while(1)
 {
  delay(20);
 }
}


main()
{
 InitTimer0();
 while(1);
}
void * const func[]={taskA,taskB,taskC};



void exint0() interrupt 1
{

 uchar idata *p;
 uchar q;
 uchar k;//寻找空闲任务的变量

    led2=~led2;
 
 if(num==1) pstk[0]=(uchar *)SP;//num=1表示第二次进入中断(主函数中没有任务运行),在进入任务后产生的中断,这时保存该任务的进入中断前的堆栈指针
 if((num==2)&&(num==taskNum-1)) pstk[1]=(uchar *)SP;	 //第三次进入中断的时候需要

 
//执行这一步!但是为什么呢?
 if(num<taskNum)		   //这种情况有几个任务就在初次启动时启动几次。
 {
  p=(uchar *)SP+1;	//将SP强制类型转换为UCHAR类型的指针,并且在SP的地址的基础上加1。
  *p++=((uint)(func[num]))%256;	 
  *p=((uint)(func[num]))/256;   //将右边赋给p指针所指向的地址。这里指的是,取出func[num]这个函数的首地址,除以256之后再赋给p指向的地址。
  SP=(uchar)p;          	    //	强制类型转换,让SP指向p的地址。
  SP+=10;	                   // 我不懂这句是啥意思……
  num++;	                	//当前的任务号:自增。
                              //这一部分应该能自动增加。
 }
 else
 {
	 static unsigned char lastFlag=2;

 flag=2;
 q=flag;
 if(delayList[0]>0){
 	delayList[0]-=1;
 }else{
 	q=flag;
 	flag=0;
 }

 if(delayList[1]>0){
 	delayList[1]-=1;
 }else{
  	q=flag;
 	flag=1;
 }
   interruptedList[0]=0;
   interruptedList[1]=0;
   interruptedList[2]=0;

	
	pstk[lastFlag]=	 (uchar *)SP;
	lastFlag = flag;
	SP = (uchar)pstk[flag];
 

 } 	
  TH0 = 0x0FC;
  TL0 = 0x18;
}
//此程序是通过定时器中断来切换的,但是切换时对堆栈的使用上存在问题。
//该程序的目的不是展示完美的任务级切换,主要是如何切换的问题。

这是仿真结果。从上到下依次为变量led0~led3

  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值