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_1heap_1.c只分配不释放简单系统
heap_2heap_2.c可分配释放,不合并固定大小块
heap_3heap_3.c封装标准库 malloc有标准库
heap_4heap_4.c可分配释放,合并碎片通用推荐
heap_5heap_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 安全函数
xQueueSendxQueueSendFromISR
xQueueReceivexQueueReceiveFromISR
xSemaphoreGivexSemaphoreGiveFromISR
xSemaphoreTakexSemaphoreTakeFromISR
xEventGroupSetBitsxEventGroupSetBitsFromISR
xTimerStartxTimerStartFromISR

九、资源管理

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. 调试:启用栈溢出检测和运行时统计

参考资料

评论

留言经审核后显示,欢迎留下想法。