FreeRTOS内核原理与应用详解

次浏览

概述

FreeRTOS 是一款流行的开源实时操作系统内核,专为嵌入式设备设计。它小巧、高效、易于使用,广泛应用于物联网设备、工业控制、消费电子等领域。

FreeRTOS 特点

特性 说明
开源免费 MIT 许可证,商用友好
小巧 核心 3-10KB ROM,最小 300B RAM
可移植 支持 40+ 架构(ARM、RISC-V、ESP32等)
实时性 确定性调度,快速响应中断
丰富功能 任务、队列、信号量、定时器等

一、任务管理

1.1 任务的概念

任务是 FreeRTOS 调度的基本单位,每个任务都是一个独立的执行流,拥有自己的栈空间和上下文。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// 任务函数原型
void vTaskFunction(void *pvParameters);

// 任务示例
void vLEDTask(void *pvParameters) {
    while (1) {
        LED_Toggle();
        vTaskDelay(pdMS_TO_TICKS(500));  // 延时500ms
    }
}

1.2 任务状态

FreeRTOS 任务有四种状态:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
                    ┌─────────────────┐
                    │    运行态       │
                    │   (Running)     │
                    └────────┬────────┘
                             │ 被抢占/时间片用完
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│    就绪态       │◄───│    阻塞态       │◄───│    挂起态       │
│   (Ready)       │───►│   (Blocked)     │───►│   (Suspended)   │
└─────────────────┘    └─────────────────┘    └─────────────────┘
        │                      │                      │
        │ 被调度器选中          │ 等待事件超时          │ vTaskResume()
        ▼                      │ 等待资源可用          │
   进入运行态                   ▼                      ▼
                          进入就绪态              进入就绪态

1.3 任务创建与删除

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include "FreeRTOS.h"
#include "task.h"

// 任务句柄
TaskHandle_t xLedTaskHandle;
TaskHandle_t xSensorTaskHandle;

