今天,做了uc/OS-II系统的消息循环的实验,写一些收获。
先说说消息机制的原理。通过消息循环可以实现基于时间驱动的应用程序,即每一个事件都会产生特定的消息,然后这个消息被发送到某个/某些任务消息队列中,任务读取到消息后作出相应的处理。任务消息队列一般采用FIFO结构,即最先发送的消息任务会最先读取到。
用uc/OS实现的系统消息循环感觉类似windows编程的消息机制。系统不断轮询来从消息队列中取出最近的消息进行处理。当然,用uc/OS实现的消息机制就要比windows的简单多了。在uc/OS中,通信机制里面有一种就是消息队列,通过这种通信方式我们就能在uc/OS中实现我们的消息机制。
在uc/OS中,消息队列可以工作与一对一的工作方式,即一个任务发送消息到消息队列,而另一个任务从消息队列中读取消息。这种方式简单也常用。另外还有一种多对一的工作方式,即多个任务发送消息队列到同一个消息队列,而另外只有一个任务从这个消息队列中读取信息,这种即是我们实现消息机制需要用到的工作方式。当然,消息队列还有其他工作方式,但是都不常用。
我们把消息队列作为任务消息队列,然后任务就可以通过读取消息队列中的消息来获取消息。当然,一般哪个任务需要处理消息循环才会建立相应自己的任务消息队列。消息的储存需要空间,所以还需要定义一个数组来进行消息的储存。因为消息的类型不同,所以数组的类型为void。而将任务队列与任务消息队列存储区连接起来的关键就是OS_EVENT *OSQCreate (void **start, INT16U size)消息队列创建函数。任务消息的队列创建需在启动uc/OS之前。
实验中用到的关于消息函数已经有现成的了。在任务消息头文件中,我们可以自定义消息。
如:
#define TM_KEY 5762
#define TM_KEYDOWN 5763
......
定义好消息结构体
typedef struct tagMSG
{
uint32 message; // 消息值
uint32 wParam; // 消息附加信息1
uint32 lParam; // 消息附加信息2
} MSG;
然后是最重要的两个消息函数SendMessage()和GetMessage()。
/****************************************************************************
* 名称:SendMessage()
* 功能:发送一个消息,即消息发送管理器。
* 根据实际情况,将消息分派到不同的任务消息队列中。
* 入口参数:msg 所要发送的消息(指针)
* 出口参数:操作成功返回TRUE,否则返回FALSE。
****************************************************************************/
uint8 SendMessage(MSG *msg)
{
uint32 message;
TMQ *target;
uint8 err;
message = msg->message;
switch(message)
{
case TM_KEY:
case TM_KEYDOWN:
case TM_KEYUP:
target = task_tmq; // 若是键盘消息,向task1_tmq任务消息队列发送
break;
case TM_UART0RCV:
target = task_tmq; // 若是串口接收消息,向task1_tmq任务消息队列发送
break;
// (在此添加用户任务消息分派处理)
default: target = NULL;
break;
}
err = OSQPost(target, msg);
if(err==OS_NO_ERR)
return(TRUE);
else
return(FALSE);
}
/****************************************************************************
* 名称:GetMessage()
* 功能:等待一个消息。当接收到消息时才返回。
* 入口参数:tmq 等待的任务消息队列(指针)
* 出口参数:返回接收到的消息。
****************************************************************************/
MSG *GetMessage(TMQ *tmq)
{
uint8 err;
return(OSQPend(tmq, 0, &err));
}
具体实现的代码就不用写了,重要是这个思想和实现方法。