FreeRTOS和RT-Thread的消息队列

一、FreeRTOS消息队列

1.1 创建消息队列

xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength,		// 队列消息最大个数
                          unsigned portBASE_TYPE uxItemSize );			// 单个消息最大字节

	uxQueueLength  队列能够存储的最大单元数目,即队列深度。
    uxItemSize  队列中数据单元的长度,以字节为单位。
    
    返回值
        NULL 表示没有足够的堆空间分配给队列而导致创建失败。
        非 NULL 值表示队列创建成功。此返回值应当保存下来,以作为
        操作此队列的句柄。

1.2 发送消息

xQueueSendToBack()用于将数据发送到队列尾;

xQueueSendToFront()用于将数据发送到队列首。

xQueueSend() 完全等同于 xQueueSendToBack()

portBASE_TYPE xQueueSendToFront(  xQueueHandle xQueue,  // 队列句柄
                                const void * pvItemToQueue, // 数据指针
                                portTickType xTicksToWait ); // 阻塞时间
portBASE_TYPE xQueueSendToBack( xQueueHandle xQueue,
                               const void * pvItemToQueue,
                               portTickType xTicksToWait );

切 记 不 要 在 中 断 服 务 例 程 中 调 用 xQueueSendToFront()xQueueSendToBack()。系统提供中断安全版本的xQueueSendToFrontFromISR()xQueueSendToBackFromISR() 用于在中断服务中实现相同的功能。

image-20201222223612913

image-20201222223631902

1.3 接受消息

xQueueReceive() 用于从队列中接收(读取)数据单元。接收到的单元同时会从队列中删除。

xQueuePeek() 也是从从队列中接收数据单元,不同的是并不从队列中删出接收到的单元。xQueuePeek() 从队列首接收到数据后,不会修改队列中的数据,也不会改变数据在队列中的存储序顺。

切记不要在中断服务例程中调用 xQueueRceive()xQueuePeek()。中断安全版本的替代 API 函数 xQueueReceiveFromISR()

portBASE_TYPE xQueueReceive(  xQueueHandle xQueue,	// 队列句柄
                            const void * pvBuffer,	// 数据指针
                            portTickType xTicksToWait );	// 超时时间
portBASE_TYPE xQueuePeek( xQueueHandle xQueue,
                         const void * pvBuffer,
                         portTickType xTicksToWait );

image-20201222223833463

image-20201222223844176

1.4 查询队列信息

uxQueueMessagesWaiting() 用于查询队列中当前有效数据单元个数。

切记不要在中断服务例程中调用 uxQueueMessagesWaiting()。应当在中断服务中使用其中断安全版本 uxQueueMessagesWaitingFromISR()

unsigned portBASE_TYPE uxQueueMessagesWaiting( xQueueHandle xQueue );	// 消息队列句柄
  • xQueue 被查询队列的句柄。这个句柄即是调用 xQueueCreate()创建该队列时的返回值。
  • 返回值 当前队列中保存的数据单元个数。返回 0 表明队列为空。

1.5 大量数据传输-注意事项

如果队列存储的数据单元尺寸较大,那最好是利用队列来传递数据的指针而不是对数据本身在队列上一字节一字节地拷贝进或拷贝出。传递指针无论是在处理速度上还是内存空间利用上都更有效。但是,当你利用队列传递指针时,一定要十分小心地做到以下两点:

  1. 指针指向的内存空间的所有权必须明确

    当任务间通过指针共享内存时,应该从根本上保证所不会有任意两个任务同时
    修改共享内存中的数据,或是以其它行为方式使得共享内存数据无效或产生一致性
    问题。原则上,共享内存在其指针发送到队列之前,其内容只允许被发送任务访问;
    共享内存指针从队列中被读出之后,其内容亦只允许被接收任务访问。

  2. 指针指向的内存空间必须有效

    如果指针指向的内存空间是动态分配的,只应该有一个任务负责对其进行内存
    释放。当这段内存空间被释放之后,就不应该有任何一个任务再访问这段空间。
    切忌用指针访问任务栈上分配的空间。因为当栈帧发生改变后,栈上的数据将不再
    有效。

二、RT-Thread 消息队列

image-20201222230105209

2.1 创建和删除消息队列

  • 创建
rt_mq_t rt_mq_create(const char* name, rt_size_t msg_size,  // 队列名称, 队列单条消息最大空间
                     rt_size_t max_msgs, rt_uint8_t flag);	// 消息最对容纳个数 消息队列灯等待方式

image-20201222230157566

  • 删除
rt_err_t rt_mq_delete(rt_mq_t mq);	// 消息队列的句柄

