FreeRTOS内核工作原理分析(1)

1 FreeRTOS 基础架构

FreeRTOS 作为一个轻量级实时操作系统,其核心架构设计遵循简洁高效的原则。整个系统由四个主要部分构成:内核、任务管理、内存管理和通信机制。

内核是整个系统的核心,负责实现基本的操作系统功能;任务管理负责多任务的创建、调度和删除;内存管理负责系统内存的分配和回收;通信机制则提供任务间的数据交换和同步功能。

1.1 系统核心组件

  • 调度器(Scheduler)

调度器是 FreeRTOS 最核心的组件,主要负责任务切换的控制。其基本工作原理是:

void vTaskStartScheduler(void) {
    // 创建空闲任务
    if(xTaskCreate(prvIdleTask,
                   "IDLE",
                   configMINIMAL_STACK_SIZE,
                   NULL,
                   tskIDLE_PRIORITY,
                   NULL) != pdPASS) {
        return;
    }
    
    // 启动定时器中断
    if(xPortStartScheduler() != pdFALSE) {
        // 调度器启动成功
    }
}

调度器采用优先级抢占式调度算法,其核心判断公式为:

优先级判定 = Base_Priority + Time_Slice_Remaining

  • 任务管理器(Task Manager)

任务管理器维护着系统中所有任务的状态和控制块。每个任务都有一个任务控制块(TCB),定义如下:

typedef struct tskTaskControlBlock {
    volatile StackType_t *pxTopOfStack;    // 栈顶指针
    ListItem_t xStateListItem;             // 状态列表项
    ListItem_t xEventListItem;             // 事件列表项
    UBaseType_t uxPriority;                // 任务优先级
    StackType_t *pxStack;                  // 栈起始地址
    char pcTaskName[configMAX_TASK_NAME_LEN];  // 任务名称
} tskTCB;
  •  中断管理系统

中断管理系统处理硬件中断和任务切换。FreeRTOS 提供了一套完整的中断管理机制:

// 中断优先级配置
void vPortSetInterruptPriority(uint32_t ulPriority) {
    NVIC_SetPriority(ulPriority & 0xFF,
                     configKERNEL_INTERRUPT_PRIORITY);
}

// 关键区域保护
#define taskENTER_CRITICAL()  portENTER_CRITICAL()
#define taskEXIT_CRITICAL()   portEXIT_CRITICAL()
  •  时钟系统

时钟系统基于系统时钟中断,提供基本的时间管理服务。配置示例:

// 系统时钟配置
#define configTICK_RATE_HZ                1000    // 1ms 时钟节拍
#define configSYSTICK_CLOCK_HZ           (configCPU_CLOCK_HZ / 8)  // 系统时钟频率

// 时钟中断处理函数
void xPortSysTickHandler(void) {
    // 增加系统时钟计数
    xTaskIncrementTick();
    
    // 触发任务切换
    #if configUSE_PREEMPTION == 1
        portYIELD_FROM_ISR(pdTRUE);
    #endif
}

1.2 内存管理架构

FreeRTOS 的内存管理架构支持多种堆管理算法,可以根据应用需求选择合适的实现:

// 内存分配接口
void *pvPortMalloc(size_t xWantedSize) {
    void *pvReturn = NULL;
    
    vTaskSuspendAll();
    {
        pvReturn = prvHeapAlloc(xWantedSize);
    }
    xTaskResumeAll();
    
    return pvReturn;
}

// 内存释放接口
void vPortFree(void *pv) {
    if(pv != NULL) {
        vTaskSuspendAll();
        {
            prvHeapFree(pv);
        }
        xTaskResumeAll();
    }
}

1.3 系统初始化流程

FreeRTOS 的初始化过程包含以下关键步骤:

  1. 硬件初始化
  2. 系统时钟配置
  3. 内存管理器初始化
  4. 创建初始任务
  5. 启动调度器

初始化代码示例:

int main(void) {
    // 硬件初始化
    prvSetupHardware();
    
    // 创建初始任务
    xTaskCreate(vInitialTask,
                "Init",
                configMINIMAL_STACK_SIZE,
                NULL,
                tskIDLE_PRIORITY + 1,
                NULL);
    
    // 启动调度器
    vTaskStartScheduler();
    
    // 正常情况下不会执行到这里
    for(;;);
}

1.4 系统配置与裁剪

FreeRTOS 提供了丰富的配置选项,通过 FreeRTOSConfig.h 文件进行系统裁剪:

// 基本配置选项
#define configUSE_PREEMPTION                    1
#define configUSE_TIME_SLICING                  1
#define configUSE_IDLE_HOOK                     0
#define configUSE_TICK_HOOK                     0
#define configCPU_CLOCK_HZ                      (SystemCoreClock)
#define configTICK_RATE_HZ                      1000
#define configMAX_PRIORITIES                    32
#define configMINIMAL_STACK_SIZE               ((unsigned short)128)
#define configTOTAL_HEAP_SIZE                  ((size_t)(75 * 1024))

1.5 调试支持

FreeRTOS 提供了完整的调试支持机制,包括:

  • 任务状态跟踪
  • 堆栈使用统计
  • 运行时间统计
  • 队列使用情况监控

调试功能配置示例:

#define configUSE_TRACE_FACILITY               1
#define configUSE_STATS_FORMATTING_FUNCTIONS   1
#define configGENERATE_RUN_TIME_STATS         1
#define configUSE_MALLOC_FAILED_HOOK          1

2 列表与列表项结构

2.1 列表基础结构

FreeRTOS 的列表结构是整个系统的基础数据结构,采用双向链表实现。其核心数据结构定义如下:

typedef struct xLIST {
    configLIST_VOLATILE UBaseType_t uxNumberOfItems;  // 列表项数量
    ListItem_t * configLIST_VOLATILE pxIndex;         // 当前索引指针
    MiniListItem_t xListEnd;                          // 列表结束标记
} List_t;

typedef struct xLIST_ITEM {
    configLIST_VOLATILE TickType_t xItemValue;        // 列表项值(通常用于排序)
    struct xLIST_ITEM * configLIST_VOLATILE pxNext;   // 指向下一个列表项
    struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; // 指向上一个列表项
    void * pvOwner;                                   // 指向列表项的拥有者(通常是TCB)
    void * configLIST_VOLATILE pvContainer;           // 指向该列表项所在的列表
} ListItem_t;

2.2 列表初始化

当创建一个新的列表时,需要进行初始化操作。初始化过程包括设置列表结束标记和重置计数器

void vListInitialise(List_t * const pxList) {
    // 初始化列表结束项
    pxList->xListEnd.xItemValue = portMAX_DELAY;
    
    // 初始化列表结束项的指针
    pxList->xListEnd.pxNext = (ListItem_t *)&(pxList->xListEnd);
    pxList->xListEnd.pxPrevious = (ListItem_t *)&(pxList->xListEnd);
    
    // 重置列表项计数器
    pxList->uxNumberOfItems = 0;
    
    // 设置列表索引指针
    pxList->pxIndex = (ListItem_t *)&(pxList->xListEnd);
}

// 初始化列表项
void vListInitialiseItem(ListItem_t * const pxItem) {
    pxItem->pvContainer = NULL;
}

2.3 列表操作函数

FreeRTOS 提供了一系列列表操作函数,用于管理列表项:

  • 插入列表项
void vListInsert(List_t * const pxList, ListItem_t * const pxNewListItem) {
    ListItem_t *pxIterator;
    const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
    
    // 按值排序找到插入位置
    if(xValueOfInsertion == portMAX_DELAY) {
        pxIterator = pxList->xListEnd.pxPrevious;
    } else {
        for(pxIterator = (ListItem_t *)&(pxList->xListEnd);
            pxIterator->pxNext->xItemValue <= xValueOfInsertion;
            pxIterator = pxIterator->pxNext) {
            // 空循环体
        }
    }
    
    // 插入新节点
    pxNewListItem->pxNext = pxIterator->pxNext;
    pxNewListItem->pxPrevious = pxIterator;
    pxIterator->pxNext->pxPrevious = pxNewListItem;
    pxIterator->pxNext = pxNewListItem;
    
    // 设置列表项所属列表
    pxNewListItem->pvContainer = (void *)pxList;
    
    // 增加列表项计数
    (pxList->uxNumberOfItems)++;
}
  • 列表末尾插入
void vListInsertEnd(List_t * const pxList, ListItem_t * const pxNewListItem) {
    ListItem_t * const pxIndex = pxList->pxIndex;
    
    pxNewListItem->pxNext = pxIndex->pxNext;
    pxNewListItem->pxPrevious = pxList->pxIndex;
    pxIndex->pxNext->pxPrevious = pxNewListItem;
    pxIndex->pxNext = pxNewListItem;
    
    pxNewListItem->pvContainer = (void *)pxList;
    (pxList->uxNumberOfItems)++;
}
  • 移除列表项
UBaseType_t uxListRemove(ListItem_t * const pxItemToRemove) {
    List_t * const pxList = (List_t *)pxItemToRemove->pvContainer;
    
    pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
    pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
    
    if(pxList->pxIndex == pxItemToRemove) {
        pxList->pxIndex = pxItemToRemove->pxPrevious;
    }
    
    pxItemToRemove->pvContainer = NULL;
    (pxList->uxNumberOfItems)--;
    
    return pxList->uxNumberOfItems;
}

2.4 列表应用场景

FreeRTOS 中的列表结构广泛应用于以下场景:

  • 就绪任务列表 
// 每个优先级对应一个就绪列表
List_t pxReadyTasksLists[configMAX_PRIORITIES];

// 将任务添加到就绪列表
void prvAddTaskToReadyList(TCB_t * const pxTCB) {
    vListInsertEnd(&(pxReadyTasksLists[pxTCB->uxPriority]),
                   &(pxTCB->xStateListItem));
}
  • 延时任务列表
// 延时列表定义
static List_t xDelayedTaskList1;
static List_t xDelayedTaskList2;
static List_t * volatile pxDelayedTaskList;
static List_t * volatile pxOverflowDelayedTaskList;

// 添加任务到延时列表
void vListInsertDelayed(List_t * const pxList,
                        ListItem_t * const pxNewListItem) {
    vListInsert(pxList, pxNewListItem);
}
  • 事件等待列表
// 事件等待列表结构
typedef struct xEVENT_GROUPS {
    List_t xTasksWaitingForBits;    // 等待事件的任务列表
} EventGroup_t;

2.5 列表遍历与查找

FreeRTOS 提供了列表遍历的宏定义,方便进行列表操作:

#define listFOR_EACH(pxIterator, pxList)                                \
    for((pxIterator) = (pxList)->pxIndex->pxNext;                      \
        (pxIterator) != (ListItem_t *)&((pxList)->xListEnd);           \
        (pxIterator) = (pxIterator)->pxNext)

#define listFOR_EACH_SAFE(pxIterator, pxNext, pxList)                  \
    for((pxIterator) = (pxList)->pxIndex->pxNext,                      \
        (pxNext) = (pxIterator)->pxNext;                               \
        (pxIterator) != (ListItem_t *)&((pxList)->xListEnd);           \
        (pxIterator) = (pxNext),                                        \
        (pxNext) = (pxIterator)->pxNext)

2.6 性能优化考虑

列表操作的性能对系统整体性能有重要影响,FreeRTOS 采用以下优化策略:

  1. 使用双向链表减少遍历开销
  2. 按值排序加快查找速度
  3. 维护索引指针优化访问效率
  4. 使用内联函数减少函数调用开销

3 任务状态及转换

3.1 任务状态定义

FreeRTOS 中的任务在运行过程中会处于不同的状态,系统定义了以下几种基本状态:

// 任务状态定义
#define tskRUNNING_CHAR               'X'    // 运行态
#define tskREADY_CHAR                 'R'    // 就绪态
#define tskBLOCKED_CHAR               'B'    // 阻塞态
#define tskSUSPENDED_CHAR            'S'    // 挂起态
#define tskDELETED_CHAR              'D'    // 删除态

