_C_OS_消息邮箱的通讯机制及其应用
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Task2 这两个任务组成,其中 Task1 的优先级设为
比 Task2 高。Task1 负责具体的清洗过程;Task2
负责检测水温和液位,并及时将检测结果通知
Task1。 下 面 是 程 序 的 主 要 代 码 , 其 硬 件 平 台 为
LPC2214,集成开发环境为 ADS1.2。
程序清单 5 消息邮箱通讯实例
hongjunbj@163.com。 通 讯 作 者 : 王 建 平 ( 1959-), 男 , 北 京 人 , 教 授 ,( E-mail) wjp
@cau.edu.cn。
中断服务 或任务
发信号
邮箱
等待
任务
超时
图 1 消息邮箱示意图
Fig.1 Sketch map of mailbox
1.1 事件控制块 ECB 分析消息邮箱的通讯机制需要了解 ECB 的数据
(1)
if(msg !=(void *)0){ pevent->OSEventPtr
= (void*)0; return (msg); }
(2)
OSTCBCur->OSTCBDly = timeout; (3)
OSEventTaskWait (pevent);
OSSched();
msg = OSTCBCur->OSTCBMsg;
- 173 -
2007 年 12 月
农机化研究
第 12 期
的,其主要代码如下:
程序清单 2 创建一个邮箱
OS_EVENT *OSMboxCreate (void *msg)
{…
OS_EVENT *pevent;
pevent = OSEventFreeList;
if (pevent != (OS_EVENT *)0) {
CoolValveClose();}
//水温过低
if(msg->Level==‘F’)Wash(); // 清 洗 液
已满
}
}
void Task2(void *pdata)
{
for(;;){
Determine(&data);
// 检 测 函
数,并将检测结果存放到结构体 data 中
OSMboxPost (MsgBox, &data);
结构(见程序清单 1)。大部分 μC/OS-II 的通 讯机 制都是通过它来完成的,其中也包括消息邮箱。
程序清单 1 ECB 的数据结构 typedef struct {
INT8U OSEventType; //事件类型 INT16U OSEventCnt; //计数器 void *OSEventPtr; // 指 向 任 意 类 型的指针 INT8U OSEventGrp; // 等 待 任 务 所 在的组 INT8U OSEventGrp [OS_EVENT_TBL_SIZE]; //等待任务列表 } OS_EVENT; OSEventType 用于记录事件的类型,可以是信 号量、消息队列、互斥信号量或者消息邮箱中的一 种。当 ECB 用于邮箱时,OSEventCnt 没有被使用。 OSEventPtr 用作消息指针,指向任意的消息类型, 而 OSEventGrp 和 OSEventGrp 用来记录等待该邮箱 的任务。 1.2 创建邮箱 使用消息邮箱进行任务间的通讯需要创建一个 邮箱,而邮箱的创 建是通过 OSMboxCreate()来 完成
Struct MyStruct *msg;//指向要传递的消息
Struct MyStruct data; //自定义结构体 ,用
于记录水温和液位
MsgBox = OSMboxCreate(NULL);
TimeDly = OSMboxCreate(NULL);
void Task1(void *pdata)
OS_EVENT 类型指针,任务 函数通过它 即可对邮 箱进
行存取操作[5]。
1.3 向邮箱发送消息
消息邮箱创建后,可 以通过函数 OSMboxPost()
向邮箱发送一则消息。其关键代码如下:
程序清单 3 向邮箱发送消息
INT8U OSMboxPost (OS_EVENT *pevent, void
*msg)
{…
if (pevent->OSEventGrp != 0x00)
{
(1)
OS_EventTaskRdy(pevent,msg,
OS_STAT_MBOX);
OSSched();
return (OS_NO_ERR);
}
if (pevent->OSEventPtr != (void *)0)
return (OS_MBOX_FULL);
(4)
if(msg != (void *)0) return (msg); (5)
OSEventTO(pevent);
(6)
*err = OS_TIMEOUT;
return ((void *)0);
}
从 ECB 中取出消息(1),判 断它是否为 空。如果 不 为 空 (2), 消 息 有 效 , 清 空 邮 箱 , 然 后 返 回 消 息 ; 如果为空(3),说明该 ECB 中没 有消息,把当前 任务 控制块的 OSTCBDly 的值设为 timeout,以便进 行超 时处理,并调用 OSEventTaskWait()把当前任务从 就绪列表中删除,在相应的 ECB 中记录此任务,以 表明此任务正在等待消息;最后,通过 OSSched() 进行任务调度,由于当前任务已经从就绪列表中删 除 , OSSched() 从 就 绪 列 表 中 选 出 优 先 级 最 高 的 任 务,保存现场后将 CPU 控制权交给它,并进行任务 切换。
1.4 从邮箱接收消息
当任务需要查询消息邮箱中是否有消息时,可 以使用 OSMboxPend()函数,其关键代码如下:
程序清单 4 查询邮箱中的消息
Fra Baidu bibliotek
void *OSMboxPend (OS_EVENT *pevent, INT16U
timeout, INT8U *err)
{…
msg = pevent->OSEventPtr;
2007 年 12 月
农机化研究
第 12 期
μC/OS-II 消息邮箱的通讯机制及其应用
洪 俊,王建平
(中国农业大学 信息与电气工程学院,北京 100083)
摘 要:为深入理解μC/OS-II 消息邮箱的通讯机制,使嵌入式系统能够得以充分与合理地运用,查找了 μ C/OS-II 消 息 邮 箱 的 源 代 码 ,并 对 其 进 行 了 深 入 的 剖 析 ,从 根 本 上 揭 示 了 μ C/OS-II 消 息 邮 箱 的 通 讯 机 制 , 并以一个移植到 LPC2214 的实例说明消息邮箱在挤奶机自动清洗控制中的应用。结果表明,消息邮箱不但 可以替代全局变量作为任务间的通讯方式,消除其带来的负作用,而且可以作为二值信号量使用,避免资 源使用冲突,实现系统的延时作用,是一种简洁与高效的通讯机制。 关键词:畜牧学;挤奶机自动清洗控制器;应用;嵌入式系统;任务通讯;消息邮箱 中图分类号:S817.2+1;TP316.2; 文献标识码:A 文章编号:1003—188X(2007)12—0173—03
OSMboxPend (TimeDly,100,&err);
}
}
程序首先创建两 个消息邮箱 ,其中 MsgBox 用于
控制水温和液位,而 TimeDly 用来控制系统延时。
由于 Task1 的优先级高,根据 μC/OS-II 调度规 则,
Task1 首先得到运行。
Task1 开始调用 WashInit()对水洗过程进行初
- 174 -
2007 年 12 月
农机化研究
第 12 期
2 消息邮箱在挤奶机自动清洗控制中的应用
在挤奶机自动清洗控制器的研制过程中,运用
消息邮箱进行任 务间的通讯 ,代替了 部分μC/OS-II
的 功 能 函 数 。现 通 过 清 洗 控 制 器 中 的 预 洗 子 程 序 [6],
来说明消息邮箱的应用。预洗程序主要由 Task1 和
邮 箱 , 以 免 其 他 通 讯 机 制 误 用 ; 其 次 , OSEventPtr
指向需要传递的消息,通过它实现消息的传递;最
后,调用 OS_EventWaitListInit()将该 ECB 中的
OSEventGrp 和 OSEventTbl 初始 化为 0,表示没 有任
务等待该邮箱中的消息。邮箱建立后将得到
0 引言
近年来,嵌入式设备的应用日益广泛,随着用 户需求的不断提高,嵌入式设备在功能上变得日趋 复杂化,各个模块之间需要及时地通讯,以实现整 个设备的协调工作。因此,简洁与高效的通讯机制 逐渐成为嵌入式开发人员关注的焦点[1]。
现有的通讯机制主要包括共享内存、动态数据 交 换 、信 号 量 、消 息 管 道 、消 息 邮 箱 和 邮 件 槽 等 [2,3]。 μC/OS-II 的消息邮箱就是其中一种,它不但可以 传送任何类型的消息实现任务间的通讯,而且可以 实现系统延时,作为二值信号量使用。
{
WashInit();
for(;;){
msg = (Struct MyStruct)OSMboxPend
(MsgBox,0,&err);
if(msg->Temp
==
‘H’)
{ HotValveClose(); CoolValveOn()}
//水温过高
if(msg->Temp == ‘L’) { HotValveOn();
1 消息邮箱的通讯机制
消息邮箱通讯机制如图 1 所示。中断服务或任 务都可以向邮箱发送消息,而只有任务才可以等待 查询邮箱。μC/OS-II 通过创建邮箱、向邮箱发送 消息与等待查询消息等服务来完成任务间的通讯。
收稿日期:2007-03-30 基金项目:北京市重大农业攻关项目(20030204) 作 者 简 介 :洪 俊 (1983-),男 ,云 南 建 水 人 ,硕 士 研 究 生 ,(E-mail)
始化(如打开相应 指示灯、电磁阀,进 水一段时 间), 然后调用 OSMboxPend()查询等待 消息。此时,Task1 被挂起,Task2 得到执行。Task2 对水 温和液位 进行 检测,将检测结果放到 data 结构体中;然后调用 OSMboxPost()向邮箱 MsgBox 发送消息,μC/OS-II 重新调度,Task1 恢复执行。Task1 根据 msg 指针指 向的数据结构 data 得知水 温高低,打 开或关闭 相应 的冷水阀与热水 阀。如果清洗 液已满,则调用 Wash() 进行清洗工作;如果液位还未达到要求,则循环调 用 OSMboxPend()查询等待消息,Task2 恢复执行, 调用 OSMboxPend()查 询邮箱 TimeDly 中的消 息,并 将超时时限定为 100。因为创建 TimeDly 时邮箱为 空,且没有其他任务或 ISR 向该邮箱发消息,所以 函数将等待超时 退出,相当于 OSTimeDly(100)的作 用。此时 ,Task1 和 Task2 均被挂起 ,LPC2214 可以 处理其他任务 。100 个时钟节 拍后,Task2 苏醒 ,循 环 检 测 水 温 和 液 位 , 将 数 据 发 送 到 MsgBox 中 供 Task1 使用,直到液位满 足要求可以 开始清洗为 止。
(2)
pevent->OSEventPtr =msg;
(3)
return (OS_NO_ERR);
}
检查该 ECB 的 OSEventGrp 是否为 0。如果不等
于 0(1),说 明已经有其 他任务在等 待此消息 ,调
用 OS_EventTaskRdy()计算出等待此消息的任务中
优先级最高的任务,将此优先级最高的任务从等待
pevent->OSEventType=OS_EVENT_TYP
E_MBOX; //将事件类型设为邮箱
pevent->OSEventPtr = msg;
OS_EventWaitListInit(pevent);
}
return (pevent);
}
首先,函数从空闲的 ECB 链表中取出一块分配
给消息邮箱,如果分配成功,则将事件类型设置为
列表中清除,并将其记录在就绪列表中以备查询, 然后执行任务调度函数 OSSched()进行任务切换。 如果 OSEventGrp 为 0(2),则说明没有任务在等待 消息,此时函数判断邮箱是否为空。如果不为空, 则返回消息已满的错误码(消息邮箱只能存放一条 消 息 ); 如 果 邮 箱 为 空 (3), 则 把 消 息 放 入 邮 箱 。
当需要实现任务间或中断服务与任务间的通讯 时,最简单的办法就是使用全局变量,同时必须保 证每个任务或中断服务子程序独享该变量[4],而且 任务还需要不断周期性地查询变量的值。使用μ C/OS-II 的消息邮箱可以很好地解决这个问题,为 此分析了μC/OS-II 消息邮箱的通讯机制,并举例 说明其在挤奶机自动清洗控制系统中的应用。
当程序再次得到执行时,从当前任务控制块中 取 出 消 息 (4), 并 判 断 是 否 为 空 。 如 果 不 为 空 (5), 说明其他任务或者 ISR 已经向邮箱发送了一则消 息,此时返回消息,完成调用;如果消息依然为空 (6),说明没有其他任务或 ISR 向该邮箱发送消息, 程序是因为等待超时后恢复执行的。调用 OSEventTO()将该任务从 ECB 的等待任务列表中清 除,然后函数返回。函数调 用完成后,可以 通过 err 查询错误码。