前言

队列(Queue)是 FreeRTOS 中任务间通信最核心、最常用的机制,它实现了任务与任务、任务与中断之间的安全数据交互。

本文基于正点原子标准队列实验,从实验设计、核心 API、代码实现、原理拆解四个维度,完整演示队列的两种经典用法:

  1. 小数据直接拷贝入队 / 出队(按键值传输)
  2. 大数据地址传递入队 / 出队(结构体 / 数组等大数据传输)帮你彻底搞懂 FreeRTOS 队列的底层原理与实战用法。

一、实验设计与目标

1. 实验目的

  • 掌握 FreeRTOS 队列核心 API(创建、入队、出队)的使用
  • 理解队列「数据拷贝」的核心特性
  • 学会用队列实现小数据直接传输大数据地址传输两种方案
  • 掌握多任务通过队列通信的设计方法

二、核心原理:队列的本质

1. 队列的核心特性:数据拷贝

FreeRTOS 队列的核心是 **「数据拷贝」而非指针传递 **:

  • 入队时:将数据完整拷贝到队列存储空间
  • 出队时:将队列中的数据完整拷贝到任务变量
  • 优点:安全、无数据竞争,任务 / 中断可独立操作
  • 对于大数据:直接拷贝开销大,因此采用 **「传地址」方案 **,只拷贝指针,大幅提升效率

2. 队列的核心 API

① 创建队列 xQueueCreate()
QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize);
  • uxQueueLength:队列最大可存储的项目数
  • uxItemSize:每个项目的字节大小
  • 返回值:队列句柄,后续所有队列操作都依赖它

② 入队 xQueueSend()(任务中使用)

BaseType_t xQueueSend(QueueHandle_t xQueue, const void *pvItemToQueue, TickType_t xTicksToWait);
  • pvItemToQueue:要发送的数据的指针
  • xTicksToWait:队列满时的最大阻塞时间
  • 中断中使用 xQueueSendFromISR() 版本

③ 出队 xQueueReceive()

BaseType_t xQueueReceive(QueueHandle_t xQueue, void *pvBuffer, TickType_t xTicksToWait);
  • pvBuffer:接收数据的缓冲区指针
  • 出队后队列中的数据会被移除

三.重要代码

#include "freertos_demo.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/LED/led.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "queue.h"
/******************************************************************************************************/
/*FreeRTOSÅäÖÃ*/

/* START_TASK ÈÎÎñ ÅäÖÃ
 * °üÀ¨: ÈÎÎñ¾ä±ú ÈÎÎñÓÅÏȼ¶ ¶ÑÕ»´óС ´´½¨ÈÎÎñ
 */
#define START_TASK_PRIO 1                   /* ÈÎÎñÓÅÏȼ¶ */
#define START_STK_SIZE  128                 /* ÈÎÎñ¶ÑÕ»´óС */
TaskHandle_t            StartTask_Handler;  /* ÈÎÎñ¾ä±ú */
void start_task(void *pvParameters);        /* ÈÎÎñº¯Êý */

/* TASK1 ÈÎÎñ ÅäÖÃ
 * °üÀ¨: ÈÎÎñ¾ä±ú ÈÎÎñÓÅÏȼ¶ ¶ÑÕ»´óС ´´½¨ÈÎÎñ
 */
#define TASK1_PRIO      2                   /* ÈÎÎñÓÅÏȼ¶ */
#define TASK1_STK_SIZE  128                 /* ÈÎÎñ¶ÑÕ»´óС */
TaskHandle_t            Task1Task_Handler;  /* ÈÎÎñ¾ä±ú */
void task1(void *pvParameters);             /* ÈÎÎñº¯Êý */

/* TASK2 ÈÎÎñ ÅäÖÃ
 * °üÀ¨: ÈÎÎñ¾ä±ú ÈÎÎñÓÅÏȼ¶ ¶ÑÕ»´óС ´´½¨ÈÎÎñ
 */
#define TASK2_PRIO      3                   /* ÈÎÎñÓÅÏȼ¶ */
#define TASK2_STK_SIZE  128                 /* ÈÎÎñ¶ÑÕ»´óС */
TaskHandle_t            Task2Task_Handler;  /* ÈÎÎñ¾ä±ú */
void task2(void *pvParameters);             /* ÈÎÎñº¯Êý */

#define TASK3_PRIO      4                  /* ÈÎÎñÓÅÏȼ¶ */
#define TASK3_STK_SIZE  128                 /* ÈÎÎñ¶ÑÕ»´óС */
TaskHandle_t            Task3Task_Handler;  /* ÈÎÎñ¾ä±ú */
void task3(void *pvParameters);             /* ÈÎÎñº¯Êý */

/******************************************************************************************************/

/* LCDË¢ÆÁʱʹÓõÄÑÕÉ« */
uint16_t lcd_discolor[11] = {WHITE, BLACK, BLUE, RED,
                             MAGENTA, GREEN, CYAN, YELLOW,
                             BROWN, BRRED, GRAY};

/**
 * @brief       FreeRTOSÀý³ÌÈë¿Úº¯Êý
 * @param       ÎÞ
 * @retval      ÎÞ
 */
