一、消息邮箱的概念:
由图可见:消息邮箱里装的是消息缓冲区的地址
消息邮箱是uC/OS-II中的一种通信机制,可以使一个任务或者中断服务子程序向另一个任务发送一个指针型的变量,而该指针指向一个包含了“消息(的地址)”的特定数据结构(参:消息邮箱 百度百科)。具体描述如下:
为了适应不同数据在任务之间的传递,需要在存储器中建立一个数据缓冲区,把要传递的数据放在这个缓冲区里就能实现任务之间的通信;如果把数据缓冲区的指针赋给一个事件控制块的成员OSEventPrt,同时使事件控制块的成员OSEventType为常数OS_EVENT_TYPE_MBOX(此过程在消息邮箱创建函数里已实现,用户不用管),则该事件控制块就是消息邮箱。由此可见,消息邮箱就是一个特定的事件控制块。事件控制块如下:
typedef struct
{
INT8U OSEventType;//事件的类型
INT16U OSEventCnt;//信号量计数器
void *OSEventPtr;//消息或消息队列的指针
INT8U OSEventGrp;//等待事件的任务组
INT8U OSEventTbl[OS_EVENT_TBL_SIZE];//任务等代表
} OS_EVENT;
若定义一个事件控制块:OS_EVENT *pEvent;
还定义一个空类型的指针:void *pMsg;
则消息邮箱需要具备的基本条件是:
pEvent->OSEventType = OS_EVENT_TYPE_MBOX;
pEvent->OSEventPtr = msg;
此时事件控制块pEvent就是一个邮箱(次要条件在此不考虑)。
二、消息邮箱的相关函数:
(1)创建消息邮箱函数:OS_EVENT *OSMboxCreate(void *pMsg)//pMsg为消息的指针(初始值一般为(void*)0))
(2)向消息邮箱发送消息函数:INT8U OSMboxPost(OS_EVENT *pEventT, void *pMsg)
(3)请求消息邮箱函数:void *OSMboxPend(OS_EVENT *pEvent, INT16U timeout, INT8U *err) //timeout为超时定义,任务若在指定数目的时钟节拍后还没有得到消息则恢复运行;若timeout为0则任务将持续等待消息直到收到消息才进入就绪。但最大的等待时间为65535个时钟节拍。
(4)查询邮箱状态函数:INT8U OSMboxQuery(OS_EVENT *pEvent, OS_MBOX_DATA *pData)
(5)删除邮箱函数:OS_EVENT *OSMboxDel(OS_EVENT *pEvent, INT8U opt, INT8U *err)
三、消息邮箱的应用(创建、发送、请求)举例:
…………;//代码省略部分
OS_EVENT *pMsgBox;//定义事件控制块指针(指向消息邮箱)
…………;
void main(void)
{
…………;
pMsgBox = OSMboxCreate((void *)0);//(1)创建消息邮箱
OSTaskCreate(StartTask, (void *)0, &StartTaskStk[TASK_STK_SIZE - 1], 0);//创建起始任务
…………;
return 0;
}
void StartTask(void *pData)
{
…………;
//创建任务1
OSTaskCreate(MyTask, (void *)0, &MyTaskStk[TASK_STK_SIZE - 1], 1);
//创建任务2
OSTaskCreate(YouTask, (void *)0, &YouTaskStk[TASK_STK_SIZE - 1], 2);
…………;
}
//任务1
void MyTask(void *pData)
{
INT32U Times = 0;
char *pMsg;
…………;
while (1)
{
sprintf(pMsg, "%d", Times);//记录运行次数
OSMboxPost(pMsgBox, pMsg);//(2)向消息邮箱发送消息
Times++;
OSTimeDlyHMSM(0, 0, 1, 0);//延时1秒
}
}
//任务2
void YouTask(void *pData)
{
char *pStr;
…………;
while (1)
{
pStr = OSMboxPend(pMsgBox, 10, &err);//(3)请求消息邮箱
PC_DispStr(10, ++y, pStr, DISP_BGND_BLACK + DISP_FGND_WHITE);
OSTimeDlyHMSM(0, 0, 1, 0);//延时1秒
}
}
现象:输出结果为0、1、2、3……
解析:任务1中Times每自增一次都会被sprintf函数转换为字符串,且将其地址保存在pMsg中,然后将其作为消息(的指针)发送给邮箱;程序运行到任务2中时,再将邮箱中的消息取出打印出来。
注:消息邮箱中装的是消息的地址而不是消息本身,发送消息时也是发送的消息的地址!
参考: 任哲 《嵌入式实时操作系统uC/OS-II原理及应用》