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

和信号量相似,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,表示无限等待。

ucos通信邮箱的理解相关推荐

  1. (三.0)通过FPGA实现以太网通信原理及理解

    0.0 OSI模型的简单理解 OSI(Open System Interconnect),即开放式系统互联.一般都叫OSI参考模型,是ISO(国际标准化组织)组织在1985年研究的网络互联模型.该体系 ...

  2. UCOS III 任务堆栈理解

    UCOS III在创建任务时,调用OSTaskStkInit函数,以初始化正在创建的任务的堆栈框架. 1:堆栈就是一段连续的空间.用于存储数据的,在c计算机中有很多应用,比如发生中断时保存现场,c语言 ...

  3. iic通信的深入理解(主从设备通信)

    虽然之前也研究了先iic同行基本的时序你弄明白了,可是在机子写at24c02驱动的时候由于理解不够透彻出了点问题. 一.写数据 24c02的写入数据,可以看到主从设备iic中写的过程:起始信号-> ...

  4. 串口通信与并口通信的浅理解

    在说到通信的时候,一般都会提到窜口通信和并口通信的问题,以前一直都是听别人说,我一点也不明白,毕竟这个概念还是偏硬件了点,但是人还是要往前进的,今天多google了几下,总结了下理解方式,算是一次学习 ...

  5. 对WIFI通信的一些理解(经常更新修改)

    1.WIFI模块配置的指令形式是什么? 指令形式是字符串,上位机或MCU通过串口连接WIFI芯片,发送指令协议中对应的字符串,实质就是发送这些字符串对应的ASCII码值.WIFI 芯片接受到这些字符串 ...

  6. 香农公式--通信的浅显理解--单纯只是为了弄懂功率和信道容量的关系

    笔记的目标:简单梳理功率和信道容量的关系 其中主要是为了弄明白论文<Spectrum Sharing in Vehicular Networks Based on Multi-Agent Rei ...

  7. 关于ucos的邮箱、信号量使用步骤

    OS_EVENT * sem; //信号量指针 OS_EVENT * msg;            //邮箱事件块指针 //开始任务 void start_task(void *pdata) {   ...

  8. LTE中基本通信过程的理解——上行调度

    上行调度 1. UE向ENB请求上行资源 Physical channel: PUCCH Message: SR (schedule request) 根据上层的配置UE按照一定的周期和子帧位置上通过 ...

  9. TencentOS-tiny 任务间通信(九)- 邮箱队列

    一.任务间通信 邮箱队列 概述 消息队列传递的是指针,邮箱队列传递的是大片的内存数据. API讲解 编程实例 1.在tos_config.h中,配置邮箱队列组件开关TOS_CFG_MAIL_QUEUE ...

最新文章

  1. spring boot分环境导出自定义xml配置
  2. 根目录android结构,android系统盘根目录中的(文件)谁给讲一下是干什么的?
  3. while循环里嵌套一个if_if-else嵌套太深?教你一个新手都能掌握的设计模式搞定!...
  4. css less 不要作用到子对象_使用Less实现网站主题切换
  5. 每天一杯C_Visual Studio各个版本的区别和总结
  6. APP违法使用个人信息?不用怕,华为云VSS为你保驾护航
  7. 揭秘阿里中台!一文看懂阿里推荐业务的两项利器 | 赠书
  8. MySQL主从复制中关于AUTO_INCREMENT的奇怪问题
  9. 【2022】【论文笔记】基于激光直写氧化石墨烯纸的超薄THz偏转——
  10. 往十年不忘初心,新十年不负韶华丨万字长文带你完整回顾2020数据技术嘉年华...
  11. 什么是Autorun病毒?它的运作原理是什么?如何手工清除?
  12. python爬虫-Day02
  13. 新浪短网址api接口——5个可生成新浪t.cn短链的在线工具网站评测
  14. 嘉为科技出席2021腾讯云启产业生态年会,荣获“年度通用明星奖”
  15. STM32F103使用L9110s驱动直流电机(必须简单易懂)
  16. QMdiSubWindow
  17. 使用python在pycharm中制作二维码
  18. Struts2注解配置之@Action(二)
  19. 不动点迭代方程收敛判据及MATLAB实现
  20. 如何开启Chrome内核浏览器(360极速版、QQ、UC)的多线程下载模式来提高浏览器的下载速度?

热门文章

  1. Note For Linux By Jes(14)-启动流程、模块管理与 Loader
  2. 计算机逻辑算法,算法逻辑
  3. UDT 最新源码分析(五) -- 网络数据收发
  4. JSP页面之间传值的方法总结
  5. sql查询记录数大于1
  6. 《微信公众平台与小程序开发——从零搭建整套系统》——第1章,第1.2节微信公众平台...
  7. 因为「Web3.0」,推特创始人被自己的投资人拉黑了
  8. 正则表达 包含 英文、数字、特殊字符
  9. android 打开系统键盘的方法
  10. 机械革命计算机配置,单品:机械革命X6Ti-S_机械革命笔记本电脑_笔记本评测-中关村在线...