ucos通信邮箱的理解

  学习过信号量之后再来看邮箱,发现他们是非常相似的,甚至有时候邮箱可以当做信号量来使用,邮箱相对信号量而言,只是多传递一个指针变量

和信号量相似,ucos提供了5个对邮箱操作的函数它们是:

1.建立一个邮箱,OSMboxCreate()

2.等待一个邮箱的消息  OSMboxPend()

3.发送一个消息到邮箱,OSMboxPost()

4.无等待从邮箱中得到一个消息,OSMboxAccept();

5.查询一个邮箱的状态 OSMboxQuery();

使用邮箱之前,必须先建立该邮箱,该操作可以通过调用OSMboxCreate函数来完成,并且要指定指针的初始化值,一般情况下,这个初始值是NULL,

但也可以初始化一个邮箱,使其在最开始就包含一条消息,如果使用邮箱的目的是用来通知任务某一个事件已经发生(发送一条消息),那么就要初始化该邮箱为null,

如果用户用邮箱来共享资源,那么就要初始化该邮箱为一个非null指针,在这种情况下,该邮箱被当成一个二值信号量使用

  OS_EVENT *OSMboxCreate(void *msg)

  {

       OS_EVENT *pevent;

       OS_ENTER_CRITICAL();

       pevent =OSEventFreeList;

      if(OSEventFreeList!=(OS_EVENT*)0){

                   OSEventFreeList=(OS_EVENT*)OSEventFreeList->OSEventPtr;

     }

      OS_EXIT_CRITICAL();

      if(pevent!=(OS_EVENT*)0)

     {

        pevent->OSEventType=OS_EVENT_TYPE_MBOX;   (1)

       pevent->OSEventPtr=msg                   (2)

        OSEventWaitListInit(pevent);            

 

     }

      return (pevent) ;  (3)

 

  }

仔细看看,其实和创建一个信号量的过程几乎是一样的,先申请一个空事件控制块,接着初始化这个事件控制块,最后返回一个纸箱这个事件控制块的,不同之处在于事件

控制块的类型被设置成OS_EVENT_TYPE_MBOX 以及使用OSEventPtr来容纳消息指针。

 

接着来看等待邮箱函数实现代码:

void *OSMboxPend(OS_EVENT *pevent,INT16U timeout,INT8U *err)

{

    void *msg;

     OS_ENTER_CRITICAL();

     if(pevent->OSEventType!=OS_EVENT_TYPE_MBOX)                 (1)

    {

              OS_EXIT_CRITICAL();

             *err=OS_ERR_EVENT_TYPE;

               return((void*)0);

     }

        msg=pevent->OSEventPtr;

        if(msg!=(void*)0)                        (2)

       {

            pevent->OSEventPtr=(void*)0;              (3)

           OS_EXIT_CRITICAL();

           *err=OS_NO_ERR;

     }else if(OSIntNesting>0)                       (4)

     {

              OS_EXIT_CRITICAL();

               *err=OS_ERR_PEND_ISR;

     }

     else

     {

            OSTCBCur->OSTCBStat|=OS_STAT_MBOX;              (5)

           OSTCBCur->OSTCBDly=timeout;

           OSEventTaskWait(pevent);

           OS_EXIT_CRITICAL();

           OSSched();

           OS_ENTER_CRITICAL();

            if((msg=OSTCBCur->OSTCBMsg)!=(void*)0)          (6)

           {

                       OSTCBCur->OSTCBMsg =(void*)0;

                      OSTCBCur->OSTCBStat=OS_STAT_RDY;

                      OSTCBCur->OSTCBEventPtr=(OS_EVENT*)0;

                       OS_EXIT_CRITICAL();

                      *err =OS_NO_ERR;

           }

          else if(OSTCBCur->OSTCBStat&OS_STAT_MBOX)      (7)

         {

                    OSEventTo(pevent);            (8)

                   OS_EXIT_CRITICAL();       

                   msg   =(void*)0;                    (9)

                    *err  =OS_TIMEOUT;

         }

        else

         {

                   msg =pevent->OSEventPtr;    (10);

                  pevent->OSEventPtr  =(void*)0;           (11)

                  OSTCBCur->OSTCBEventPtr =(OS_EVENT*)0;        (12)

                 OS_EXIT_CRITICAL();

                  *err  =OS_NO_ERR;

          }

 

    }

        return(msg);

}

同样,它和OSSemPend()也相似,说白了就是先看有没有有用的消息,要使没有,就该把任务挂起来。

OSMboxPend首先检查该事件控制块是由OSMboxCreate()函数建立(1)。当OSEventPtr域是一个非

NULL的指针时,说明该邮箱有可用的消息(2);这种情况下,OSMboxPend()函数将该域的值复制到句柄变量

msg中,然后将OSEventPtr置为null,这正是我们期望的,也是执行OSMboxPend函数最快的路径。

如果此时邮箱中没有消息是可用的额(OSEventPtr域是null指针),OSMboxPend函数检查它的调用者是否是中断服务子程序。

像OSSemPend函数一样,不能在中断服务子程序中调用OSMboxPend(),因为中断服务子程序是不能等待的,但是如果邮箱有可用的消息,

即使从中断服务子程序中调用OSMboxPend()函数,也一样是成功的。如果没有可用的消息,OSMboxPend的调用任务就被挂起,直到邮箱中有了