typedef enum {
    eRunning = 0,      // 任务正在运行
    eReady,            // 任务准备就绪
    eBlocked,          // 任务阻塞中
    eSuspended,        // 任务被挂起
    eDeleted           // 任务已删除
} eTaskState;

3.2 任务控制块(TCB)

每个任务都有一个对应的任务控制块,用于存储任务的状态信息:

typedef struct tskTaskControlBlock {
    volatile StackType_t *pxTopOfStack;    // 栈顶指针
    ListItem_t xStateListItem;             // 状态列表项
    StackType_t *pxStack;                  // 栈起始地址
    char pcTaskName[configMAX_TASK_NAME_LEN];  // 任务名称
    UBaseType_t uxPriority;                // 任务优先级
    UBaseType_t uxBasePriority;            // 基础优先级
    uint32_t ulRunTimeCounter;             // 运行时间计数
    TickType_t xTicksToDelay;              // 延时时钟节拍数
    void *pvParameters;                     // 任务参数
} tskTCB;

// 任务句柄类型定义
typedef void * TaskHandle_t;

3.3 任务创建与初始化

创建新任务时需要进行状态初始化:

BaseType_t xTaskCreate(TaskFunction_t pxTaskCode,
                      const char * const pcName,
                      const configSTACK_DEPTH_TYPE usStackDepth,
                      void *pvParameters,
                      UBaseType_t uxPriority,
                      TaskHandle_t *pxCreatedTask) {
    TCB_t *pxNewTCB;
    BaseType_t xReturn;
    
    // 分配任务控制块内存
    pxNewTCB = pvPortMalloc(sizeof(TCB_t));
    
    if(pxNewTCB != NULL) {
        // 初始化任务栈
        StackType_t *pxTopOfStack = prvTaskInit(pxNewTCB, 
                                               pxTaskCode,
                                               pvParameters,
                                               usStackDepth);
        pxNewTCB->pxTopOfStack = pxTopOfStack;
        
        // 设置任务初始状态为就绪
        prvAddTaskToReadyList(pxNewTCB);
        
        xReturn = pdPASS;
    } else {
        xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
    }
    
    return xReturn;
}

3.4 状态转换机制

任务状态转换由以下几种触发机制:

  • 调度器触发转换
void vTaskSwitchContext(void) {
    // 获取最高优先级的就绪任务
    TCB_t *pxNewTCB = prvGetHighestPriorityTask();
    
    if(pxNewTCB != pxCurrentTCB) {
        // 切换当前任务
        pxCurrentTCB = pxNewTCB;
    }
}
  •  任务自主转换
// 任务延时导致状态转换
void vTaskDelay(const TickType_t xTicksToDelay) {
    TCB_t *pxTCB = pxCurrentTCB;
    
    // 将任务从就绪列表移除
    if(uxListRemove(&(pxTCB->xStateListItem)) == 0) {
        portRESET_READY_PRIORITY(pxTCB->uxPriority);
    }
    
    // 添加到延时列表
    prvAddCurrentTaskToDelayedList(xTicksToDelay);
}
  • 阻塞状态转换
// 等待信号量导致阻塞
BaseType_t xQueueSemaphoreTake(QueueHandle_t xQueue,
                              TickType_t xTicksToWait) {
    BaseType_t xEntryTimeSet = pdFALSE;
    TimeOut_t xTimeOut;
    
    // 设置阻塞超时时间
    vTaskSetTimeOutState(&xTimeOut);
    
    // 将任务加入等待列表
    vTaskPlaceOnEventList(&(xQueue->xTasksWaitingToReceive),
                         xTicksToWait);
}

3.5 状态检查与管理

FreeRTOS 提供了一系列函数用于任务状态管理:

