在本实验中,设计了6个普通应用任务:TA0(优先级为1)、TA1(优先级为2)、TA2(优先级为3)、TA3(优先级为4)、TA4(优先级为5)、TA5(优先级为6),以及一个控制任务TaskCon(优先级为7)。
µC/OS-II中,等待消息的任务总是按照优先级的高低来决定获得消息的顺序的。
具体的设计思路为:
#include"includes.h"
#define TASK_STK_SIZE 512
#define QUEUE_SIZE 150
OS_STK TA1Stk[TASK_STK_SIZE];
OS_STK TA2Stk[TASK_STK_SIZE];
OS_STK TA3Stk[TASK_STK_SIZE];
OS_STK TA4Stk[TASK_STK_SIZE];
OS_STK TA5Stk[TASK_STK_SIZE];
OS_STK TA6Stk[TASK_STK_SIZE];
OS_STK TaskConStk[TASK_STK_SIZE];
void*Queuef[QUEUE_SIZE];
OS_EVENT*qf;
void*Queuel[QUEUE_SIZE];
OS_EVENT*ql;
char*s;
INT16S key;
INT8U x=0,y=0;
INT8U err;
OS_Q_DATA data;
void TA1(void *pdata)
{
#if OS_CRITICAL_METHOD==3
OS_CPU_SR cpu_sr;
#endif
pdata=pdata;
for(;;)
{
s=OSQPend(qf,0,&err);
y++;
if(err==OS_NO_ERR)
{
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
s="TA1";
PC_DispStr(x,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_TIMEOUT)
{
s="TA1 OS_TIMEOUT~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_ERR_PEND_ISR)
{
s="TA1 OS_ERR_PEND_ISR~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_ERR_EVENT_TYPE)
{
s="TA1 OS_ERR_EVENT_TYPE~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
OSTimeDlyHMSM(0,0,3,0);
}
}
void TA2(void *pdata)
{
#if OS_CRITICAL_METHOD==3
OS_CPU_SR cpu_sr;
#endif
pdata=pdata;
for(;;)
{
s=OSQPend(qf,0,&err);
y++;
if(err==OS_NO_ERR)
{
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
s="TA2";
PC_DispStr(x,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_TIMEOUT)
{
s="TA2 OS_TIMEOUT~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_ERR_PEND_ISR)
{
s="TA2 OS_ERR_PEND_ISR~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_ERR_EVENT_TYPE)
{
s="TA2 OS_ERR_EVENT_TYPE~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
OSTimeDlyHMSM(0,0,3,0);
}
}
void TA3(void *pdata)
{
#if OS_CRITICAL_METHOD==3
OS_CPU_SR cpu_sr;
#endif
pdata=pdata;
for(;;)
{
s=OSQPend(qf,0,&err);
y++;
if(err==OS_NO_ERR)
{
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
s="TA3";
PC_DispStr(x,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_TIMEOUT)
{
s="TA3 OS_TIMEOUT~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_ERR_PEND_ISR)
{
s="TA3 OS_ERR_PEND_ISR~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_ERR_EVENT_TYPE)
{
s="TA3 OS_ERR_EVENT_TYPE~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
OSTimeDlyHMSM(0,0,3,0);
}
}
void TA4(void *pdata)
{
#if OS_CRITICAL_METHOD==3
OS_CPU_SR cpu_sr;
#endif
pdata=pdata;
for(;;)
{
s=OSQPend(ql,0,&err);
y++;
if(err==OS_NO_ERR)
{
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
s="TA4";
PC_DispStr(x,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_TIMEOUT)
{
s="TA4 OS_TIMEOUT~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_ERR_PEND_ISR)
{
s="TA4 OS_ERR_PEND_ISR~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_ERR_EVENT_TYPE)
{
s="TA4 OS_ERR_EVENT_TYPE~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
OSTimeDlyHMSM(0,0,3,0);
}
}
void TA5(void *pdata)
{
#if OS_CRITICAL_METHOD==3
OS_CPU_SR cpu_sr;
#endif
pdata=pdata;
for(;;)
{
s=OSQPend(ql,0,&err);
y++;
if(err==OS_NO_ERR)
{
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
s="TA5";
PC_DispStr(x,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_TIMEOUT)
{
s="TA5 OS_TIMEOUT~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_ERR_PEND_ISR)
{
s="TA5 OS_ERR_PEND_ISR~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_ERR_EVENT_TYPE)
{
s="TA5 OS_ERR_EVENT_TYPE~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
OSTimeDlyHMSM(0,0,3,0);
}
}
void TA6(void *pdata)
{
#if OS_CRITICAL_METHOD==3
OS_CPU_SR cpu_sr;
#endif
pdata=pdata;
for(;;)
{
s=OSQPend(ql,0,&err);
y++;
if(err==OS_NO_ERR)
{
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
s="TA6";
PC_DispStr(x,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_TIMEOUT)
{
s="TA6 OS_TIMEOUT~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_ERR_PEND_ISR)
{
s="TA6 OS_ERR_PEND_ISR~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_ERR_EVENT_TYPE)
{
s="TA6 OS_ERR_EVENT_TYPE~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
OSTimeDlyHMSM(0,0,3,0);
}
}
void TaskCon(void *pdata)
{
#if OS_CRITICAL_METHOD==3
OS_CPU_SR cpu_sr;
#endif
pdata=pdata;
OS_ENTER_CRITICAL();
PC_VectSet(0x08,OSTickISR);
PC_SetTickRate(OS_TICKS_PER_SEC);
OS_EXIT_CRITICAL();
OSStatInit();
OSTaskCreate(TA1,0,&TA1Stk[TASK_STK_SIZE-1],1);
OSTaskCreate(TA2,0,&TA2Stk[TASK_STK_SIZE-1],2);
OSTaskCreate(TA3,0,&TA3Stk[TASK_STK_SIZE-1],3);
OSTaskCreate(TA4,0,&TA4Stk[TASK_STK_SIZE-1],4);
OSTaskCreate(TA5,0,&TA5Stk[TASK_STK_SIZE-1],5);
OSTaskCreate(TA6,0,&TA6Stk[TASK_STK_SIZE-1],6);
for(;;)
{
int i;
if(OSTimeGet()>500)
{
OSQFlush(qf);
for(i=0;i<6;i++)
{
s="massage";
err=OSQPostFront(qf,s);
}
OSQQuery(qf,&data);
sprintf(s,"%d",data.OSNMsgs);
y++;
PC_DispStr(x+35,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
//OSQDel(&ql,&err);
}
for(i=0;i<3;i++)
{
s="LIFO massage";
err=OSQPostFront(qf,s);
y++;
if(err==OS_NO_ERR)
{
s="TaskCon LIFO OS_NO_ERR~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_MBOX_FULL)
{
s="TaskCon LIFO OS_MBOX_FULL~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_ERR_EVENT_TYPE)
{
s="TaskCon LIFO OS_ERR_EVENT_TYPE~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
}
for(i=0;i<3;i++)
{
s="FIFO massage";
err=OSQPost(ql,s);
y++;
if(err==OS_NO_ERR)
{
s="TaskCon FIFO OS_NO_ERR~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_MBOX_FULL)
{
s="TaskCon FIFO OS_MBOX_FULL~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
else if(err==OS_ERR_EVENT_TYPE)
{
s="TaskCon FIFO OS_ERR_EVENT_TYPE~";
PC_DispStr(x+3,y,s,DISP_BGND_BLACK+DISP_FGND_WHITE);
}
}
if(PC_GetKey(&key)==TRUE)
{
if(key==0x1B)
{
PC_DOSReturn();
}
}
OSTimeDlyHMSM(0,0,2,0);
}
}
void main()
{
OSInit();
PC_DOSSaveReturn();
PC_VectSet(uCOS,OSCtxSw);
qf=OSQCreate(&Queuef[0],QUEUE_SIZE);
ql=OSQCreate(&Queuel[0],QUEUE_SIZE);
OSTaskCreate(TaskCon,(void*)0,&TaskConStk[TASK_STK_SIZE-1],7);
OSStart();
}
本实验中,设计了6个普通应用任务:
TA0(优先级为1)、TA1(优先级为2)、
TA2(优先级为3)、TA3(优先级为4)、
TA4(优先级为5)、TA5(优先级为6),
以及一个控制任务TaskCon(优先级为7)。
TaskCon每隔2秒向LIFO队列、FIFO队列中分别放三条信息。
若成功放入则显示 OS_NO_ERR。
TA0~TA5五个任务每隔3秒分别向不同的队列中取信息。
成功取得则显示 massage。
由于TA任务优先级高于TaskCon,所以在TaskCon放入第一条信息后,TA0立刻获取消息,运行并显示massage。然后TaskCon显示没有出错。
在经过500个单位时间时,TaskCon清空FIFO消息队列,然后向队列中连续发送6条消息,然后查询消息数并显示,结果如图,显示为6。
由于发送消息速度比接受消息快,所以在第一次轮回后,开始先发后收。队列中的信息随时间累积,最终会返回满队信息。
该函数用于建立一个消息队列。任务或中断可以通过消息队列向一个或多个任务发送消息。消息的含义是和具体的应用密切相关的。
函数原型:OS_EVENT *OSQCreate( void **start, INT8U size);
参数说明:
start 是消息内存区的首地址,消息内存区是一个指针数组。
Size 是消息内存区的大小。
返回值:
OSQCreate()函数返回一个指向消息队列控制块的指针。如果没有空闲的控制块,OSQCreate()函数返回空指针。
该函数用于任务等待消息。消息通过中断或任务发送给需要的任务。消息是一个指针变量,在不同的应用中消息的具体含义不同。如果调用OSQPend()函数时队列中已经存在消息,那么该消息被返回给OSQPend()函数的调用者,该消息同时从队列中清除。如果调用OSQPend()函数时队列中没有消息,OSQPend()函数挂起调用任务直到得到消息或超出定义的超时时间。如果同时有多个任务等待同一个消息,μC/OS-Ⅱ默认最高优先级的任务取得消息。一个由OSTaskSuspend()函数挂起的任务也可以接受消息,但这个任务将一直保持挂起状态直到通过调用OSTaskResume()函数恢复任务的运行。
函数原型:Void *OSQPend( OS_EVENT *pevent, INT16U timeout, INT8U *err);
参数:
pevent 是指向消息队列的指针,该指针的值在建立该队列时可以得到。(参考OSMboxCreate()函数)。
Timeout 允许一个任务以指定数目的时钟节拍等待消息。超时后如果还没有得到消息则恢复成就绪状态。如果该值设置成零则表示任务将持续地等待消息,最大的等待时间为65535个时钟节拍。这个时间长度并不是非常严格的,可能存在一个时钟节拍的误差。
Err 是指向包含错误码的变量的指针。OSQPend()函数返回的错误码可能为下述几种:
返回值:
OSQPend()函数返回取得的消息并将*err置为OS_NO_ERR。如果没有在指定数目的时钟节拍内接受到消息,OSQPend()函数返回空指针并将*err设置为OS_TIMEOUT。
该函数用于向消息队列发送消息。OSQPostFront()函数和OSQPost()函数非常相似,不同之处在于OSQPostFront()函数将发送的消息插到消息队列的最前端。也就是说,OSQPostFront()函数使得消息队列按照后入先出(LIFO)的方式工作,而不是先入先出(FIFO)。消息是一个指针长度的变量,在不同的应用中消息的含义也可能不同。如果队列中已经存满消息,则此调用将返回错误码。OSQPost()函数也是如此。在调用此函数时如果有任何任务在等待队列中的消息,则最高优先级的任务将得到这个消息。如果等待消息的任务优先级比发送消息的任务优先级高,那么高优先级的任务在得到消息后将立即抢占当前任务执行,也就是说,将发生一次任务切换。
函数原型:INT8U OSQPostFront(OS_EVENT *pevent, void *msg);
参数:
pevent 是指向即将接收消息的消息队列的指针。该指针的值在建立队列时可以得到。(参考OSQCreate()函数)。
Msg 是即将发送的消息的指针。不允许传递一个空指针。
返回值:
OSQPost()函数的返回值为下述之一:
该函数用于向消息队列发送消息。消息是一个指针长度的变量,在不同的应用中消息的含义也可能不同。如果队列中已经存满消息,则此调用返回错误码。如果有任何任务在等待队列中的消息,则最高优先级的任务将得到这个消息。如果等待消息的任务优先级比发送消息的任务优先级高,那么高优先级的任务将在得到消息后立即抢占当前任务执行,也就是说,将发生一次任务切换。消息是以先入先出(FIFO)方式进入队列的,即先进入队列的消息先被传递给任务。
函数原型:INT8U OSQPost(OS_EVENT *pevent, void *msg);
参数:
pevent 是指向即将接受消息的消息队列的指针。该指针的值在建立队列时可以得到。(参考OSQCreate()函数)。
Msg 是即将发送给队列的消息。不允许传递一个空指针。
返回值:
OSQPost()函数的返回值为下述之一:
该函数用于清空消息队列。
函数原型:INT8U *OSQFlush(OS_EVENT *pevent);
参数:
pevent 是指向消息队列的指针。该指针的值在建立队列时可以得到。(参考OSQCreate()函数)。
返回值:
OSQFlush()函数的返回值为下述之一:
该函数用来取得消息队列的信息。用户程序必须建立一个OS_Q_DATA的数据结构,该结构用来保存从消息队列的控制块得到的数据。通过调用该函数可以知道是否有任务在等待消息、有多少个任务在等待消息、队列中有多少消息以及消息队列可以容纳的消息数。OSQQuery()函数还可以得到即将被传递给任务的消息。
函数原型:INT8U OSQQuery(OS_EVENT *pevent, OS_Q_DATA *pdata);
参数:
pevent 是指向消息队列的指针。该指针的值在建立消息队列时可以得到。(参考OSQCreate()函数)。
Pdata 是指向OS_Q_DATA数据结构的指针,该数据结构包含下述成员:
Void *OSMsg; /* 下一个可用的消息*/
INT16U OSNMsgs; /* 队列中的消息数目*/
INT16U OSQSize; /* 消息队列的大小 */
INT8U OSEventTbl[OS_EVENT_TBL_SIZE]; /* 消息队列的等待队列*/
INT8U OSEventGrp;
返回值:
OSQQuery()函数的返回值为下述之一:
该函数用于删除指定的消息队列。
该函数用于将一个任务延时若干时间。延时的单位是小时、分、秒、毫秒。调用OSTimeDlyHMSM()后,如果延时时间不为0,系统将立即进行任务调度。
函数原型: void OSTimeDlyHMSM( INT8U hours,INT8U minutes,INT8U seconds,INT8U milli);
参数:
hours为延时小时数,范围从0-255。
minutes为延时分钟数,范围从0-59。
seconds为延时秒数,范围从0-59
milli为延时毫秒数,范围从0-999。
需要说明的是,操作系统在处理延时操作时都是以时钟节拍为单位的,实际的延时时间是时钟节拍的整数倍。如果系统时钟节拍的间隔是10ms,而设定延时为5ms的话,则不会产生延时操作;而如果设定延时为15ms,则实际的延时是两个时钟节拍,也就是20ms。
返回值:
OSTimeDlyHMSM()的返回值为下述之一: