µC/OS-II 示例 ucos消息队列

在本实验中,设计了6个普通应用任务:TA0(优先级为1)、TA1(优先级为2)、TA2(优先级为3)、TA3(优先级为4)、TA4(优先级为5)、TA5(优先级为6),以及一个控制任务TaskCon(优先级为7)。

µC/OS-II中,等待消息的任务总是按照优先级的高低来决定获得消息的顺序的。

具体的设计思路为:

  • 创建队列的功能:创建一个等待属性为FIFO的消息队列1;创建一个等待属性为LIFO的消息队列2。
  • 考察以FIFO方式释放消息的消息队列:由任务TA0、TA1、TA2等待队列1中的消息。
  • 考察以LIFO方式释放消息的消息队列:由任务TA3、TA4、TA5等待队列2中的消息。
  • 考察清空消息队列、查询消息队列的功能:TaskCon任务向队列2中连续发送6条消息,然后查询消息数;清空该队列后再查询。

程序:

#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();
}

结果:

µC/OS-II 示例 ucos消息队列_第1张图片

本实验中,设计了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。

由于发送消息速度比接受消息快,所以在第一次轮回后,开始先发后收。队列中的信息随时间累积,最终会返回满队信息。

µC/OS-II相关函数:

1 OSQCreate()

    该函数用于建立一个消息队列。任务或中断可以通过消息队列向一个或多个任务发送消息。消息的含义是和具体的应用密切相关的。

函数原型:OS_EVENT  *OSQCreate( void **start, INT8U size);

参数说明:

start  是消息内存区的首地址,消息内存区是一个指针数组。

Size  是消息内存区的大小。

返回值:

OSQCreate()函数返回一个指向消息队列控制块的指针。如果没有空闲的控制块,OSQCreate()函数返回空指针。

2 OSQPend()

    该函数用于任务等待消息。消息通过中断或任务发送给需要的任务。消息是一个指针变量,在不同的应用中消息的具体含义不同。如果调用OSQPend()函数时队列中已经存在消息,那么该消息被返回给OSQPend()函数的调用者,该消息同时从队列中清除。如果调用OSQPend()函数时队列中没有消息,OSQPend()函数挂起调用任务直到得到消息或超出定义的超时时间。如果同时有多个任务等待同一个消息,μC/OS-Ⅱ默认最高优先级的任务取得消息。一个由OSTaskSuspend()函数挂起的任务也可以接受消息,但这个任务将一直保持挂起状态直到通过调用OSTaskResume()函数恢复任务的运行。

 

函数原:Void *OSQPend( OS_EVENT *pevent, INT16U timeout, INT8U *err);

 

参数:

    pevent  是指向消息队列的指针,该指针的值在建立该队列时可以得到。(参考OSMboxCreate()函数)。

    Timeout  允许一个任务以指定数目的时钟节拍等待消息。超时后如果还没有得到消息则恢复成就绪状态。如果该值设置成零则表示任务将持续地等待消息,最大的等待时间为65535个时钟节拍。这个时间长度并不是非常严格的,可能存在一个时钟节拍的误差。

    Err 是指向包含错误码的变量的指针。OSQPend()函数返回的错误码可能为下述几种:

  1. OS_NO_ERR :消息被正确地接受。
  2. OS_TIMEOUT :消息没有在指定的时钟周期数内接收到消息。
  3. OS_ERR_PEND_ISR :从中断调用该函数。虽然规定了不允许从中断中调用该函数,但μC/OS-Ⅱ仍然包含了检测这种情况的功能。
  4. OS_ERR_EVENT_TYPE  :pevent 不是指向消息队列的指针。

 

返回值:

OSQPend()函数返回取得的消息并将*err置为OS_NO_ERR。如果没有在指定数目的时钟节拍内接受到消息,OSQPend()函数返回空指针并将*err设置为OS_TIMEOUT。