// 获取任务状态
eTaskState eTaskGetState(TaskHandle_t xTask) {
    TCB_t *pxTCB = xTask;
    eTaskState eReturn;
    
    if(pxTCB == pxCurrentTCB) {
        eReturn = eRunning;
    } else {
        taskENTER_CRITICAL();
        {
            if(listLIST_ITEM_CONTAINER(&(pxTCB->xStateListItem)) == NULL) {
                eReturn = eDeleted;
            } else if(listLIST_ITEM_CONTAINER(&(pxTCB->xStateListItem)) == &xSuspendedTaskList) {
                eReturn = eSuspended;
            } else if(listLIST_ITEM_CONTAINER(&(pxTCB->xStateListItem)) == &xDelayedTaskList1 ||
                     listLIST_ITEM_CONTAINER(&(pxTCB->xStateListItem)) == &xDelayedTaskList2) {
                eReturn = eBlocked;
            } else {
                eReturn = eReady;
            }
        }
        taskEXIT_CRITICAL();
    }
    
    return eReturn;
}

3.6 状态转换优先级处理

状态转换过程中需要考虑任务优先级:

// 优先级继承机制
void prvInheritPriority(TCB_t * const pxMutexHolder,
                        const UBaseType_t uxPriorityToCopy) {
    if(pxMutexHolder->uxPriority < uxPriorityToCopy) {
        // 提升优先级
        if(listIS_CONTAINED_WITHIN(&(pxReadyTasksLists[pxMutexHolder->uxPriority]),
                                 &(pxMutexHolder->xStateListItem))) {
            uxListRemove(&(pxMutexHolder->xStateListItem));
            pxMutexHolder->uxPriority = uxPriorityToCopy;
            prvAddTaskToReadyList(pxMutexHolder);
        } else {
            pxMutexHolder->uxPriority = uxPriorityToCopy;
        }
    }
}

3.7 状态转换时序图

Running -----> Blocked
   ^            |
   |            |
   |            v
Ready <------ Suspended

这些状态转换机制共同构成了 FreeRTOS 的任务管理核心。

4 任务调度机制

4.1 调度器基本原理

FreeRTOS 采用优先级抢占式调度机制,高优先级任务可以抢占低优先级任务的 CPU 使用权。调度器的核心是任务切换机制,由以下关键组件构成:

// 当前运行的任务指针
static TCB_t *volatile pxCurrentTCB = NULL;

// 就绪任务列表数组(每个优先级一个列表)
static List_t pxReadyTasksLists[configMAX_PRIORITIES];

// 任务优先级位图,用于快速查找最高优先级任务
static UBaseType_t uxTopReadyPriority = 0;

4.2 调度器初始化

调度器启动前需要进行初始化配置:

void prvInitialiseTaskLists(void) {
    UBaseType_t uxPriority;
    
    // 初始化所有优先级的就绪列表
    for(uxPriority = 0; uxPriority < configMAX_PRIORITIES; uxPriority++) {
        vListInitialise(&(pxReadyTasksLists[uxPriority]));
    }
    
    // 初始化延时任务列表
    vListInitialise(&xDelayedTaskList1);
    vListInitialise(&xDelayedTaskList2);
    
    // 初始化挂起任务列表
    vListInitialise(&xSuspendedTaskList);
    
    // 初始化任务优先级位图
    uxTopReadyPriority = 0;
}

4.3 调度算法实现

FreeRTOS 的调度算法包含以下核心功能:

  • 优先级调度
static TCB_t *prvGetHighestPriorityTask(void) {
    TCB_t *pxTCB = NULL;
    UBaseType_t uxTopPriority = uxTopReadyPriority;
    
    // 查找最高优先级的就绪任务
    while(listLIST_IS_EMPTY(&(pxReadyTasksLists[uxTopPriority])) && 
          uxTopPriority > 0) {
        --uxTopPriority;
    }
    
    // 获取该优先级下的第一个任务
    if(!listLIST_IS_EMPTY(&(pxReadyTasksLists[uxTopPriority]))) {
        ListItem_t *pxListItem = listGET_HEAD_ENTRY(&(pxReadyTasksLists[uxTopPriority]));
        pxTCB = listGET_LIST_ITEM_OWNER(pxListItem);
    }
    
    return pxTCB;
}
  • 时间片轮转

当多个相同优先级的任务就绪时,采用时间片轮转调度:

