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 的初始化过程包含以下关键步骤:
- 硬件初始化
- 系统时钟配置
- 内存管理器初始化
- 创建初始任务
- 启动调度器
初始化代码示例:
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 采用以下优化策略:
- 使用双向链表减少遍历开销
- 按值排序加快查找速度
- 维护索引指针优化访问效率
- 使用内联函数减少函数调用开销
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 的任务间协作提供了完整的解决方案。
在实践中逐步应用这些知识,从简单的任务创建开始,逐步过渡到更复杂的多任务管理和通信机制。