删除消息队列时,如果有线程被挂起在该消息队列等待队列上,则内核先唤醒挂起在该消息等待队列上的所有线程(线程返回值是 - RT_ERROR),然后再释放消息队列使用的内存,最后删除消息队列对象。下表描述了该函数的输入参数与返回值

image-20201222230255313

2.2 初始话和脱离消息队列

  • 初始话

初始化静态消息队列对象跟创建消息队列对象类似,只是静态消息队列对象的内存是在系统编译时由编译器分配的,一般放于读数据段或未初始化数据段中。在使用这类静态消息队列对象前,需要进行初始化。初始化消息队列对象的函数接口如下

rt_err_t rt_mq_init(rt_mq_t mq, const char* name,	// 消息队列句柄 消息队列名称
                    void *msgpool, rt_size_t msg_size,	
                    rt_size_t pool_size, rt_uint8_t flag);

初始化消息队列时,该接口需要用户已经申请获得的消息队列对象的句柄(即指向消息队列对象控制块的指针)、消息队列名、消息缓冲区指针、消息大小以及消息队列缓冲区大小。如下图所示,消息队列初始化后所有消息都挂在空闲消息链表上,消息队列为空。下表描述了该函数的输入参数与返回值

image-20201222230414993-

  • 脱离

脱离消息队列将使消息队列对象被从内核对象管理器中脱离。脱离消息队列使用下面的接口:

rt_err_t rt_mq_detach(rt_mq_t mq);

使用该函数接口后,内核先唤醒所有挂在该消息等待队列对象上的线程(线程返回值是 -RT_ERROR),然后将该消息队列对象从内核对象管理器中脱离。下表描述了该函数的输入参数与返回值

image-20201222230516815

2.3 发送消息

2.3.1 直接发送消息

线程或者中断服务程序都可以给消息队列发送消息。当发送消息时,消息队列对象先从空闲消息链表上取下一个空闲消息块,把线程或者中断服务程序发送的消息内容复制到消息块上,然后把该消息块挂到消息队列的尾部。当且仅当空闲消息链表上有可用的空闲消息块时,发送者才能成功发送消息;当空闲消息链表上无可用消息块,说明消息队列已满,此时,发送消息的的线程或者中断程序会收到一个错误码
(-RT_EFULL)。发送消息的函数接口如下:

rt_err_t rt_mq_send (rt_mq_t mq, void* buffer, rt_size_t size);

发送消息时,发送者需指定发送的消息队列的对象句柄(即指向消息队列控制块的指针),并且指定发送的消息内容以及消息大小。如下图所示,在发送一个普通消息之后,空闲消息链表上的队首消息被转移到了消息队列尾。下表描述了该函数的输入参数与返回值:

image-20201222230858226

2.3.2 延迟发送消息
rt_err_t rt_mq_send_wait(rt_mq_t mq,
                         const void *buffer,
                         rt_size_t size,
                         rt_int32_t timeout);

如果消息队列已经满了,那么发送线程将根据设定的 timeout 参数进行等待。如果设置的超时时间到达依然没有空出空间,这时发送线程将被
唤醒并返回错误码。下表描述了该函数的输入参数与返回值:

image-20201222231026053

2.3.3 发送紧急消息

当发送紧急消息时,从空闲消息链表上取下来的消息块不是挂到消息队列的队尾,而是挂到队首,这样,接收者就能够优先接收到紧急消息,从而
及时进行消息处理。发送紧急消息的函数接口如下:

rt_err_t rt_mq_urgent(rt_mq_t mq, void* buffer, rt_size_t size);

image-20201222231109668

2.4 接收消息

当消息队列中有消息时,接收者才能接收消息,否则接收者会根据超时时间设置,或挂起在消息队列的等待线程队列上,或直接返回。接收消息函数接口如下:

rt_err_t rt_mq_recv (rt_mq_t mq, void* buffer,
                     rt_size_t size, rt_int32_t timeout);

接收消息时,接收者需指定存储消息的消息队列对象句柄,并且指定一个内存缓冲区,接收到的消息内容将被复制到该缓冲区里。此外,还需指定未能及时取到消息时的超时时间。如下图所示,接收一个消息后消息队列上的队首消息被转移到了空闲消息链表的尾部。下表描述了该函数的输入参数与返回值:

image-20201222231230522

3. 消息队列的使用场景

消息队列可以应用于发送不定长消息的场合,包括线程与线程间的消息交换,以及中断服务例程中给线程发送消息(中断服务例程不能接收消息)。下面分发送消息和同步消息两部分来介绍消息队列的使用。

  1. 发送消息

