04 - 核心编程

FreeRTOS 任务管理与内存管理

FreeRTOS 基础

ESP32 使用 FreeRTOS 作为实时操作系统,支持双核并行执行。

核心概念

┌────────────────────────────────────────┐
│              CPU Core 0                 │
│  ┌──────────┐   ┌──────────┐          │
│  │  Task A  │   │  Task B  │          │
│  │ (High)   │   │ (Medium) │          │
│  └────┬─────┘   └────┬─────┘          │
│       │              │                 │
│  ┌────▼──────────────▼─────┐          │
│  │      Task Scheduler      │          │
│  └──────────────────────────┘          │
└────────────────────────────────────────┘

任务状态

        ┌─────────┐
        │  Ready  │
        └────┬────┘
             │ 调度
    ┌────────┼────────┐
    │        │        │
┌───▼───┐ ┌──▼──┐ ┌──▼────┐
│Running│ │ Blocked │ │Suspended│
└───────┘ └──────┘ └────────┘
    │        │        │
    └────────┴────────┘
           时间片/事件

任务管理

创建任务

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
 
void task_function(void *parameter)
{
    while (1) {
        printf("Task running...\n");
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}
 
void app_main(void)
{
    xTaskCreate(
        task_function,      // 任务函数
        "TaskName",         // 任务名称
        4096,               // 栈深度(字)
        NULL,               // 参数
        1,                  // 优先级
        NULL                // 任务句柄
    );
}

任务参数说明

参数说明建议值
pvTaskCode任务函数-
pcName任务名称字符串
usStackDepth栈深度(字节=字×4)2048-4096
pvParameters传入参数NULL 或指针
uxPriority优先级 (0最低)1-10
pxCreatedTask任务句柄NULL

删除任务

// 任务内自删
void self_delete_task(void *pvParameters)
{
    // 执行任务工作
    vTaskDelete(NULL);  // 删除自己
}
 
// 从其他任务删除
void another_task(void)
{
    xTaskHandle handle;
    xTaskCreate(..., &handle);
    vTaskDelete(handle);
}

任务间通信

队列 (Queue)

#include "freertos/queue.h"
 
QueueHandle_t msg_queue;
 
// 创建队列
msg_queue = xQueueCreate(10, sizeof(int));
 
// 发送
void sender_task(void *pvParameters)
{
    int value = 100;
    xQueueSend(msg_queue, &value, portMAX_DELAY);
}
 
// 接收
void receiver_task(void *pvParameters)
{
    int value;
    while (1) {
        if (xQueueReceive(msg_queue, &value, pdMS_TO_TICKS(1000)) == pdTRUE) {
            printf("Received: %d\n", value);
        }
    }
}

信号量 (Semaphore)

#include "freertos/semphr.h"
 
// 二值信号量
SemaphoreHandle_t binary_sem = xSemaphoreCreateBinary();
 
// 互斥信号量
SemaphoreHandle_t mutex_sem = xSemaphoreCreateMutex();
 
// 获取
xSemaphoreTake(mutex_sem, portMAX_DELAY);
 
// 释放
xSemaphoreGive(mutex_sem);

事件组 (Event Group)

#include "freertos/event_groups.h"
 
#define WIFI_CONNECTED_BIT  (1 << 0)
#define MQTT_CONNECTED_BIT  (1 << 1)
 
EventGroupHandle_t event_group = xEventGroupCreate();
 
// 设置事件
xEventGroupSetBits(event_group, WIFI_CONNECTED_BIT);
 
// 等待事件
EventBits_t bits = xEventGroupWaitBits(
    event_group,
    WIFI_CONNECTED_BIT | MQTT_CONNECTED_BIT,
    pdTRUE,        // 清除已设置位
    pdTRUE,        // 等待所有位
    portMAX_DELAY
);

定时器

软件定时器

#include "freertos/timers.h"
 
TimerHandle_t timer_handle;
 
void timer_callback(TimerHandle_t xTimer)
{
    printf("Timer triggered!\n");
}
 
void app_main(void)
{
    timer_handle = xTimerCreate(
        "MyTimer",           // 名称
        pdMS_TO_TICKS(1000), // 周期 1秒
        pdTRUE,              // 自动重载
        (void *)0,           // 定时器ID
        timer_callback       // 回调
    );
 
    xTimerStart(timer_handle, 0);
}

内存管理

堆内存

#include "esp_heap_caps.h"
 
// 通用内存分配
void *ptr = malloc(1024);
free(ptr);
 
// 带特定属性分配 (DRAM)
void *ptr = heap_caps_malloc(1024, MALLOC_CAP_8BIT);
 
// 带特定属性分配 (DMA)
void *ptr = heap_caps_malloc(1024, MALLOC_CAP_DMA);
 
// 获取可用内存
size_t free_heap = esp_get_free_heap_size();
size_t min_free = esp_get_minimum_free_heap_size();

静态分配

// 静态任务内存
static StaticTask_t task_buffer;
static StackType_t task_stack[4096];
 
void app_main(void)
{
    xTaskCreateStatic(
        task_function,
        "StaticTask",
        4096,
        NULL,
        1,
        task_stack,
        &task_buffer
    );
}

双核执行

核心绑定

// 在 Core 0 上运行
xTaskCreatePinnedToCore(
    task_function,
    "TaskCore0",
    4096,
    NULL,
    1,
    NULL,
    0  // Core 0
);
 
// 在 Core 1 上运行
xTaskCreatePinnedToCore(
    task_function,
    "TaskCore1",
    4096,
    NULL,
    1,
    NULL,
    1  // Core 1
);

任务亲和性

┌─────────────────┬─────────────────┐
│     Core 0      │     Core 1      │
├─────────────────┼─────────────────┤
│ WiFi 处理任务   │ 传感器采集任务  │
│ 网络协议栈      │ 数据处理任务    │
│ 系统任务        │ 用户交互任务    │
└─────────────────┴─────────────────┘

临界区

// 方法1: 禁用中断
taskENTER_CRITICAL();
// 临界代码
taskEXIT_CRITICAL();
 
// 方法2: 任务临界区 (带端口)
taskENTER_CRITICAL(&mux);
...
taskEXIT_CRITICAL(&mux);
 
// 方法3: 锁调度器
vTaskSuspendAll();
// 临界代码
xTaskResumeAll();

参考资料

官方文档

核心调度

图片参考

FreeRTOS 任务状态转换


相关链接

反向链接

进阶学习


下一步