#if (configUSE_TIME_SLICING == 1)
void prvCheckTimeSlice(void) {
    if(listCURRENT_LIST_LENGTH(&(pxReadyTasksLists[pxCurrentTCB->uxPriority])) > 1) {
        listGET_OWNER_OF_NEXT_ENTRY(pxCurrentTCB, 
                                   &(pxReadyTasksLists[pxCurrentTCB->uxPriority]));
    }
}
#endif

4.4 任务切换机制

任务切换是调度器的核心操作,包含以下步骤:

void vTaskSwitchContext(void) {
    #if (configUSE_TASK_NOTIFICATIONS == 1)
    // 检查是否有高优先级任务被通知唤醒
    prvCheckPendingNotifications();
    #endif
    
    // 获取最高优先级任务
    TCB_t *pxNewTCB = prvGetHighestPriorityTask();
    
    if(pxNewTCB != pxCurrentTCB) {
        // 保存当前任务上下文
        portSAVE_CONTEXT();
        
        // 切换任务
        pxCurrentTCB = pxNewTCB;
        
        // 恢复新任务上下文
        portRESTORE_CONTEXT();
    }
}

4.5 调度触发条件

调度器在以下情况下会被触发:

  • 系统时钟中断
void xPortSysTickHandler(void) {
    // 关中断
    portDISABLE_INTERRUPTS();
    
    // 处理延时任务
    if(xTaskIncrementTick() != pdFALSE) {
        // 触发任务切换
        portNVIC_INT_CTRL_REG = portNVIC_PENDSVSET_BIT;
    }
    
    // 开中断
    portENABLE_INTERRUPTS();
}
  •  任务让出处理器
void taskYIELD(void) {
    // 触发PendSV中断,引发任务切换
    portYIELD();
}

4.6 优先级管理

FreeRTOS 支持动态优先级调整:

BaseType_t vTaskPrioritySet(TaskHandle_t xTask, UBaseType_t uxNewPriority) {
    TCB_t *pxTCB = xTask;
    
    taskENTER_CRITICAL();
    {
        // 记录原优先级
        UBaseType_t uxCurrentPriority = pxTCB->uxPriority;
        
        if(uxCurrentPriority != uxNewPriority) {
            // 更新优先级
            pxTCB->uxPriority = uxNewPriority;
            
            // 如果任务在就绪列表中,需要移动到新的优先级列表
            if(listIS_CONTAINED_WITHIN(&(pxReadyTasksLists[uxCurrentPriority]),
                                     &(pxTCB->xStateListItem))) {
                uxListRemove(&(pxTCB->xStateListItem));
                prvAddTaskToReadyList(pxTCB);
            }
        }
    }
    taskEXIT_CRITICAL();
    
    // 可能需要进行任务切换
    portYIELD_WITHIN_API();
}

4.7 调度锁定机制

为了保护临界区,FreeRTOS 提供了调度器锁定机制:

void vTaskSuspendAll(void) {
    // 增加调度器挂起计数
    ++uxSchedulerSuspended;
}

BaseType_t xTaskResumeAll(void) {
    BaseType_t xAlreadyYielded = pdFALSE;
    
    // 确保所有挂起的任务都被正确恢复
    taskENTER_CRITICAL();
    {
        --uxSchedulerSuspended;
        
        if(uxSchedulerSuspended == 0) {
            if(uxCurrentNumberOfTasks > 0) {
                // 检查是否需要任务切换
                if(xYieldPending != pdFALSE) {
                    xAlreadyYielded = pdTRUE;
                    xYieldPending = pdFALSE;
                    taskYIELD();
                }
            }
        }
    }
    taskEXIT_CRITICAL();
    
    return xAlreadyYielded;
}

5 任务间通信

5.1 队列(Queue)基本结构

队列是 FreeRTOS 最基础的任务间通信机制,其核心数据结构如下:

typedef struct QueueDefinition {
    int8_t *pcHead;                // 队列存储区首地址
    int8_t *pcTail;                // 队列存储区尾地址
    int8_t *pcWriteTo;             // 下一个写入位置
    int8_t *pcReadFrom;            // 下一个读取位置
    
    List_t xTasksWaitingToSend;    // 等待发送的任务列表
    List_t xTasksWaitingToReceive; // 等待接收的任务列表
    
    volatile UBaseType_t uxMessagesWaiting;  // 当前消息数量
    UBaseType_t uxLength;          // 队列长度
    UBaseType_t uxItemSize;        // 队列项大小
    
    volatile int8_t cRxLock;       // 接收锁
    volatile int8_t cTxLock;       // 发送锁
} xQUEUE;

