05_FreeRTOS 队列(简单队列)
介绍如何使用Queue在任务之间进行通信。下面是队列如何工作的流程:
队列是任务之间发送和接收数据的最简单方法。首先,我们将使用简单队列,其中队列中的所有元素都是相同的数据类型,然后我们将使用结构化队列,其中数据类型可以不同。
简单队列
在一个简单的队列中,所有元素都是同一类型。队列由其处理程序识别,因此我们首先需要为该队列创建一个处理程序:
osMessageQId Queue01Handle;
接下来,在main函数内部,我们将创建一个Queue,该队列可以存储5个整数:
osMessageQDef(Queue01, 5, int);
Queue01Handle = osMessageCreate(osMessageQ(Queue01), NULL);
if (Queue01Handle == 0) // Queue not created
{
printf("Unable to create Integer Queue\n");
}else{
printf("Integer Queue Created successfully\n");
}
创建任务:
/* definition and creation of Task1 */
osThreadDef(Task1, Task1_init, 2, 0, 512);
Task1Handle = osThreadCreate(osThread(Task1), NULL);
/* definition and creation of Task2 */
osThreadDef(Task2, Task2_init, 1, 0, 512);
Task2Handle = osThreadCreate(osThread(Task2), (void *)222);
/* definition and creation of Task3 */
osThreadDef(Task3, Task3_init, 0, 0, 512);
Task3Handle = osThreadCreate(osThread(Task3), NULL);
如果在创建队列时出现错误(例如内存不足),则该xQueueCreate函数将返回’0’。否则,它将返回任何其他值。
任务函数内部,我们可以使用以下命令将数据发送到Queue:
/* USER CODE END Header_Task1_init */
void Task1_init(void const * argument)
{
/* USER CODE BEGIN 5 */
int i = 111;
/* Infinite loop */
for(;;)
{
printf("Entered Task1\n");
if (xQueueSend(Queue01Handle, &i, portMAX_DELAY) == pdPASS)
{
printf("Successfully sent from Task1\n");
printf("-----");
}
vTaskDelay(2000);
}
/* USER CODE END 5 */
}
void Task2_init(void const * argument)
{
/* USER CODE BEGIN Task2_init */
int ToSend;
/* Infinite loop */
for(;;)
{
ToSend = (int) argument;
printf("Entered Task2\n");
xQueueSend(Queue01Handle, &ToSend, portMAX_DELAY);
printf("Successfully sent from Task2\n");
printf("----");
vTaskDelay(1000);
}
/* USER CODE END Task2_init */
}
将等待时间指定为portMAX_DELAY,这意味着任务将永远等待,直到队列中的空间可用。在此等待时间内,此任务将处于暂停状态。
接收函数:
void Task3_init(void const * argument)
{
/* USER CODE BEGIN Task3_init */
osEvent event;
/* Infinite loop */
for(;;)
{
printf ( "Entered RECEIVER\n");
event = osMessageGet(Queue01Handle, portMAX_DELAY);
printf("%d Receiving from Queue\n",(int)event.value.v);
vTaskDelay(500);
}
/* USER CODE END Task3_init */
}
若是用中断发送,则需要用ISR版函数,若是队列满了就只能超时,而不能等待:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Receive_IT(huart, &rx_data, 1);
int ToSend = 123456789;
if (rx_data == 'g')
{
/* The xHigherPriorityTaskWoken parameter must be initialized to pdFALSE as
it will get set to pdTRUE inside the interrupt safe API function if a
context switch is required. */
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (xQueueSendToFrontFromISR(Queue01Handle, &ToSend, &xHigherPriorityTaskWoken) == pdPASS)
{
printf("ISR ISR ISR ISR\n");
}
/* Pass the xHigherPriorityTaskWoken value into portEND_SWITCHING_ISR(). If
xHigherPriorityTaskWoken was set to pdTRUE inside xSemaphoreGiveFromISR()
then calling portEND_SWITCHING_ISR() will request a context switch. If
xHigherPriorityTaskWoken is still pdFALSE then calling
portEND_SWITCHING_ISR() will have no effect */
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
}
}
输出结果:
2s一次Task2 1s一次task1,输入中断,在输入g后就产生。