FreeRTOS连载09:队列机制深度解析 - 从环形缓冲区到生产者消费者模式

引言

队列是FreeRTOS中最重要的任务间通信机制之一,它不仅实现了数据的安全传递,还提供了任务同步功能。本文将深入分析FreeRTOS队列的实现原理,从数据结构设计到算法实现,揭示其高效性和可靠性的秘密。

1. 队列数据结构深度剖析

1.1 核心数据结构

FreeRTOS队列的核心数据结构定义在queue.c中:

typedef struct QueueDefinition
{
    int8_t * pcHead;           /* 指向队列存储区域的开始 */
    int8_t * pcWriteTo;        /* 指向下一个可写入位置 */
​
    union
    {
        QueuePointers_t xQueue;     /* 队列专用数据 */
        SemaphoreData_t xSemaphore; /* 信号量专用数据 */
    } u;
​
    List_t xTasksWaitingToSend;             /* 等待发送的任务链表 */
    List_t xTasksWaitingToReceive;          /* 等待接收的任务链表 */
​
    volatile UBaseType_t uxMessagesWaiting; /* 当前队列中的消息数量 */
    UBaseType_t uxLength;                   /* 队列长度(项目数) */
    UBaseType_t uxItemSize;                 /* 每个项目的大小 */
​
    volatile int8_t cRxLock;                /* 接收锁计数器 */
    volatile int8_t cTxLock;                /* 发送锁计数器 */
​
    #if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
        uint8_t ucStaticallyAllocated;      /* 静态分配标志 */
    #endif
​
    #if ( configUSE_QUEUE_SETS == 1 )
        struct QueueDefinition * pxQueueSetContainer;
    #endif
​
    #if ( configUSE_TRACE_FACILITY == 1 )
        UBaseType_t uxQueueNumber;
        uint8_t ucQueueType;
    #endif
} xQUEUE;

1.2 队列指针结构

队列使用联合体来区分不同的用途:

typedef struct QueuePointers
{
    int8_t * pcTail;     /* 指向队列存储区域的末尾 */
    int8_t * pcReadFrom; /* 指向最后读取位置 */
} QueuePointers_t;
​
typedef struct SemaphoreData
{
    TaskHandle_t xMutexHolder;        /* 互斥量持有者 */
    UBaseType_t uxRecursiveCallCount; /* 递归调用计数 */
} SemaphoreData_t;

设计亮点

  • 联合体设计:节省内存,同一结构支持队列和信号量

  • 双指针系统:pcHead和pcWriteTo实现环形缓冲区

  • 等待链表:分离发送和接收等待队列,提高效率

2. 队列创建机制

2.1 动态创建队列

QueueHandle_t xQueueCreate( const UBaseType_t uxQueueLength,
                           const UBaseType_t uxItemSize )
{
    Queue_t * pxNewQueue;
    size_t xQueueSizeInBytes;
    uint8_t * pucQueueStorage;
​
    configASSERT( uxQueueLength > ( UBaseType_t ) 0 );
​
    /* 计算队列所需的总内存大小 */
    if( uxItemSize == ( UBaseType_t ) 0 )
    {
        /* 信号量不需要存储数据 */
        xQueueSizeInBytes = ( size_t ) 0;
    }
    else
    {
        /* 为队列项目分配内存,多分配一个字节作为标记 */
        xQueueSizeInBytes = ( size_t ) ( uxQueueLength * uxItemSize );
    }
​
    /* 分配队列结构和存储空间 */
    pxNewQueue = ( Queue_t * ) pvPortMalloc( sizeof( Queue_t ) + xQueueSizeInBytes );
​
    if( pxNewQueue != NULL )
    {
        if( uxItemSize == ( UBaseType_t ) 0 )
        {
            pxNewQueue->pcHead = ( int8_t * ) pxNewQueue;
        }
        else
        {
            pxNewQueue->pcHead = ( int8_t * ) ( pxNewQueue + 1 );
        }
​
        /* 初始化队列 */
        prvInitialiseNewQueue( uxQueueLength, uxItemSize, pxNewQueue->pcHead, pxNewQueue );
    }
​
    return pxNewQueue;
}

2.2 队列初始化过程

