跳到主要内容

STM32 FreeRTOS队列

介绍

在嵌入式系统中,任务之间的通信是一个非常重要的概念。FreeRTOS 提供了一种称为队列的机制,用于在任务之间传递数据。队列是一种先进先出(FIFO)的数据结构,允许多个任务安全地发送和接收数据。

在STM32微控制器上使用FreeRTOS时,队列是实现任务间通信的常用工具。通过队列,任务可以发送消息、数据或其他信息给其他任务,而无需直接访问共享资源,从而避免了潜在的竞争条件。

队列的基本概念

什么是队列?

队列是一种数据结构,允许数据按照先进先出的顺序进行存储和检索。在FreeRTOS中,队列可以用于任务之间传递数据,也可以用于任务与中断服务例程(ISR)之间的通信。

队列的特点

  • 线程安全:FreeRTOS队列是线程安全的,多个任务可以同时访问队列而不会导致数据损坏。
  • 阻塞和非阻塞操作:任务可以在发送或接收数据时选择阻塞或非阻塞模式。阻塞模式下,任务会等待直到队列有空间或数据可用;非阻塞模式下,任务会立即返回。
  • 动态或静态创建:队列可以在运行时动态创建,也可以在编译时静态分配。

创建和使用队列

创建队列

在FreeRTOS中,队列通过 xQueueCreate() 函数创建。该函数需要两个参数:队列的长度和每个队列项的大小。

c
QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize );
  • uxQueueLength:队列的长度,即队列中可以存储的最大项数。
  • uxItemSize:每个队列项的大小,以字节为单位。

例如,创建一个可以存储10个整数的队列:

c
QueueHandle_t xQueue = xQueueCreate(10, sizeof(int));

发送数据到队列

使用 xQueueSend() 函数将数据发送到队列。该函数有三个参数:队列句柄、要发送的数据的指针以及等待时间。

c
BaseType_t xQueueSend( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait );
  • xQueue:队列句柄。
  • pvItemToQueue:指向要发送的数据的指针。
  • xTicksToWait:如果队列已满,任务等待的最长时间。设置为 portMAX_DELAY 表示无限等待。

例如,发送一个整数到队列:

c
int data = 42;
xQueueSend(xQueue, &data, portMAX_DELAY);

从队列接收数据

使用 xQueueReceive() 函数从队列中接收数据。该函数也有三个参数:队列句柄、存储接收数据的指针以及等待时间。

c
BaseType_t xQueueReceive( QueueHandle_t xQueue, void * pvBuffer, TickType_t xTicksToWait );
  • xQueue:队列句柄。
  • pvBuffer:指向存储接收数据的缓冲区的指针。
  • xTicksToWait:如果队列为空,任务等待的最长时间。设置为 portMAX_DELAY 表示无限等待。

例如,从队列中接收一个整数:

c
int receivedData;
xQueueReceive(xQueue, &receivedData, portMAX_DELAY);

实际应用场景

任务间通信

假设我们有两个任务:一个任务负责采集传感器数据,另一个任务负责处理这些数据。我们可以使用队列将传感器数据从采集任务传递到处理任务。

c
// 采集任务
void vSensorTask(void *pvParameters) {
int sensorData;
while (1) {
// 采集传感器数据
sensorData = readSensor();
// 发送数据到队列
xQueueSend(xQueue, &sensorData, portMAX_DELAY);
vTaskDelay(pdMS_TO_TICKS(100)); // 每100ms采集一次
}
}

// 处理任务
void vProcessTask(void *pvParameters) {
int receivedData;
while (1) {
// 从队列接收数据
if (xQueueReceive(xQueue, &receivedData, portMAX_DELAY) == pdPASS) {
// 处理接收到的数据
processData(receivedData);
}
}
}

中断服务例程(ISR)与任务通信

队列也可以用于中断服务例程(ISR)与任务之间的通信。在ISR中,可以使用 xQueueSendFromISR() 函数将数据发送到队列。

c
void vISR(void) {
int data = 123;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(xQueue, &data, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

总结

FreeRTOS队列是任务间通信的强大工具,特别适用于STM32等嵌入式系统。通过队列,任务可以安全地传递数据,而无需担心竞争条件。本文介绍了如何创建队列、发送和接收数据,并展示了队列在实际应用中的使用场景。

附加资源与练习

  • 练习1:创建一个包含两个任务的FreeRTOS项目,一个任务生成随机数并发送到队列,另一个任务从队列接收数据并打印出来。
  • 练习2:修改练习1,使生成随机数的任务在队列满时进入阻塞状态,观察任务的行为。
提示

FreeRTOS提供了丰富的API来处理队列,建议查阅FreeRTOS官方文档以了解更多高级功能。