a task通过消息队列给b task发送一个结构体,结构体里面包含数据信息,这样 a 和 b task就可以进行通信和交换数据了、

  1. 同步消息

a task通过消息队列给 b task发送结构体,完成数据交互, b task通过邮件简短回复a task 。 可以节省内存消耗。

image-20201222232045475

### 回答1: rt-threadfreertos 都是实时操作系统(RTOS),旨在为嵌入式系统提供可靠的多任务处理能力。 rt-thread 是一款开源的 RTOS,专门设计用于低功耗、小容量的嵌入式系统。rt-thread 采用了轻量级线程实现,支持信号量、互斥锁、消息队列等同步机制,并提供了丰富的驱动支持和组件,如 TCP/IP 协议栈、文件系统、GUI 界面等。rt-thread 的内核代码非常精简,可运行在 RAM 或者 ROM 上。 相比之下,freertos 同样是一款开源的 RTOS,但是功能更为丰富,支持更多的处理器架构,包括 ARM、MIPS、x86 等。freertos 提供了多任务调度、内存管理、IPC 机制、软件定时器等功能,并且还有完善的文档和社区支持。与 rt-thread 相比,freertos 的内核代码更加复杂,但是在可移植性和跨平台性方面表现更好。 综上所述,rt-thread 适合用于资源受限的嵌入式系统,而 freertos 则适用于更为复杂的系统,需要更多的功能和处理器架构支持。 ### 回答2: RT-ThreadFreeRTOS都是开源的实时操作系统(RTOS),主要用于嵌入式系统中。它们都提供了许多标准的功能,如多任务处理、线程同步和通信、定时器和时间管理等。但是,它们在一些方面有所不同,下面将对它们进行详细的比较。 首先,RT-Thread是一个面向对象的RTSOS。在RT-Thread中,所有的线程、设备驱动以及其他的系统对象都是对象。这使得它在处理复杂系统时更加容易。而FreeRTOS则是一个面向任务的RTSOS,这意味着它在调度和处理多个任务时更加强大和灵活,但是处理复杂系统时会更加困难。 其次,RT-Thread内置了很多功能模块,如文件系统、TCP/IP协议栈、USB驱动等,这些模块可以很方便地进行移植和使用。而FreeRTOS则需要额外的组件来实现这些功能。这使得RT-Thread更加适合处理复杂系统,而FreeRTOS则更加适合轻量级和低功耗的系统。 另外,RT-Thread提供了C++接口以及Lua脚本语言支持,可以方便地进行自定义扩展和应用开发。而FreeRTOS则只支持C语言,扩展和应用开发需要更多的工作量。 总的来说,RT-Thread适合处理复杂系统和大型项目,FreeRTOS适合轻量级和低功耗的应用。选择哪一个取决于项目的需求和特点。 ### 回答3: rt-threadfreertos是两种嵌入式实时操作系统,都具有轻量级、开源、定位于小型嵌入式设备等特点。它们的主要区别体现在以下几个方面: 1.架构和设计 rt-thread是一个基于“内核+组件”的架构设计,内核负责任务调度、内存管理、线程间通信等核心功能,组件则提供文件系统、网络协议栈等更高层次的服务;而freertos则采用了更为简单的内核设计,将任务抽象为优先级,通过优先级管理和调度任务。rt-thread的组件化设计使得系统功能更为完备,但也导致代码更为复杂,freertos则相对来说更为易于理解和实现。 2.可移植性 rt-thread支持多种平台和开发板,包括ARM Cortex-M、RISC-V、Xtensa等架构,同时也支持uClinux内核。这使得rt-thread具有很高的可移植性,能够适应不同类型的嵌入式设备;而freertos则针对特定芯片或板卡进行了优化,移植性相对来说较差。 3.资源占用情况 rt-thread在处理器内存和rom占用方面相对freertos更优,主要是因为rt-thread采用了更为灵活的组件化设计,能够根据实际需要选择加载不同的组件;而freertos则拥有更为紧凑的内核,能够在小型设备上运行。 4.社区支持和生态 rt-threadfreertos都是活跃的开源项目,拥有庞大的社区和完善的生态。但由于rt-thread的组件化设计和多平台支持,其组件库更丰富,社区支持也更活跃,可以提供更为全面的功能和应用支持。 综上所述,二者在应用场景上有着较为明显的区别,rt-thread适用于需求更为复杂、功能更为完备的嵌入式设备,而freertos则更适合资源有限、对实时性要求不高的小型设备。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

早睡的叶子

你的鼓励就是我的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值