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,表示无限等待。
ucos通信邮箱的理解相关推荐
- (三.0)通过FPGA实现以太网通信原理及理解
0.0 OSI模型的简单理解 OSI(Open System Interconnect),即开放式系统互联.一般都叫OSI参考模型,是ISO(国际标准化组织)组织在1985年研究的网络互联模型.该体系 ...
- UCOS III 任务堆栈理解
UCOS III在创建任务时,调用OSTaskStkInit函数,以初始化正在创建的任务的堆栈框架. 1:堆栈就是一段连续的空间.用于存储数据的,在c计算机中有很多应用,比如发生中断时保存现场,c语言 ...
- iic通信的深入理解(主从设备通信)
虽然之前也研究了先iic同行基本的时序你弄明白了,可是在机子写at24c02驱动的时候由于理解不够透彻出了点问题. 一.写数据 24c02的写入数据,可以看到主从设备iic中写的过程:起始信号-> ...
- 串口通信与并口通信的浅理解
在说到通信的时候,一般都会提到窜口通信和并口通信的问题,以前一直都是听别人说,我一点也不明白,毕竟这个概念还是偏硬件了点,但是人还是要往前进的,今天多google了几下,总结了下理解方式,算是一次学习 ...
- 对WIFI通信的一些理解(经常更新修改)
1.WIFI模块配置的指令形式是什么? 指令形式是字符串,上位机或MCU通过串口连接WIFI芯片,发送指令协议中对应的字符串,实质就是发送这些字符串对应的ASCII码值.WIFI 芯片接受到这些字符串 ...
- 香农公式--通信的浅显理解--单纯只是为了弄懂功率和信道容量的关系
笔记的目标:简单梳理功率和信道容量的关系 其中主要是为了弄明白论文<Spectrum Sharing in Vehicular Networks Based on Multi-Agent Rei ...
- 关于ucos的邮箱、信号量使用步骤
OS_EVENT * sem; //信号量指针 OS_EVENT * msg; //邮箱事件块指针 //开始任务 void start_task(void *pdata) { ...
- LTE中基本通信过程的理解——上行调度
上行调度 1. UE向ENB请求上行资源 Physical channel: PUCCH Message: SR (schedule request) 根据上层的配置UE按照一定的周期和子帧位置上通过 ...
- TencentOS-tiny 任务间通信(九)- 邮箱队列
一.任务间通信 邮箱队列 概述 消息队列传递的是指针,邮箱队列传递的是大片的内存数据. API讲解 编程实例 1.在tos_config.h中,配置邮箱队列组件开关TOS_CFG_MAIL_QUEUE ...
最新文章
- spring boot分环境导出自定义xml配置
- 根目录android结构,android系统盘根目录中的(文件)谁给讲一下是干什么的?
- while循环里嵌套一个if_if-else嵌套太深?教你一个新手都能掌握的设计模式搞定!...
- css less 不要作用到子对象_使用Less实现网站主题切换
- 每天一杯C_Visual Studio各个版本的区别和总结
- APP违法使用个人信息?不用怕,华为云VSS为你保驾护航
- 揭秘阿里中台!一文看懂阿里推荐业务的两项利器 | 赠书
- MySQL主从复制中关于AUTO_INCREMENT的奇怪问题
- 【2022】【论文笔记】基于激光直写氧化石墨烯纸的超薄THz偏转——
- 往十年不忘初心,新十年不负韶华丨万字长文带你完整回顾2020数据技术嘉年华...
- 什么是Autorun病毒?它的运作原理是什么?如何手工清除?
- python爬虫-Day02
- 新浪短网址api接口——5个可生成新浪t.cn短链的在线工具网站评测
- 嘉为科技出席2021腾讯云启产业生态年会,荣获“年度通用明星奖”
- STM32F103使用L9110s驱动直流电机(必须简单易懂)
- QMdiSubWindow
- 使用python在pycharm中制作二维码
- Struts2注解配置之@Action(二)
- 不动点迭代方程收敛判据及MATLAB实现
- 如何开启Chrome内核浏览器(360极速版、QQ、UC)的多线程下载模式来提高浏览器的下载速度?
热门文章
- Note For Linux By Jes(14)-启动流程、模块管理与 Loader
- 计算机逻辑算法,算法逻辑
- UDT 最新源码分析(五) -- 网络数据收发
- JSP页面之间传值的方法总结
- sql查询记录数大于1
- 《微信公众平台与小程序开发——从零搭建整套系统》——第1章,第1.2节微信公众平台...
- 因为「Web3.0」,推特创始人被自己的投资人拉黑了
- 正则表达 包含 英文、数字、特殊字符
- android 打开系统键盘的方法
- 机械革命计算机配置,单品:机械革命X6Ti-S_机械革命笔记本电脑_笔记本评测-中关村在线...