QueueHandle_t		key_queue;												
QueueHandle_t	  big_date_queue;
char buff[100]={"12412sadidnandkajsdadan"};
void freertos_demo(void)
{
   
	  key_queue=xQueueCreate(2,sizeof(uint8_t));
    if(key_queue!=NULL)
		{
			printf("key_queue_sucess\r\n");
		}else{
			printf("key_queue_fail\r\n");
		}
		big_date_queue=xQueueCreate(1,sizeof(char*));
		if(big_date_queue!=NULL){
				printf("big_date_queue\r\n");
		}else{
			printf("big_date_queue\r\n");
		}
    xTaskCreate((TaskFunction_t )start_task,            /* ÈÎÎñº¯Êý */
                (const char*    )"start_task",          /* ÈÎÎñÃû³Æ */
                (uint16_t       )START_STK_SIZE,        /* ÈÎÎñ¶ÑÕ»´óС */
                (void*          )NULL,                  /* ´«Èë¸øÈÎÎñº¯ÊýµÄ²ÎÊý */
                (UBaseType_t    )START_TASK_PRIO,       /* ÈÎÎñÓÅÏȼ¶ */
                (TaskHandle_t*  )&StartTask_Handler);   /* ÈÎÎñ¾ä±ú */
    vTaskStartScheduler();
}

/**
 * @brief       start_task
 * @param       pvParameters : ´«Èë²ÎÊý(δÓõ½)
 * @retval      ÎÞ
 */
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           /* ½øÈëÁÙ½çÇø */
    /* ´´½¨ÈÎÎñ1 */
    xTaskCreate((TaskFunction_t )task1,                 /* ÈÎÎñº¯Êý */
                (const char*    )"task1",               /* ÈÎÎñÃû³Æ */
                (uint16_t       )TASK1_STK_SIZE,        /* ÈÎÎñ¶ÑÕ»´óС */
                (void*          )NULL,                  /* ´«Èë¸øÈÎÎñº¯ÊýµÄ²ÎÊý */
                (UBaseType_t    )TASK1_PRIO,            /* ÈÎÎñÓÅÏȼ¶ */
                (TaskHandle_t*  )&Task1Task_Handler);   /* ÈÎÎñ¾ä±ú */
   

		 xTaskCreate((TaskFunction_t )task2,                 /* ÈÎÎñº¯Êý */
                (const char*    )"task2",               /* ÈÎÎñÃû³Æ */
                (uint16_t       )TASK2_STK_SIZE,        /* ÈÎÎñ¶ÑÕ»´óС */
                (void*          )NULL,                  /* ´«Èë¸øÈÎÎñº¯ÊýµÄ²ÎÊý */
                (UBaseType_t    )TASK2_PRIO,            /* ÈÎÎñÓÅÏȼ¶ */
                (TaskHandle_t*  )&Task2Task_Handler);   /* ÈÎÎñ¾ä±ú */
								
		xTaskCreate((TaskFunction_t )task3,                 /* ÈÎÎñº¯Êý */
                (const char*    )"task3",               /* ÈÎÎñÃû³Æ */
                (uint16_t       )TASK3_STK_SIZE,        /* ÈÎÎñ¶ÑÕ»´óС */
                (void*          )NULL,                  /* ´«Èë¸øÈÎÎñº¯ÊýµÄ²ÎÊý */
                (UBaseType_t    )TASK3_PRIO,            /* ÈÎÎñÓÅÏȼ¶ */
                (TaskHandle_t*  )&Task3Task_Handler);   /* ÈÎÎñ¾ä±ú */
   
    vTaskDelete(StartTask_Handler); /* ɾ³ý¿ªÊ¼ÈÎÎñ */
    taskEXIT_CRITICAL();            /* Í˳öÁÙ½çÇø */
}

/**
 * @brief       task1
 * @param       pvParameters : ´«Èë²ÎÊý(δÓõ½)
 * @retval      ÎÞ
 */
void task1(void *pvParameters)
{
    uint16_t key = 0;
    char *buf = &buff[0];
    BaseType_t err = 0;

    while (1) {
        key = key_scan(0);
        if (key == KEY0_PRES || key == KEY1_PRES) {
            err = xQueueSend(key_queue, &key, portMAX_DELAY);
            if (err != pdTRUE) {
                printf("key_queue_fail_1\r\n");
            }
            vTaskDelay(10);
        }
        else if (key == WKUP_PRES) {
            err = xQueueSend(big_date_queue, &buf, portMAX_DELAY);
            if (err != pdTRUE) {
                printf("big_date_queue_fail_1\r\n");
            }
            vTaskDelay(10);
        }
    }
}
 
void task2(void *pvParameters){
	uint8_t key=0;
	BaseType_t err=0;
	 while(1){
		 err=xQueueReceive(key_queue,&key,portMAX_DELAY);
		 if(err!=pdTRUE){
			 printf("key_queue_fail_duqu\r\n");
		 }else{
			 printf("key_queue_chenggong_duqu,data:%d\r\n",key);
		 }
	 }
}

void task3( void * pvParameters )
 {
	 char * buf;
	 BaseType_t err=0;
	 while(1){
		 err=xQueueReceive(big_date_queue,&buf,portMAX_DELAY);
		 if(err!=pdTRUE){
			 printf("big_date_queue_fail_duqu\r\n");
		 }else{
			 printf("big_date_queue_chenggong_duqu,data:%s\r\n",buf);
		 }
	 }
 }
 
 
 
 

四.实验结果展示

更多推荐