队列创建与初始化:

QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize) {
    xQUEUE *pxNewQueue;
    size_t xQueueSizeInBytes;
    
    // 计算所需内存大小
    xQueueSizeInBytes = (size_t)(uxQueueLength * uxItemSize);
    
    // 分配队列结构内存
    pxNewQueue = pvPortMalloc(sizeof(xQUEUE) + xQueueSizeInBytes);
    
    if(pxNewQueue != NULL) {
        // 初始化队列存储区指针
        pxNewQueue->pcHead = ((int8_t *)pxNewQueue) + sizeof(xQUEUE);
        pxNewQueue->pcTail = pxNewQueue->pcHead + xQueueSizeInBytes;
        
        // 初始化其他成员
        pxNewQueue->uxLength = uxQueueLength;
        pxNewQueue->uxItemSize = uxItemSize;
        pxNewQueue->pcWriteTo = pxNewQueue->pcHead;
        pxNewQueue->pcReadFrom = pxNewQueue->pcHead;
        
        // 初始化任务等待列表
        vListInitialise(&(pxNewQueue->xTasksWaitingToSend));
        vListInitialise(&(pxNewQueue->xTasksWaitingToReceive));
    }
    
    return (QueueHandle_t)pxNewQueue;
}

5.2 信号量(Semaphore)

实现 FreeRTOS 的信号量基于队列实现,包括二值信号量和计数信号量:

// 创建二值信号量
SemaphoreHandle_t xSemaphoreCreateBinary(void) {
    SemaphoreHandle_t xSemaphore;
    
    // 创建长度为1的队列
    xSemaphore = xQueueGenericCreate(1, semSEMAPHORE_QUEUE_ITEM_LENGTH,
                                    queueQUEUE_TYPE_BINARY_SEMAPHORE);
    
    return xSemaphore;
}

// 创建计数信号量
SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount,
                                          UBaseType_t uxInitialCount) {
    SemaphoreHandle_t xSemaphore;
    
    // 创建指定长度的队列
    xSemaphore = xQueueCreateCountingSemaphore(uxMaxCount,
                                              uxInitialCount);
    
    return xSemaphore;
}

5.3事件组(Event Groups)

事件组用于多事件同步:

typedef struct EventGroupDef_t {
    EventBits_t uxEventBits;       // 事件位
    List_t xTasksWaitingForBits;   // 等待事件的任务列表
} EventGroup_t;

// 创建事件组
EventGroupHandle_t xEventGroupCreate(void) {
    EventGroup_t *pxEventBits;
    
    // 分配事件组结构内存
    pxEventBits = pvPortMalloc(sizeof(EventGroup_t));
    
    if(pxEventBits != NULL) {
        pxEventBits->uxEventBits = 0;
        vListInitialise(&(pxEventBits->xTasksWaitingForBits));
    }
    
    return (EventGroupHandle_t)pxEventBits;
}

5.4 消息缓冲区(Message Buffer)

用于处理变长数据的通信机制:

// 消息缓冲区结构
typedef struct MessageBufferDef_t {
    size_t xBufferSizeBytes;       // 缓冲区大小
    size_t xWriteIndex;            // 写入位置
    size_t xReadIndex;             // 读取位置
    size_t xFreeBytes;             // 可用空间
    size_t xBytesInBuffer;         // 已用空间
    uint8_t ucBuffer[];            // 实际存储区
} MessageBuffer_t;

