FreeRTOS 队列操作实验:从基础入队出队到大数据传输,一文吃透
·
前言
队列(Queue)是 FreeRTOS 中任务间通信最核心、最常用的机制,它实现了任务与任务、任务与中断之间的安全数据交互。
本文基于正点原子标准队列实验,从实验设计、核心 API、代码实现、原理拆解四个维度,完整演示队列的两种经典用法:
- 小数据直接拷贝入队 / 出队(按键值传输)
- 大数据地址传递入队 / 出队(结构体 / 数组等大数据传输)帮你彻底搞懂 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);
}
}
}
四.实验结果展示

更多推荐
所有评论(0)