// 任务函数
void vLedTask(void *pvParameters) {
    const char *pcTaskName = (const char *)pvParameters;
    
    while (1) {
        printf("%s: LED toggle\n", pcTaskName);
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

void vSensorTask(void *pvParameters) {
    while (1) {
        int sensor_value = read_sensor();
        printf("Sensor: %d\n", sensor_value);
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

int main(void) {
    // 创建任务
    // 参数: 任务函数, 任务名称, 栈大小, 参数, 优先级, 任务句柄
    BaseType_t xReturn1 = xTaskCreate(
        vLedTask,               // 任务函数
        "LED",                  // 任务名称
        128,                    // 栈大小(字)
        "LED Task",             // 传递参数
        1,                      // 优先级
        &xLedTaskHandle         // 任务句柄
    );
    
    BaseType_t xReturn2 = xTaskCreate(
        vSensorTask,
        "Sensor",
        128,
        NULL,
        2,                      // 更高优先级
        &xSensorTaskHandle
    );
    
    if (xReturn1 == pdPASS && xReturn2 == pdPASS) {
        // 启动调度器
        vTaskStartScheduler();
    }
    
    // 正常情况下不会到达这里
    while (1);
    
    return 0;
}

// 删除任务(可以在任务内部或外部调用)
void delete_task_example(void) {
    vTaskDelete(xLedTaskHandle);  // 删除指定任务
    vTaskDelete(NULL);            // 删除当前任务
}

1.4 任务优先级与调度

FreeRTOS 采用抢占式优先级调度

1
2
3
4
5
6
// 优先级范围: 0 (最低) ~ configMAX_PRIORITIES-1 (最高)

// 同优先级任务使用时间片轮转
void vApplicationIdleHook(void) {
    // 空闲任务钩子函数
}

调度规则

  1. 高优先级任务总是抢占低优先级任务
  2. 同优先级任务按时间片轮转(可配置)
  3. 阻塞的任务不参与调度

1.5 任务延时

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// 相对延时(阻塞指定时间)
vTaskDelay(pdMS_TO_TICKS(1000));  // 延时1000ms

// 绝对延时(周期性任务推荐)
void vPeriodicTask(void *pvParameters) {
    TickType_t xLastWakeTime = xTaskGetTickCount();
    const TickType_t xFrequency = pdMS_TO_TICKS(100);
    
    while (1) {
        // 执行任务...
        
        // 精确周期性延时
        vTaskDelayUntil(&xLastWakeTime, xFrequency);
    }
}

1.6 任务通知

任务通知是 FreeRTOS 的轻量级通信机制:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 发送通知
void vSenderTask(void *pvParameters) {
    while (1) {
        // 发送通知给接收任务
        xTaskNotifyGive(xReceiverTaskHandle);
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

// 接收通知
void vReceiverTask(void *pvParameters) {
    while (1) {
        // 等待通知
        uint32_t ulNotificationValue = ulTaskNotifyTake(
            pdTRUE,           // 清除通知值
            portMAX_DELAY     // 无限等待
        );
        
        if (ulNotificationValue > 0) {
            printf("Received notification!\n");
        }
    }
}

// 发送带值的通知
void vNotifyWithValue(void) {
    xTaskNotify(xTaskHandle, 0x01, eSetBits);      // 设置位
    xTaskNotify(xTaskHandle, 100, eIncrement);      // 增加值
    xTaskNotify(xTaskHandle, 0x55, eSetValueWithOverwrite); // 覆盖值
}

二、内存管理

2.1 内存分配方案

FreeRTOS 提供 5 种内存管理方案:

方案 文件 特点 适用场景
heap_1 heap_1.c 只分配不释放 简单系统
heap_2 heap_2.c 可分配释放,不合并 固定大小块
heap_3 heap_3.c 封装标准库 malloc 有标准库
heap_4 heap_4.c 可分配释放,合并碎片 通用推荐
heap_5 heap_5.c 多内存区域 非连续内存

2.2 内存分配函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include "FreeRTOS.h"

// 动态内存分配
void *pvPortMalloc(size_t xWantedSize);
void vPortFree(void *pv);
size_t xPortGetFreeHeapSize(void);
size_t xPortGetMinimumEverFreeHeapSize(void);

// 使用示例
void memory_example(void) {
    // 分配内存
    uint8_t *buffer = (uint8_t *)pvPortMalloc(256);
    
    if (buffer != NULL) {
        // 使用内存
        memset(buffer, 0, 256);
        
        // 释放内存
        vPortFree(buffer);
    }
    
    // 查看剩余内存
    printf("Free heap: %u bytes\n", xPortGetFreeHeapSize());
}

2.3 静态内存分配

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 静态创建任务
static StackType_t xStack[128];
static StaticTask_t xTaskBuffer;

void static_task_example(void) {
    TaskHandle_t xHandle = xTaskCreateStatic(
        vTaskFunction,       // 任务函数
        "StaticTask",        // 名称
        128,                 // 栈大小
        NULL,                // 参数
        1,                   // 优先级
        xStack,              // 栈数组
        &xTaskBuffer         // 任务控制块
    );
    
    vTaskStartScheduler();
}

// 静态创建队列
static uint8_t ucQueueStorage[10 * sizeof(uint32_t)];
static StaticQueue_t xQueueBuffer;

void static_queue_example(void) {
    QueueHandle_t xQueue = xQueueCreateStatic(
        10,                           // 队列长度
        sizeof(uint32_t),             // 元素大小
        ucQueueStorage,               // 存储区域
        &xQueueBuffer                 // 队列控制块
    );
}

2.4 内存配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
// FreeRTOSConfig.h 中的内存相关配置

// 总堆大小
#define configTOTAL_HEAP_SIZE           (40 * 1024)  // 40KB

// 内存分配失败钩子
#define configUSE_MALLOC_FAILED_HOOK    1

void vApplicationMallocFailedHook(void) {
    taskDISABLE_INTERRUPTS();
    printf("Memory allocation failed!\n");
    while (1);
}

三、队列

3.1 队列基础

队列是 FreeRTOS 任务间通信的主要方式,支持在任务之间传递数据。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include "queue.h"

// 创建队列
QueueHandle_t xQueue;

void queue_create_example(void) {
    // 参数: 队列长度, 每个元素大小
    xQueue = xQueueCreate(10, sizeof(uint32_t));
    
    if (xQueue == NULL) {
        printf("Queue creation failed!\n");
    }
}

// 发送到队列
void vSenderTask(void *pvParameters) {
    uint32_t ulValueToSend = 0;
    
    while (1) {
        ulValueToSend++;
        
        // 发送数据到队列尾部
        if (xQueueSend(xQueue, &ulValueToSend, pdMS_TO_TICKS(100)) != pdPASS) {
            printf("Queue send failed!\n");
        }
        
        // 发送到队列头部
        // xQueueSendToFront(xQueue, &ulValueToSend, pdMS_TO_TICKS(100));
        
        // 覆盖队列头部(用于环形缓冲)
        // xQueueOverwrite(xQueue, &ulValueToSend);
        
        vTaskDelay(pdMS_TO_TICKS(50));
    }
}

// 从队列接收
void vReceiverTask(void *pvParameters) {
    uint32_t ulReceivedValue;
    
    while (1) {
        // 从队列头部接收
        if (xQueueReceive(xQueue, &ulReceivedValue, pdMS_TO_TICKS(200)) == pdPASS) {
            printf("Received: %lu\n", ulReceivedValue);
        }
        
        // 查看队列数据但不移除
        // xQueuePeek(xQueue, &ulReceivedValue, pdMS_TO_TICKS(100));
    }
}

// 删除队列
void queue_delete_example(void) {
    vQueueDelete(xQueue);
}

3.2 队列操作函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// 发送函数
BaseType_t xQueueSend(QueueHandle_t xQueue, 
                      const void *pvItemToQueue, 
                      TickType_t xTicksToWait);

BaseType_t xQueueSendToFront(QueueHandle_t xQueue, 
                             const void *pvItemToQueue, 
                             TickType_t xTicksToWait);

BaseType_t xQueueSendToBack(QueueHandle_t xQueue, 
                            const void *pvItemToQueue, 
                            TickType_t xTicksToWait);

BaseType_t xQueueOverwrite(QueueHandle_t xQueue, 
                           const void *pvItemToQueue);

// 接收函数
BaseType_t xQueueReceive(QueueHandle_t xQueue, 
                         void *pvBuffer, 
                         TickType_t xTicksToWait);

BaseType_t xQueuePeek(QueueHandle_t xQueue, 
                      void *pvBuffer, 
                      TickType_t xTicksToWait);

// 查询函数
UBaseType_t uxQueueMessagesWaiting(QueueHandle_t xQueue);
UBaseType_t uxQueueSpacesAvailable(QueueHandle_t xQueue);
BaseType_t xQueueIsQueueEmptyFromISR(QueueHandle_t xQueue);
BaseType_t xQueueIsQueueFullFromISR(QueueHandle_t xQueue);

3.3 中断中使用队列

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 中断服务函数中使用队列
void UART_IRQHandler(void) {
    uint8_t ucReceivedByte;
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    // 读取接收到的数据
    ucReceivedByte = UART_DR;
    
    // 从ISR发送到队列
    xQueueSendFromISR(xQueue, &ucReceivedByte, &xHigherPriorityTaskWoken);
    
    // 如果唤醒了更高优先级任务,触发上下文切换
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

// ISR专用函数
BaseType_t xQueueSendFromISR(QueueHandle_t xQueue, 
                             const void *pvItemToQueue, 
                             BaseType_t *pxHigherPriorityTaskWoken);

BaseType_t xQueueReceiveFromISR(QueueHandle_t xQueue, 
                                void *pvBuffer, 
                                BaseType_t *pxHigherPriorityTaskWoken);

四、信号量与互斥量

4.1 二值信号量

用于任务同步,类似于标志位:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "semphr.h"

SemaphoreHandle_t xBinarySemaphore;

void binary_sem_example(void) {
    // 创建二值信号量
    xBinarySemaphore = xSemaphoreCreateBinary();
    
    if (xBinarySemaphore == NULL) {
        printf("Semaphore creation failed!\n");
    }
}

// 中断中释放信号量
void EXTI_IRQHandler(void) {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    // 清除中断标志
    EXTI_ClearFlag();
    
    // 释放信号量
    xSemaphoreGiveFromISR(xBinarySemaphore, &xHigherPriorityTaskWoken);
    
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

// 任务中等待信号量
void vWaitTask(void *pvParameters) {
    while (1) {
        // 等待信号量(阻塞)
        if (xSemaphoreTake(xBinarySemaphore, portMAX_DELAY) == pdTRUE) {
            printf("Event received!\n");
        }
    }
}

4.2 计数信号量

用于资源计数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
SemaphoreHandle_t xCountingSemaphore;

void counting_sem_example(void) {
    // 参数: 最大计数值, 初始计数值
    xCountingSemaphore = xSemaphoreCreateCounting(5, 0);
}

// 生产者
void vProducerTask(void *pvParameters) {
    while (1) {
        // 释放信号量(计数+1)
        xSemaphoreGive(xCountingSemaphore);
        printf("Produced, count: %u\n", 
               uxSemaphoreGetCount(xCountingSemaphore));
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

// 消费者
void vConsumerTask(void *pvParameters) {
    while (1) {
        // 获取信号量(计数-1)
        if (xSemaphoreTake(xCountingSemaphore, portMAX_DELAY) == pdTRUE) {
            printf("Consumed, count: %u\n", 
                   uxSemaphoreGetCount(xCountingSemaphore));
        }
    }
}

4.3 互斥量

用于保护共享资源,具有优先级继承机制:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
SemaphoreHandle_t xMutex;

void mutex_example(void) {
    // 创建互斥量
    xMutex = xSemaphoreCreateMutex();
}

// 使用互斥量保护共享资源
void vTask1(void *pvParameters) {
    while (1) {
        // 获取互斥量
        if (xSemaphoreTake(xMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
            // 访问共享资源
            shared_resource++;
            printf("Task1: shared_resource = %d\n", shared_resource);
            
            // 释放互斥量
            xSemaphoreGive(xMutex);
        }
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

void vTask2(void *pvParameters) {
    while (1) {
        if (xSemaphoreTake(xMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
            shared_resource--;
            printf("Task2: shared_resource = %d\n", shared_resource);
            xSemaphoreGive(xMutex);
        }
        vTaskDelay(pdMS_TO_TICKS(15));
    }
}

4.4 递归互斥量

同一任务可以多次获取:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
SemaphoreHandle_t xRecursiveMutex;

void recursive_mutex_example(void) {
    xRecursiveMutex = xSemaphoreCreateRecursiveMutex();
}

void vRecursiveFunction(void) {
    // 第一次获取
    if (xSemaphoreTakeRecursive(xRecursiveMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
        printf("First take\n");
        
        // 第二次获取(同一任务)
        if (xSemaphoreTakeRecursive(xRecursiveMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
            printf("Second take\n");
            xSemaphoreGiveRecursive(xRecursiveMutex);
        }
        
        xSemaphoreGiveRecursive(xRecursiveMutex);
    }
}

五、软件定时器

5.1 定时器基础

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include "timers.h"

TimerHandle_t xTimer;

// 定时器回调函数
void vTimerCallback(TimerHandle_t xTimer) {
    printf("Timer expired!\n");
}

void timer_create_example(void) {
    // 创建单次定时器
    xTimer = xTimerCreate(
        "MyTimer",                    // 定时器名称
        pdMS_TO_TICKS(1000),          // 周期
        pdFALSE,                      // 自动重载 (pdFALSE = 单次)
        (void *)0,                    // 定时器ID
        vTimerCallback                // 回调函数
    );
    
    if (xTimer != NULL) {
        // 启动定时器
        xTimerStart(xTimer, pdMS_TO_TICKS(100));
    }
}

// 周期定时器
void periodic_timer_example(void) {
    TimerHandle_t xPeriodicTimer = xTimerCreate(
        "PeriodicTimer",
        pdMS_TO_TICKS(500),           // 500ms周期
        pdTRUE,                        // 自动重载
        (void *)1,
        vTimerCallback
    );
    
    xTimerStart(xPeriodicTimer, 0);
}

5.2 定时器操作

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// 启动定时器
BaseType_t xTimerStart(TimerHandle_t xTimer, TickType_t xTicksToWait);
BaseType_t xTimerStartFromISR(TimerHandle_t xTimer, BaseType_t *pxHigherPriorityTaskWoken);

// 停止定时器
BaseType_t xTimerStop(TimerHandle_t xTimer, TickType_t xTicksToWait);
BaseType_t xTimerStopFromISR(TimerHandle_t xTimer, BaseType_t *pxHigherPriorityTaskWoken);

// 重置定时器
BaseType_t xTimerReset(TimerHandle_t xTimer, TickType_t xTicksToWait);
BaseType_t xTimerResetFromISR(TimerHandle_t xTimer, BaseType_t *pxHigherPriorityTaskWoken);

// 修改周期
BaseType_t xTimerChangePeriod(TimerHandle_t xTimer, TickType_t xNewPeriod, TickType_t xTicksToWait);

// 获取定时器ID
void *pvTimerGetTimerID(TimerHandle_t xTimer);

5.3 定时器服务任务

软件定时器运行在定时器服务任务中,需要配置:

1
2
3
4
5
// FreeRTOSConfig.h
#define configUSE_TIMERS                1
#define configTIMER_TASK_PRIORITY       3
#define configTIMER_QUEUE_LENGTH        10
#define configTIMER_TASK_STACK_DEPTH    128

六、事件组

6.1 事件组基础

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include "event_groups.h"

EventGroupHandle_t xEventGroup;

// 事件位定义
#define EVENT_BIT_0 (1 << 0)
#define EVENT_BIT_1 (1 << 1)
#define EVENT_BIT_2 (1 << 2)

void event_group_create(void) {
    xEventGroup = xEventGroupCreate();
}

// 设置事件位
void vEventSetterTask(void *pvParameters) {
    while (1) {
        // 设置事件位
        xEventGroupSetBits(xEventGroup, EVENT_BIT_0);
        vTaskDelay(pdMS_TO_TICKS(100));
        
        xEventGroupSetBits(xEventGroup, EVENT_BIT_1);
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

// 等待事件
void vEventWaiterTask(void *pvParameters) {
    EventBits_t xEventBits;
    
    while (1) {
        // 等待多个事件位(任意一个)
        xEventBits = xEventGroupWaitBits(
            xEventGroup,
            EVENT_BIT_0 | EVENT_BIT_1,   // 等待的位
            pdTRUE,                       // 退出时清除
            pdFALSE,                      // 任意一个位即可
            portMAX_DELAY                 // 等待时间
        );
        
        if (xEventBits & EVENT_BIT_0) {
            printf("Event 0 occurred\n");
        }
        if (xEventBits & EVENT_BIT_1) {
            printf("Event 1 occurred\n");
        }
    }
}

// 等待所有位
void wait_all_bits(void) {
    EventBits_t xEventBits = xEventGroupWaitBits(
        xEventGroup,
        EVENT_BIT_0 | EVENT_BIT_1 | EVENT_BIT_2,
        pdTRUE,
        pdTRUE,                      // 等待所有位
        pdMS_TO_TICKS(1000)
    );
}

6.2 ISR 中使用事件组

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
void ISR_Handler(void) {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    xEventGroupSetBitsFromISR(
        xEventGroup,
        EVENT_BIT_0,
        &xHigherPriorityTaskWoken
    );
    
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

七、流缓冲区与消息缓冲区

7.1 流缓冲区

用于字节流传输:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include "stream_buffer.h"

StreamBufferHandle_t xStreamBuffer;

void stream_buffer_example(void) {
    // 创建流缓冲区
    // 参数: 缓冲区大小, 触发阈值
    xStreamBuffer = xStreamBufferCreate(256, 1);
}

// 发送数据
void vSenderTask(void *pvParameters) {
    const char *data = "Hello FreeRTOS!";
    size_t xBytesSent;
    
    xBytesSent = xStreamBufferSend(
        xStreamBuffer,
        data,
        strlen(data),
        pdMS_TO_TICKS(100)
    );
}

// 接收数据
void vReceiverTask(void *pvParameters) {
    char rxBuffer[32];
    size_t xReceivedBytes;
    
    xReceivedBytes = xStreamBufferReceive(
        xStreamBuffer,
        rxBuffer,
        sizeof(rxBuffer) - 1,
        pdMS_TO_TICKS(100)
    );
    
    if (xReceivedBytes > 0) {
        rxBuffer[xReceivedBytes] = '\0';
        printf("Received: %s\n", rxBuffer);
    }
}

7.2 消息缓冲区

用于变长消息传输:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include "message_buffer.h"

MessageBufferHandle_t xMessageBuffer;

void message_buffer_example(void) {
    xMessageBuffer = xMessageBufferCreate(256);
}

// 发送消息
void vMessageSender(void *pvParameters) {
    const char *message = "Message 1";
    
    xMessageBufferSend(
        xMessageBuffer,
        message,
        strlen(message) + 1,  // 包含终止符
        pdMS_TO_TICKS(100)
    );
}

// 接收消息
void vMessageReceiver(void *pvParameters) {
    char rxMessage[64];
    size_t xReceivedBytes;
    
    xReceivedBytes = xMessageBufferReceive(
        xMessageBuffer,
        rxMessage,
        sizeof(rxMessage),
        pdMS_TO_TICKS(100)
    );
    
    if (xReceivedBytes > 0) {
        printf("Message: %s\n", rxMessage);
    }
}

八、中断管理

8.1 中断优先级配置

1
2
3
4
5
6
7
8
9
// FreeRTOSConfig.h

// 中断优先级配置
#define configKERNEL_INTERRUPT_PRIORITY         255     // 最低优先级
#define configMAX_SYSCALL_INTERRUPT_PRIORITY    191     // FreeRTOS可管理的最高中断优先级

// ARM Cortex-M 中:
// 优先级数值越小,优先级越高
// configMAX_SYSCALL_INTERRUPT_PRIORITY 以上的中断不能调用FreeRTOS API

8.2 中断服务函数模板

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
void UART_IRQHandler(void) {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    uint8_t ucReceivedByte;
    
    // 读取中断状态
    if (UART_GetITStatus(UART_IT_RXNE)) {
        ucReceivedByte = UART_ReceiveByte();
        
        // 使用 FromISR 版本的 API
        xQueueSendFromISR(xRxQueue, &ucReceivedByte, &xHigherPriorityTaskWoken);
    }
    
    // 如果唤醒了更高优先级任务,请求上下文切换
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

8.3 中断安全函数

标准函数 ISR 安全函数
xQueueSend xQueueSendFromISR
xQueueReceive xQueueReceiveFromISR
xSemaphoreGive xSemaphoreGiveFromISR
xSemaphoreTake xSemaphoreTakeFromISR
xEventGroupSetBits xEventGroupSetBitsFromISR
xTimerStart xTimerStartFromISR

九、资源管理

9.1 临界区

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 任务级临界区
void critical_section_example(void) {
    // 进入临界区(禁用中断)
    taskENTER_CRITICAL();
    
    // 访问共享资源
    shared_variable++;
    
    // 退出临界区(恢复中断)
    taskEXIT_CRITICAL();
}

// ISR 级临界区
void ISR_critical_example(void) {
    UBaseType_t uxSavedStatus;
    
    // 保存并禁用中断
    uxSavedStatus = taskENTER_CRITICAL_FROM_ISR();
    
    // 访问共享资源
    shared_variable++;
    
    // 恢复中断状态
    taskEXIT_CRITICAL_FROM_ISR(uxSavedStatus);
}

9.2 挂起调度器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 挂起调度器(不禁用中断)
void suspend_scheduler_example(void) {
    vTaskSuspendAll();
    
    // 访问共享资源
    // 此时其他任务无法运行,但中断仍然响应
    shared_resource++;
    
    // 恢复调度器
    xTaskResumeAll();
}

9.3 禁用中断

1
2
3
4
5
6
7
8
9
// 禁用中断
void disable_interrupts_example(void) {
    // 保存当前中断状态并禁用
    portENTER_CRITICAL();
    
    // ...
    
    portEXIT_CRITICAL();
}

十、配置选项

10.1 FreeRTOSConfig.h 核心配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H

// ========== 基本配置 ==========
#define configUSE_PREEMPTION                    1
#define configUSE_IDLE_HOOK                     0
#define configUSE_TICK_HOOK                     0
#define configCPU_CLOCK_HZ                      (72000000UL)
#define configTICK_RATE_HZ                      ((TickType_t)1000)
#define configMAX_PRIORITIES                    7
#define configMINIMAL_STACK_SIZE                ((uint16_t)128)
#define configTOTAL_HEAP_SIZE                   ((size_t)(40 * 1024))
#define configMAX_TASK_NAME_LEN                 16
#define configUSE_16_BIT_TICKS                  0
#define configIDLE_SHOULD_YIELD                 1
#define configUSE_MUTEXES                       1
#define configUSE_RECURSIVE_MUTEXES             1
#define configUSE_COUNTING_SEMAPHORES           1
#define configUSE_QUEUE_SETS                    1
#define configUSE_TIME_SLICING                  1

// ========== 内存配置 ==========
#define configSUPPORT_STATIC_ALLOCATION         1
#define configSUPPORT_DYNAMIC_ALLOCATION        1
#define configAPPLICATION_ALLOCATED_HEAP        0

// ========== 钩子函数配置 ==========
#define configCHECK_FOR_STACK_OVERFLOW          2
#define configUSE_MALLOC_FAILED_HOOK            1

// ========== 软件定时器配置 ==========
#define configUSE_TIMERS                        1
#define configTIMER_TASK_PRIORITY               3
#define configTIMER_QUEUE_LENGTH                10
#define configTIMER_TASK_STACK_DEPTH            128

// ========== 断言配置 ==========
#include <stdio.h>
#define configASSERT(x) if((x) == 0) { taskDISABLE_INTERRUPTS(); printf("Assert failed: %s\n", #x); while(1); }

// ========== 中断优先级配置 (Cortex-M) ==========
#ifdef __NVIC_PRIO_BITS
    #define configPRIO_BITS                    __NVIC_PRIO_BITS
#else
    #define configPRIO_BITS                    4
#endif

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY         15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    5
#define configKERNEL_INTERRUPT_PRIORITY                 (configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))
#define configMAX_SYSCALL_INTERRUPT_PRIORITY            (configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS))

#endif

10.2 钩子函数实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 空闲任务钩子
void vApplicationIdleHook(void) {
    // 省电模式
    __WFI();
}

// 栈溢出钩子
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) {
    printf("Stack overflow in task: %s\n", pcTaskName);
    while (1);
}

// 内存分配失败钩子
void vApplicationMallocFailedHook(void) {
    printf("Memory allocation failed!\n");
    while (1);
}

// Tick 钩子
void vApplicationTickHook(void) {
    // 每 tick 执行一次
}

十一、调试与优化

11.1 任务统计

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
// 启用任务统计
#define configGENERATE_RUN_TIME_STATS    1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1

// 获取任务运行时间
void print_task_stats(void) {
    char *pcWriteBuffer = pvPortMalloc(1024);
    
    vTaskList(pcWriteBuffer);
    printf("Task            State   Prio    Stack   Num\n");
    printf("%s\n", pcWriteBuffer);
    
    vPortFree(pcWriteBuffer);
}

// 输出示例:
// Task            State   Prio    Stack   Num
// IDLE            R       0       100     1
// LED             B       1       80      2
// Sensor          B       2       60      3
// Tmr Svc         S       3       90      4

11.2 栈使用监控

1
2
3
// 获取任务栈剩余空间
UBaseType_t uxStackRemaining = uxTaskGetStackHighWaterMark(xTaskHandle);
printf("Stack remaining: %u words\n", uxStackRemaining);

11.3 运行时间统计

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 配置运行时间统计
#define configGENERATE_RUN_TIME_STATS    1
#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()  // 配置定时器
#define portGET_RUN_TIME_COUNTER_VALUE()  // 返回时间计数

void print_runtime_stats(void) {
    char *pcWriteBuffer = pvPortMalloc(512);
    
    vTaskGetRunTimeStats(pcWriteBuffer);
    printf("Task            Abs Time        %% Time\n");
    printf("%s\n", pcWriteBuffer);
    
    vPortFree(pcWriteBuffer);
}

十二、完整示例

12.1 生产者-消费者模型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

QueueHandle_t xQueue;

// 生产者任务
void vProducerTask(void *pvParameters) {
    uint32_t ulCounter = 0;
    
    while (1) {
        ulCounter++;
        
        if (xQueueSend(xQueue, &ulCounter, pdMS_TO_TICKS(100)) != pdPASS) {
            printf("Queue full!\n");
        }
        
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

// 消费者任务
void vConsumerTask(void *pvParameters) {
    uint32_t ulReceivedValue;
    
    while (1) {
        if (xQueueReceive(xQueue, &ulReceivedValue, portMAX_DELAY) == pdPASS) {
            printf("Consumed: %lu\n", ulReceivedValue);
        }
    }
}

int main(void) {
    // 创建队列
    xQueue = xQueueCreate(10, sizeof(uint32_t));
    
    if (xQueue != NULL) {
        // 创建任务
        xTaskCreate(vProducerTask, "Producer", 128, NULL, 1, NULL);
        xTaskCreate(vConsumerTask, "Consumer", 128, NULL, 2, NULL);
        
        // 启动调度器
        vTaskStartScheduler();
    }
    
    while (1);
    return 0;
}

12.2 多任务数据采集系统

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "timers.h"

// 传感器数据结构
typedef struct {
    uint8_t sensor_id;
    float value;
    uint32_t timestamp;
} SensorData_t;

// 句柄定义
QueueHandle_t xSensorQueue;
SemaphoreHandle_t xI2CMutex;
TimerHandle_t xSampleTimer;

// 数据采样回调(定时器)
void vSampleTimerCallback(TimerHandle_t xTimer) {
    static uint8_t sensor_id = 0;
    SensorData_t data;
    
    data.sensor_id = sensor_id;
    data.value = read_sensor(sensor_id);
    data.timestamp = xTaskGetTickCount();
    
    xQueueSendFromISR(xSensorQueue, &data, NULL);
    
    sensor_id = (sensor_id + 1) % 4;
}

// 数据处理任务
void vDataProcessTask(void *pvParameters) {
    SensorData_t data;
    
    while (1) {
        if (xQueueReceive(xSensorQueue, &data, portMAX_DELAY) == pdPASS) {
            printf("Sensor %d: %.2f @ %lu\n", 
                   data.sensor_id, data.value, data.timestamp);
        }
    }
}

// 显示任务
void vDisplayTask(void *pvParameters) {
    while (1) {
        update_display();
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

int main(void) {
    // 创建队列
    xSensorQueue = xQueueCreate(20, sizeof(SensorData_t));
    
    // 创建互斥量
    xI2CMutex = xSemaphoreCreateMutex();
    
    // 创建定时器
    xSampleTimer = xTimerCreate(
        "SampleTimer",
        pdMS_TO_TICKS(50),
        pdTRUE,
        NULL,
        vSampleTimerCallback
    );
    
    if (xSensorQueue && xI2CMutex && xSampleTimer) {
        // 创建任务
        xTaskCreate(vDataProcessTask, "Process", 256, NULL, 2, NULL);
        xTaskCreate(vDisplayTask, "Display", 128, NULL, 1, NULL);
        
        // 启动定时器
        xTimerStart(xSampleTimer, 0);
        
        // 启动调度器
        vTaskStartScheduler();
    }
    
    while (1);
    return 0;
}

十三、总结

13.1 核心概念速查

概念 用途 关键函数
任务 独立执行流 xTaskCreate, vTaskDelay
队列 任务间数据传递 xQueueCreate, xQueueSend, xQueueReceive
二值信号量 任务同步 xSemaphoreCreateBinary, xSemaphoreTake
计数信号量 资源计数 xSemaphoreCreateCounting
互斥量 资源保护 xSemaphoreCreateMutex
事件组 多事件同步 xEventGroupCreate, xEventGroupWaitBits
软件定时器 定时任务 xTimerCreate, xTimerStart
任务通知 轻量级同步 xTaskNotifyGive, ulTaskNotifyTake

13.2 最佳实践

  1. 栈大小:根据实际需求设置,避免浪费和溢出
  2. 优先级:合理分配,避免优先级反转
  3. 互斥量:保护共享资源,优先使用互斥量而非信号量
  4. 中断处理:ISR 中使用 FromISR 版本 API
  5. 内存管理:推荐使用 heap_4 方案
  6. 调试:启用栈溢出检测和运行时统计

参考资料

使用 Hugo 构建
主题 StackJimmy 设计