到目前为止,所有的线程间通信方法都只用于触发线程的执行;他们不支持线程间的数据交换。很明显,在实际程序中,我们需要在线程之间移动数据。这可以通过读取和写入全局变量来完成,这种方式,除了一个非常简单的程序之外,尝试保证数据完整性将非常困难并且容易出现无法预料的错误。 线程之间的数据交换需要更正式的异步通信方法。
CMSIS-RTOS提供了两种线程之间的数据传输方法。 第一种方法是消息队列,它在两个线程之间创建缓冲数据“管道”。 消息队列旨在传输整数值。
第二种形式的数据传输是邮件队列。 这与消息队列非常相似,只是它传输数据块而不是单个整数。
消息和邮件队列都提供了一种在线程之间传输数据的方法。这允许您将设计视为由数据流互连的对象(线程)的集合。数据流由消息和邮件队列实现。 这提供了数据传输的缓冲区和线程之间良好定义的通信接口。基于通过邮件和消息队列连接的线程的系统级设计开始,您可以编写项目的不同子系统,如果在团队中工作,这很有用。此外,由于每个线程都有明确定义的输入和输出,因此很容易隔离以进行测试和代码复用。
基于RTOS的项目的系统级视图包括由消息和邮件队列形式的数据流连接的线程对象。
消息队列
设置消息队列,我们首先需要分配内存资源。
osMessageQId Q_LED; /*声明消息队列ID*/
osMessageQDef (Q_LED,16_Message_Slots,unsigned int);
/*定义消息队列结构体, 消息队列ID,
16_Message_Slots指示空间大小为16,unsigned int指示空间类型*/
这定义了具有16个存储元素的消息队列。 在此特定队列中,每个元素都定义为unsigned int。
虽然我们可以将数据直接发布到消息队列中,但也可以发布指向数据对象的指针。
osEvent result;
我们还需要定义一个osEvent变量,该变量将用于检索队列数据。 osEvent变量是一个联合体变量,允许您以多种格式从消息队列中检索数据。
union{
uint32_t v
void *p
int32_t signals
}value
osEvent联合体可以将您将发布到消息队列的数据作为unsigned int或void指针读取。 一旦创建了内存资源,我们就可以在一个线程中声明消息队列。
Q_LED = osMessageCreate(osMessageQ(Q_LED),NULL); /*在进程中创建消息队列*/
一旦创建了消息队列,我们就可以从一个线程将数据放入队列。
osMessagePut(Q_LED,0x0,osWaitForever); /*在进程中发送数据到消息队列*/
然后从另一个队列中读取。
result = osMessageGet(Q_LED,osWaitForever); /* 在另一进程中获取消息队列数据*/
LED_data = result.value.v;
消息队列联系
在本练习中,我们将研究在两个线程之间定义消息队列,然后使用它来发送过程数据。
在Pack Installer中选择“Ex 16 Message Queue”并将其复制到教程目录中。
打开Main.c并查看消息队列初始化代码。
int main (void) {
LED_Init ();
Q_LED = osMessageCreate(osMessageQ(Q_LED),NULL);
我们在主线程中定义和创建消息队列以及事件结构。
osMessagePut(Q_LED,0x1,osWaitForever);
osDelay(100);
然后在其中一个线程中,我们可以发布数据并在第二个线程中接收数据。
result = osMessageGet(Q_LED,osWaitForever);
LED_On(result.value.v);
构建项目并启动调试器。
在led_thread1中设置断点。
现在运行代码并在数据到达时观察数据。
自己实现的一个小例子:https://download.youkuaiyun.com/download/white_loong/10833909