7.FreeRTOS_邮箱

本文内容的基础知识点在博文 “ FreeRTOS_队列基础知识 ”中,博文链接如下:

FreeRTOS_队列基础知识-优快云博客

邮箱概述

邮箱的本质是一个长度为1的队列

当进行写邮箱时,队列中的数据会被覆盖,因此每次写邮箱一定成功,没有阻塞选择。

当进行读邮箱时,队列中的数据不会消失,因此写一次邮箱后,读邮箱就一定成功。

操作邮箱与操作队列的逻辑完全一致。

写邮箱

函数声明如下:

/* 这是一个宏,写邮箱 */
xQueueOverwrite( xQueue, pvItemToQueue )

/* 宏定义 */
#define xQueueOverwrite( xQueue, pvItemToQueue ) \
    xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), 0, queueOVERWRITE )

/* 真实调用的函数 */
BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
                              const void * const pvItemToQueue,
                              TickType_t xTicksToWait,
                              const BaseType_t xCopyPosition )

xQueue:队列的句柄,即:创建队列函数的返回值

pvItemToQueue:原始数据的指针

读邮箱

函数声明如下:

/* 读邮箱 */
BaseType_t xQueuePeek( QueueHandle_t xQueue,
                       void * const pvBuffer,
                       TickType_t xTicksToWait )

xQueue:队列的句柄,即:创建队列函数的返回值

pvItemToQueue:原始数据的指针

xTicksToWait :当队列为满时等待写入的时间。写0表示不等待,portMAX_DELAY表示死等

实验

验证读邮箱不会移除队列数据、写邮箱会覆盖队列内容

具体代码如下:

void Task1Function(void *param){

	int i;
	
	while(1){
		xQueuePeek((QueueHandle_t)param,&i,portMAX_DELAY);/* 读邮箱 */
		printf("%d",i);
	}
	
}

int main( void )
{
#ifdef DEBUG
  debug();
#endif
	
	TaskHandle_t xHandleTask1;
	QueueHandle_t QueueHandle_Test;/* 定义一个队列句柄,这是个指针 */
	int i = 0;
	
	prvSetupHardware();
	SerialPortInit();
	printf("UART TEST\r\n");
	
	QueueHandle_Test = xQueueCreate(1,sizeof(int));/* 创建队列 */
	if(QueueHandle_Test == NULL){
		printf("queue create fail\r\n");
	}
	xQueueOverwrite(QueueHandle_Test,&i);/* 写邮箱 */
	i++;
    xQueueOverwrite(QueueHandle_Test,&i);/* 写邮箱 */

	xTaskCreate(Task1Function,"Task1",100,(void*)QueueHandle_Test,2,&xHandleTask1);

	vTaskStartScheduler();
	
	return 0;
}

运行结果:

可以看到尽管在创建任务后不再邮箱,但Task1不断的输出1,这说明Task1并未因为不断读邮箱而阻塞,因此读邮箱并不清除队列的值。

在任务创建前,第一次写邮箱的值为0,第二次为1,这时Task打印的值为1,说明写邮箱会覆盖队列内容。

FreeRTOS中,队列和邮箱都是用于任务间通信的机制,但它们在功能和使用场景上有显著的区别。 ### 队列 队列是一种用于在任务之间传递数据的机制。它允许一个任务或中断服务例程(ISR)将数据发送到队列中,而另一个任务可以从队列中接收数据。队列可以配置为存储多个数据项,每个数据项的大小可以是任意的。队列的操作包括发送(`xQueueSend`)和接收(`xQueueReceive`),发送和接收操作都可以设置超时时间。 - **发送操作**:当一个任务或中断服务例程向队列发送数据时,如果队列已满,发送操作可以选择阻塞等待队列有空间可用。 - **接收操作**:当一个任务从队列接收数据时,如果队列为空,接收操作可以选择阻塞等待数据到达。 队列的容量可以根据需要进行配置,适用于需要处理多个数据项的场景。 ### 邮箱 邮箱是队列的一种特殊形式,通常用于存储单个数据项。创建邮箱时,队列的长度被设置为1,这意味着邮箱只能存储一个数据项。当一个新的数据项被发送到邮箱时,如果邮箱中已经有数据,旧的数据会被覆盖。这种特性使得邮箱非常适合用于传递最新的状态信息,而不关心历史数据。 - **发送操作**:当一个任务或中断服务例程向邮箱发送数据时,如果邮箱中已经有数据,旧的数据会被覆盖。 - **接收操作**:当一个任务从邮箱接收数据时,数据会被移除,但是一旦有新的数据被发送到邮箱,旧的数据就会被覆盖。 邮箱的这种特性使得它非常适合用于传递最新的状态信息,而不关心历史数据。 ### 使用场景 - **队列**:适用于需要处理多个数据项的场景,例如传感器数据的批量处理。 - **邮箱**:适用于只需要传递最新状态信息的场景,例如系统状态更新或配置参数的传递。 ### 示例代码 以下是一个创建邮箱的示例代码: ```c #include "FreeRTOS.h" #include "queue.h" // 创建一个邮箱,可以存储1个int类型的数据 QueueHandle_t mailbox = xQueueCreate(1, sizeof(int)); // 发送数据到邮箱 int data = 42; xQueueSend(mailbox, &data, portMAX_DELAY); // 从邮箱接收数据 int receivedData; if (xQueueReceive(mailbox, &receivedData, portMAX_DELAY) == pdTRUE) { // 处理接收到的数据 } ``` ### 总结 - **队列**:可以存储多个数据项,适用于需要处理多个数据项的场景。 - **邮箱**:只能存储一个数据项,新的数据会覆盖旧的数据,适用于传递最新的状态信息。 通过合理选择队列或邮箱,可以根据具体的应用需求优化任务间的通信机制
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值