STM32 FreeRTOS队列
介绍
在嵌入式系统中,任务之间的通信是一个非常重要的概念。FreeRTOS 提供了一种称为队列的机制,用于在任务之间传递数据。队列是一种先进先出(FIFO)的数据结构,允许多个任务安全地发送和接收数据。
在STM32微控制器上使用FreeRTOS时,队列是实现任务间通信的常用工具。通过队列,任务可以发送消息、数据或其他信息给其他任务,而无需直接访问共享资源,从而避免了潜在的竞争条件。
队列的基本概念
什么是队列?
队列是一种数据结构,允许数据按照先进先出的顺序进行存储和检索。在FreeRTOS中,队列可以用于任务之间传递数据,也可以用于任务与中断服务例程(ISR)之间的通信。
队列的特点
- 线程安全:FreeRTOS队列是线程安全的,多个任务可以同时访问队列而不会导致数据损坏。
- 阻塞和非阻塞操作:任务可以在发送或接收数据时选择阻塞或非阻塞模式。阻塞模式下,任务会等待直到队列有空间或数据可用;非阻塞模式下,任务会立即返回。
- 动态或静态创建:队列可以在运行时动态创建,也可以在编译时静态分配。
创建和使用队列
创建队列
在FreeRTOS中,队列通过 xQueueCreate()
函数创建。该函数需要两个参数:队列的长度和每个队列项的大小。
QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength, UBaseType_t uxItemSize );
uxQueueLength
:队列的长度,即队列中可以存储的最大项数。uxItemSize
:每个队列项的大小,以字节为单位。
例如,创建一个可以存储10个整数的队列:
QueueHandle_t xQueue = xQueueCreate(10, sizeof(int));
发送数据到队列
使用 xQueueSend()
函数将数据发送到队列。该函数有三个参数:队列句柄、要发送的数据的指针以及等待时间。
BaseType_t xQueueSend( QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait );
xQueue
:队列句柄。pvItemToQueue
:指向要发送的数据的指针。xTicksToWait
:如果队列已满,任务等待的最长时间。设置为portMAX_DELAY
表示无限等待。
例如,发送一个整数到队列:
int data = 42;
xQueueSend(xQueue, &data, portMAX_DELAY);
从队列接收数据
使用 xQueueReceive()
函数从队列中接收数据。该函数也有三个参数:队列句柄、存储接收数据的指针以及等待时间。
BaseType_t xQueueReceive( QueueHandle_t xQueue, void * pvBuffer, TickType_t xTicksToWait );
xQueue
:队列句柄。pvBuffer
:指向存储接收数据的缓冲区的指针。xTicksToWait
:如果队列为空,任务等待的最长时间。设置为portMAX_DELAY
表示无限等待。
例如,从队列中接收一个整数:
int receivedData;
xQueueReceive(xQueue, &receivedData, portMAX_DELAY);
实际应用场景
任务间通信
假设我们有两个任务:一个任务负责采集传感器数据,另一个任务负责处理这些数据。我们可以使用队列将传感器数据从采集任务传递到处理任务。
// 采集任务
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()
函数将数据发送到队列。
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官方文档以了解更多高级功能。