FreeRTOS 中的队列是任务之间进行通信的一种重要机制。通过队列,任务可以发送和接收数据,从而实现同步和数据共享。
队列又称消息队列,是一种常用于任务间通信的数据结构,队列可以在任务与任务间、中断和任务间传递信息,实现任务接收来自其他任务或中断的不固定长度的消息,任务能够从队列中读取消息,当队列中的消息是空时,读取消息的任务将被阻塞,用户还可以指定阻塞的任务时间xTicksToWait,在这段时间中,如果队列是空,该任务将保持阻塞状态以等待队列数据有效。当队列中有新消息时,被阻塞的任务会被唤醒并处理新消息:当等待的时间超过了指定的阻塞时间,即使队列中尚无有效数据,任务也会自动从阻塞态转为就绪态。消息队列是一种异步的通信方式。
通过消息队列服务,任务或中断服务例程可以将一条或多条消息放入消息队列中,同样,一个或多个任务可以从消息队列中获得消息。当有多个消息发送到消息队列时,通常是将先进入消息队列的消息先传给任务,也就是说,任务先得到的是最先进入消息队列的消息,即先进先出原则(FIFO),但是也支持后进先出原则(LIFO)。
队列的基本操作
-
创建队列: 使用
xQueueCreate()
函数可以创建一个队列。该函数需要两个参数:队列的长度和每个队列项的大小。QueueHandle_t xQueue = NULL; xQueue = xQueueCreate(10, sizeof(int));
-
发送数据到队列: 使用
xQueueSend()
或xQueueSendToBack()
函数可以将数据发送到队列中。这些函数需要队列句柄、要发送的数据和等待时间作为参数。xQueueSend()
用于向队列尾部发送一个队列消息。消息以拷贝的形式入队,而不是以引用的形式。该函数不能在中断服务程序里面调用,中断中需使用带有中断保护功能的xQueueSendFromISR()
代替。xQueueSendToFront()
用于向队列队首发送一个消息。消息以拷贝的形式入队。该函数不能在中断服务程序里面调用,中断中需使用带有中断保护功能的xQueueSendToFrontFromISR()
代替。int data = 100; xQueueSend(xQueue, &data, portMAX_DELAY);//中断中需使用此函数 xQueueSendFromISR(xQueue, &data, portMAX_DELAY);
-
从队列接收数据: 使用
xQueueReceive()
函数可以从队列中接收数据。该函数需要队列句柄、接收缓冲区和等待时间作为参数。xQueueReceive()
用于从一个队列中接收消息并把消息从队列中删除。接收的消息是以拷贝 的形式进行的,所以我们必须提供一个足够大空间的缓冲区。该函数绝不能在中断服务程序里面被调用,而是必须使用带有中断保护功能的xQueueReceiveFromISR ()
来代替。int receivedData; xQueueReceive(xQueue, &receivedData, portMAX_DELAY);
队列的应用场景
队列在 FreeRTOS 中有广泛的应用,例如:
- 任务间通信:一个任务可以将数据发送到队列中,另一个任务可以从队列中接收数据,从而实现任务间的通信。
- 中断处理:中断服务程序可以将数据发送到队列中,任务可以从队列中接收数据,从而实现中断处理与任务之间的通信。
- 事件管理:通过队列可以实现事件的管理和处理,例如按键事件、传感器事件等。
通过合理使用队列,可以提高系统的响应性和数据处理效率。
队列的高级操作
-
队列的删除: 使用
vQueueDelete()
函数可以删除一个队列。删除队列后,所有试图访问该队列的任务都会收到错误。if (xQueue == NULL) {} else {vQueueDelete(xQueue); }
-
阻塞时间: 当队列为空时,
xQueueReceive()
函数可以选择阻塞一段时间,等待队列中有数据可用。当队列已满时,xQueueSend()
函数也可以选择阻塞,直到队列有空位。
实战示例
假设我们有一个传感器任务,它定期读取传感器数据并将其发送到队列中。另一个任务负责从队列中读取数据并进行处理。
传感器任务
void vSensorTask(void *pvParameters) {int sensorData;for (;;) {// 读取传感器数据sensorData = readSensor();// 发送数据到队列xQueueSend(xQueue, &sensorData, portMAX_DELAY);// 延时一段时间vTaskDelay(pdMS_TO_TICKS(1000));}
}
数据处理任务
void vProcessingTask(void *pvParameters) {int receivedData;for (;;) {// 从队列接收数据if (xQueueReceive(xQueue, &receivedData, portMAX_DELAY) == pdPASS) {// 处理接收到的数据processData(receivedData);}}
}
通过上述示例,我们可以看到如何通过队列在不同任务之间进行数据传输和处理,从而实现任务之间的协同工作。
欢迎指出博客中的错误,如果你觉得对你有用,记得点赞三连,有问题可留言,会及时回复