消息队列数据结构如下:

typedef struct os_q {

struct os_q *OSQPtr; /* 在空闲队列控制块中链接所有的队列控制块*/

void *OSQStart; /*指向消息队列的指针数组的起始地址的指针*/

void *OSQEnd; /* 指向消息队列结束单元的下一个地址的指针*/

void *OSQIn; /* 指向消息队列中插入下一条信息位置的指针*/

void *OSQOut; /* 指向消息队列中下一个取出消息位置的指针*/

INT16U OSQSize; /* 消息队列中总的单元数*/

INT16U OSQEntries; /*消息队列中总的消息数量*/

} OS_Q;

图2为消息队列信息流的演示说明。

① CanSendMessageProcess任务完成信息的计算工作以后,将要发送的信息送进消息队列1。

② CanSendMessage任务负责取得消息队列1里面的信息。

③ 通过CAN总线I/O端口将数据发送到总线上去。如果消息队列中没有信息,则该任务由运行状态进入等待状态,直到从消息队列中接收到信息为止。

④ CanReceiveMessage任务负责读取总线上面的信息。

⑤ CanReceiveMessage任务将读取到的信息送入消息队列2。

⑥ CanReceiveMessageProcess任务是从消息队列2中取出信息开始计算工作,如果消息队列为空的话,该任务进入等待状态。

消息队列适用于一对一、一对多、多对多和多对一的关系。也就是说,消息队列可以作为一块共享的公共区域,为实施互斥,任务间需要同步;为了合作,进程间需要交换信息,这样也就实现了同步和通信。

 

基于多任务信息流的CAN总线驱动设计

(2)邮箱通信机制

邮箱的概念和管道(管线)有相似的定义,一个任务或者中断服务子程序向另一个任务发送一个指针型的变量,该指针指向一个包含了特定“消息”的数据结构。在源端的任务只能向邮箱写,在目的端的任务只能从邮箱读。邮箱传输流数据,即连续的字节串或流。因此,访问一个邮箱就像是访问一个顺序文件。邮箱可以用来通知一个事件的发生(发送一条信息),也可以用来共享某些资源,这样邮箱就被当成一个二值信号量。

图3为邮箱信息流的演示说明。

① CanSendMessageProcess任务将计算好的数据发送给CanSendMessage任务,然后进入就绪态等待应答信号。CanSendMessage在接收的同时发送应答握手信号给CanSendMessageProcess,确认信息接收完毕。

②CanSendMessage任务将CanSend MessageProcess任务发送来的信息发送到CAN总线,发送结束后进入就绪态等待下一次传输工作。

③ CanReceiveMessage任务接收来自总线的信息流,将接收到的信息发送到Can ReceiveMessageProcess任务,进入就绪态等待应答信号。