static void prvInitialiseNewQueue( const UBaseType_t uxQueueLength,
                                  const UBaseType_t uxItemSize,
                                  uint8_t * pucQueueStorage,
                                  Queue_t * pxNewQueue )
{
    /* 设置队列参数 */
    pxNewQueue->uxLength = uxQueueLength;
    pxNewQueue->uxItemSize = uxItemSize;
    
    /* 重置队列到空状态 */
    ( void ) xQueueGenericReset( pxNewQueue, pdTRUE );
​
    #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
    {
        pxNewQueue->ucStaticallyAllocated = pdFALSE;
    }
    #endif
​
    #if ( configUSE_TRACE_FACILITY == 1 )
    {
        pxNewQueue->ucQueueType = queueQUEUE_TYPE_BASE;
    }
    #endif
​
    #if ( configUSE_QUEUE_SETS == 1 )
    {
        pxNewQueue->pxQueueSetContainer = NULL;
    }
    #endif
​
    traceQUEUE_CREATE( pxNewQueue );
}

3. 环形缓冲区实现原理

3.1 环形缓冲区的巧妙设计

FreeRTOS队列使用环形缓冲区来存储数据,这种设计的优势:

/* 队列重置函数展示了环形缓冲区的初始化 */
BaseType_t xQueueGenericReset( QueueHandle_t xQueue, BaseType_t xNewQueue )
{
    Queue_t * const pxQueue = xQueue;
​
    configASSERT( pxQueue );
​
    taskENTER_CRITICAL();
    {
        pxQueue->u.xQueue.pcTail = pxQueue->pcHead + ( pxQueue->uxLength * pxQueue->uxItemSize );
        pxQueue->uxMessagesWaiting = ( UBaseType_t ) 0U;
        pxQueue->pcWriteTo = pxQueue->pcHead;
        pxQueue->u.xQueue.pcReadFrom = pxQueue->pcHead + ( ( pxQueue->uxLength - 1U ) * pxQueue->uxItemSize );
        pxQueue->cRxLock = queueUNLOCKED;
        pxQueue->cTxLock = queueUNLOCKED;
​
        if( xNewQueue == pdFALSE )
        {
            /* 如果有任务在等待,需要解除阻塞 */
            if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
            {
                if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
                {
                    queueYIELD_IF_USING_PREEMPTION();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
            {
                if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE )
                {
                    queueYIELD_IF_USING_PREEMPTION();
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
        else
        {
            /* 初始化等待链表 */
            vListInitialise( &( pxQueue->xTasksWaitingToSend ) );
            vListInitialise( &( pxQueue->xTasksWaitingToReceive ) );
        }
    }
    taskEXIT_CRITICAL();
​
    return pdPASS;
}

3.2 指针管理策略

环形缓冲区的关键在于指针的循环管理:

/* 写指针前进函数 */
static void prvCopyDataToQueue( Queue_t * const pxQueue, 
                               const void * pvItemToQueue, 
                               const BaseType_t xPosition )
{
  
本项目采用C++编程语言结合ROS框架构建了完整的双机械臂控制系统,实现了Gazebo仿真环境下的协同运动模拟,并完成了两台实体UR10工业机器人的联动控制。该毕业设计在答辩环节获得98分的优异成绩,所有程序代码均通过系统性调试验证,保证可直接部署运行。 系统架构包含三个核心模块:基于ROS通信架构的双臂协调控制器、Gazebo物理引擎下的动力学仿真环境、以及真实UR10机器人的硬件接口层。在仿真验证阶段,开发了双臂碰撞检测算法和轨迹规划模块,通过ROS控制包实现了末端执行器的同步轨迹跟踪。硬件集成方面,建立了基于TCP/IP协议的实时通信链路,解决了双机数据同步和运动指令分发等关键技术问题。 本资源适用于自动化、机械电子、人工智能等专业方向的课程实践,可作为高年级课程设计、毕业课题的重要参考案例。系统采用模块化设计理念,控制核心与硬件接口分离架构便于功能扩展,具备工程实践能力的学习者可在现有框架基础上进行二次开发,例如集成视觉感知模块或优化运动规划算法。 项目文档详细记录了环境配置流程、参数调试方法和实验验证数据,特别说明了双机协同作业时的时序同步解决方案。所有功能模块均提供完整的API接口说明,便于使用者快速理解系统架构并进行定制化修改。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VehSwHwDeveloper

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值