// 发送消息到缓冲区
size_t xMessageBufferSend(MessageBufferHandle_t xMessageBuffer,
                         const void *pvTxData,
                         size_t xDataLengthBytes,
                         TickType_t xTicksToWait) {
    MessageBuffer_t *pxMessageBuffer = xMessageBuffer;
    size_t xReturn;
    
    // 检查是否有足够空间
    if(xDataLengthBytes <= pxMessageBuffer->xFreeBytes) {
        // 复制数据
        memcpy(&(pxMessageBuffer->ucBuffer[pxMessageBuffer->xWriteIndex]),
               pvTxData,
               xDataLengthBytes);
        
        // 更新索引
        pxMessageBuffer->xWriteIndex += xDataLengthBytes;
        pxMessageBuffer->xFreeBytes -= xDataLengthBytes;
        pxMessageBuffer->xBytesInBuffer += xDataLengthBytes;
        
        xReturn = xDataLengthBytes;
    } else {
        xReturn = 0;
    }
    
    return xReturn;
}

5.5 任务通知(Task Notification)

轻量级的任务间通信机制:

// 发送任务通知
BaseType_t xTaskGenericNotify(TaskHandle_t xTaskToNotify,
                             UBaseType_t uxIndexToNotify,
                             uint32_t ulValue,
                             eNotifyAction eAction,
                             uint32_t *pulPreviousNotificationValue) {
    TCB_t *pxTCB = xTaskToNotify;
    BaseType_t xReturn = pdPASS;
    uint8_t ucOriginalNotifyState;
    
    taskENTER_CRITICAL();
    {
        ucOriginalNotifyState = pxTCB->ucNotifyState[uxIndexToNotify];
        pxTCB->ucNotifyState[uxIndexToNotify] = taskNOTIFICATION_RECEIVED;
        
        switch(eAction) {
            case eSetBits:
                pxTCB->ulNotifiedValue[uxIndexToNotify] |= ulValue;
                break;
            case eIncrement:
                pxTCB->ulNotifiedValue[uxIndexToNotify]++;
                break;
            case eSetValueWithOverwrite:
                pxTCB->ulNotifiedValue[uxIndexToNotify] = ulValue;
                break;
            default:
                /* 其他操作类型处理 */
                break;
        }
        
        // 如果任务在等待通知,则唤醒它
        if(ucOriginalNotifyState == taskWAITING_NOTIFICATION) {
            if(uxSchedulerSuspended == 0) {
                vTaskRemoveFromAllReadyLists(pxTCB);
                prvAddTaskToReadyList(pxTCB);
            }
        }
    }
    taskEXIT_CRITICAL();
    
    return xReturn;
}

5.6 流控制机制

为避免通信拥塞,FreeRTOS 提供了流控制功能:

BaseType_t xQueueSendWithTimeout(QueueHandle_t xQueue,
                                const void *pvItemToQueue,
                                TickType_t xTicksToWait) {
    BaseType_t xEntryTimeSet = pdFALSE;
    TimeOut_t xTimeOut;
    
    // 设置超时
    vTaskSetTimeOutState(&xTimeOut);
    
    for(;;) {
        taskENTER_CRITICAL();
        {
            // 检查队列是否有空间
            if(xQueue->uxMessagesWaiting < xQueue->uxLength) {
                prvCopyDataToQueue(xQueue, pvItemToQueue);
                taskEXIT_CRITICAL();
                return pdPASS;
            }
            else if(xTicksToWait == 0) {
                taskEXIT_CRITICAL();
                return errQUEUE_FULL;
            }
            else {
                // 将任务加入等待发送列表
                vTaskPlaceOnEventList(&(xQueue->xTasksWaitingToSend),
                                    xTicksToWait);
                taskEXIT_CRITICAL();
            }
        }
        
        // 等待空间可用或超时
        taskENTER_CRITICAL();
        if(xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) != pdFALSE) {
            // 超时处理
            uxListRemove(&(pxCurrentTCB->xEventListItem));
            taskEXIT_CRITICAL();
            return errQUEUE_FULL;
        }
        taskEXIT_CRITICAL();
    }
}

这些通信机制为 FreeRTOS 的任务间协作提供了完整的解决方案。

在实践中逐步应用这些知识,从简单的任务创建开始,逐步过渡到更复杂的多任务管理和通信机制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

可喜~可乐

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

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

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

打赏作者

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

抵扣说明:

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

余额充值