消息或者等待超时时(5).当有其它任务向该邮箱发送了消息(或等待时间超时时),这时,该任务再一次成为最高任务优先级任务,OSSched()返回,这时,

OSMboxPend()函数要检查是否有消息被放到该任务的任务控制块中(6),如果有,那么该函数调用成功,对应的消息被返回到调用的函数

 

发送一个消息到邮箱中OSMboxPost()的代码如下:

INT8U OSMboxPost(OS_EVENT *pevent,void *msg)

{

   OS_ENTER_CRITICAL();

   if(pevent->OSEventType!=OS_EVENT_TYPE_MBOX)     (1)

  {

              OS_EXIT_CRITICAL();

             return(OS_ERR_EVENT_TYPE);

  }

if(pevent->OSEventGrp)                                 (2)

{

     OSEventTaskRdy(pevent,msg,OS_STAT_MBOX);        (3)

      OS_EXIT_CRITICAL();

      OSSched();                    (4)

      return(OS_NO_ERR);

}

else

{

    if(pevent->OSEventPtr!=(void*)0)             (5)

  {

        OS_EXIT_CRITICAL();

       return(OS_MBOX_FULL);

 }

 else

{

    pevent->OSEventPtr =msg  ;                         (6)

    OS_EXIT_CRITICAL();

    return(OS_NO_ERR);

}

}

}

 

 

发送一个消息到邮箱和发送一个信号量也相似,就丝毫查看有没有任务在等待这个消息,如果有就把哪个任务从睡眠态拉回就就绪态。

代码的详细解释如下:

检查了事件控制块是否是一个邮箱后(1),OSMboxPost()函数还要检查是否有任务等待该邮箱汇总的消息(2)。如果事件控制块中的OSEventGrp域包含非零值,

就暗示有任务在等待该消息,这时,调用OSEventTaskRdy()将其中的最高级优先级任务从等待列表中删除,加入系统的就绪任务列表中,准备运行,然后,调用OSSched()(4)函数,检查该任务十分是系统中最高优先级的就绪任务,如果是,这些任务切换【仅当OSMboxPost()】函数是由任务调用时,该任务得以执行,如果该任务不是最高优先级的任务,OSSched()返回,OSMboxPost()的调用函数继续执行,如果没有任务任务等待该消息,指向消息的指针就被保存到邮箱中(6)(假设此时邮箱汇总的指针不是非NULL的【5】),这样,下一个调用OSMboxPend函数的任务就可以立刻得到该消息了。

#define  TASK_STK_SIZE   512

char *s ;//MyTask发送的消息指针,

char *ss;//YouTask接收到的消息的指针

INT8U err;

INT8U y=0;

INT32U Times=0;

OS_EVENT *Str_Box;  //定义事件控制块指针,定义消息邮箱的指针

OS_STK    StartTask[TASK_STK_SIZE];

OS_STK     MyTaskStk[TASK_STK_SIZE];

OS_STK     YouTaskStk[TASK_STK_SIZE];

void StartTask(void *data);

void MyTask(void *data);

void YouTask(void *data);

void main(void)

{

    OSInit();

    Str_Box=OSMboxCreate((void*)0);//创建消息邮箱,返回值指向创建消息邮箱指针,初始值为null 表示创建的消息邮箱没有内容。

     OSTaskCreate(StartTask,(void*)0,&StartTaskStk[TASK_STK_SIZE-1],0); 

    OSStart();

}

 

void StartTask(void *pdata)

{

#if OS_CRITICAL_METHOD==3

    OS_CPU_SR   cpu_sr;

#endif

   INT16S  key;

   pdata=pdata;

   OSStatInit();

       OSTaskCreate(MyTask,(void*)0,&StartTaskStk[TASK_STK_SIZE-1],1); 

           OSTaskCreate(YouTask,(void*)0,&StartTaskStk[TASK_STK_SIZE-1],2); 

   for(;;)

   {

         if(PC_GetKey(&key)==TRUE)

         {

              if(key==0x1B)

              {

                     PC_DOSReturn();

                }

         }

               OSTimeDlyHMSM(0,0,3,0);

   }

}

 

void MyTask(void *pdata)

{

#if OS_CRITICAL_METHOD==3

     OS_CPU_SR  cpu_sr;

#endif

    pdata=pdata;

  for(;;)

  {

       sprintf(s,"%d",times);//把Times赋值给s

        OSMboxPost(Str_Box,s);//发送消息s 其中两个参数Str_Box是OS_EVENT *pevent表示消息邮箱指针,s是void*msg表示消息指针

                                                 该函数表示把消息s发送到消息邮箱Str_Box中

             Times++;//MyTask的运行次数加1

            OSTimeDlyHMSM(0,0,1,0);

  }

}

 

void YouTask(void *pdata)

{

  #if OS_CRITICAL_METHOD==3

    OS_CPU_SR cpu_sr;

  #endif

   pdata=pdata;

   for(;;)

    {

         ss=OSMboxPend(Str_Box,10,&err);//请求消息邮箱参数表示:Str_Box是消息邮箱指针,10表示等待时间 ss是邮箱中的消息指针

          OSTimeDlyHMSM(0,0,1,0);   //等待1s

    }

 

}

//OSMboxPend时指定等待时间为10,所以当等待时间到了,即使邮箱中还是无消息,YouTask也会进入就绪态的,然后继续往下运行,但是

 当OSMboxPend的等待时间设置为0,表示无限等待。

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值