3 OSQPostFront()

    该函数用于向消息队列发送消息。OSQPostFront()函数和OSQPost()函数非常相似,不同之处在于OSQPostFront()函数将发送的消息插到消息队列的最前端。也就是说,OSQPostFront()函数使得消息队列按照后入先出(LIFO)的方式工作,而不是先入先出(FIFO)。消息是一个指针长度的变量,在不同的应用中消息的含义也可能不同。如果队列中已经存满消息,则此调用将返回错误码。OSQPost()函数也是如此。在调用此函数时如果有任何任务在等待队列中的消息,则最高优先级的任务将得到这个消息。如果等待消息的任务优先级比发送消息的任务优先级高,那么高优先级的任务在得到消息后将立即抢占当前任务执行,也就是说,将发生一次任务切换。

 

函数原:INT8U OSQPostFront(OS_EVENT *pevent, void *msg);

 

参数:

    pevent  是指向即将接收消息的消息队列的指针。该指针的值在建立队列时可以得到。(参考OSQCreate()函数)。

Msg 是即将发送的消息的指针。不允许传递一个空指针。

 

返回值:

OSQPost()函数的返回值为下述之一:

  1. OS_NO_ERR :消息成功地放到消息队列中。
  2. OS_MBOX_FULL :消息队列已满。
  3. OS_ERR_EVENT_TYPE  :pevent 不是指向消息队列的指针。

4 OSQPost()

该函数用于向消息队列发送消息。消息是一个指针长度的变量,在不同的应用中消息的含义也可能不同。如果队列中已经存满消息,则此调用返回错误码。如果有任何任务在等待队列中的消息,则最高优先级的任务将得到这个消息。如果等待消息的任务优先级比发送消息的任务优先级高,那么高优先级的任务将在得到消息后立即抢占当前任务执行,也就是说,将发生一次任务切换。消息是以先入先出(FIFO)方式进入队列的,即先进入队列的消息先被传递给任务。

 

函数原型:INT8U OSQPost(OS_EVENT *pevent, void *msg);

 

参数:

pevent  是指向即将接受消息的消息队列的指针。该指针的值在建立队列时可以得到。(参考OSQCreate()函数)。

Msg 是即将发送给队列的消息。不允许传递一个空指针。

 

返回值:

OSQPost()函数的返回值为下述之一:

  1. OS_NO_ERR :消息成功地放到消息队列中。
  2. OS_MBOX_FULL :消息队列已满。
  3. OS_ERR_EVENT_TYPE  :pevent 不是指向消息队列的指针。

5 OSQFlush ()

该函数用于清空消息队列。

函数原型:INT8U *OSQFlush(OS_EVENT *pevent);

参数:

pevent  是指向消息队列的指针。该指针的值在建立队列时可以得到。(参考OSQCreate()函数)。

返回值:

OSQFlush()函数的返回值为下述之一:

  1. OS_NO_ERR :消息队列被成功清空
  2. OS_ERR_EVENT_TYPE :试图清除不是消息队列的对象

6 OSQQuery()

该函数用来取得消息队列的信息。用户程序必须建立一个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()函数的返回值为下述之一:

  1. OS_NO_ERR :调用成功
  2. OS_ERR_EVENT_TYPE  :pevent 不是指向消息队列的指针。

7 OSQDel() 

该函数用于删除指定的消息队列。

8 OSTimeDlyHMSM()

该函数用于将一个任务延时若干时间。延时的单位是小时、分、秒、毫秒。调用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()的返回值为下述之一:

  1. OS_NO_ERR:函数调用成功。
  1. OS_TIME_INVALID_MINUTES:参数错误,分钟数大于59。
  2. OS_TIME_INVALID_SECONDS:参数错误,秒数大于59。
  3. OS_TIME_INVALID_MILLI:参数错误,毫秒数大于999。
  4. OS_TIME_ZERO_DLY:四个参数全为0。

 

 

 

 

 

 

你可能感兴趣的:(µC/OS-II 示例 ucos消息队列)