Chenyj Space
返回博客
·33 分钟

嵌入式实时操作系统(RTOS):FreeRTOS 入门与实战

嵌入式RTOSFreeRTOS任务管理实时系统嵌入式

实时操作系统概述

实时操作系统(RTOS)是一种专门为实时应用设计的操作系统,能够在确定的时间内响应外部事件。

1. RTOS 特性

code
RTOS 核心特性:

1. 实时性
   - 确定性响应时间
   - 可预测的任务调度
   - 严格的时间约束

2. 多任务管理
   - 任务调度
   - 任务间通信
   - 资源管理

3. 可靠性
   - 错误处理
   - 内存保护
   - 看门狗机制

2. 常见 RTOS 对比

RTOS特点许可证典型应用
FreeRTOS免费、小巧、易用MITIoT、消费电子
RT-Thread国产、组件丰富Apache工业、IoT
uC/OS-II商业、稳定商业工业、医疗
VxWorks商业、高性能商业航空、军事
QNX商业、微内核商业汽车、医疗

3. FreeRTOS 优势

code
FreeRTOS 优势:

1. 免费开源
   - MIT 许可证
   - 无商业限制
   - 源码开放

2. 小巧高效
   - 内核 6-9KB
   - 低 RAM 占用
   - 高效调度

3. 移植性好
   - 支持 40+ 处理器架构
   - 简单移植接口
   - 丰富示例

4. 生态完善
   - 丰富组件
   - 社区活跃
   - 文档齐全

FreeRTOS 核心概念

1. 任务(Task)

c
// 任务创建
void vTaskFunction(void *pvParameters) {
    // 任务参数
    char *pcTaskName = (char *)pvParameters;
    
    // 任务主循环
    for(;;) {
        // 任务逻辑
        printf("%s is running\n", pcTaskName);
        
        // 延时
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

// 创建任务
xTaskCreate(
    vTaskFunction,      // 任务函数
    "Task1",            // 任务名称
    configMINIMAL_STACK_SIZE,  // 栈大小
    (void *)"Task 1",   // 任务参数
    tskIDLE_PRIORITY + 1,  // 优先级
    NULL                // 任务句柄
);

2. 任务状态

code
任务状态转换:

┌─────────┐    创建    ┌─────────┐
│  就绪   │◄──────────│  创建   │
│ (Ready) │           │(Created)│
└────┬────┘           └─────────┘
     │
     │ 调度器选择
     ↓
┌─────────┐    延时    ┌─────────┐
│  运行   │──────────►│  阻塞   │
│(Running)│           │(Blocked)│
└────┬────┘           └────┬────┘
     │                     │
     │ 被抢占              │ 延时结束
     ↓                     ↓
┌─────────┐           ┌─────────┐
│  就绪   │◄──────────│  就绪   │
│ (Ready) │           │ (Ready) │
└─────────┘           └─────────┘

3. 任务优先级

c
// 优先级定义
#define configMAX_PRIORITIES  5

// 优先级分配
// 0: 空闲任务
// 1: 低优先级任务
// 2: 中优先级任务
// 3: 高优先级任务
// 4: 最高优先级任务

// 创建不同优先级的任务
xTaskCreate(vTaskIdle, "Idle", 128, NULL, 0, NULL);
xTaskCreate(vTaskLow, "Low", 128, NULL, 1, NULL);
xTaskCreate(vTaskMedium, "Medium", 128, NULL, 2, NULL);
xTaskCreate(vTaskHigh, "High", 128, NULL, 3, NULL);

任务调度

1. 调度策略

c
// 配置调度策略
// 1. 抢占式调度(默认)
#define configUSE_PREEMPTION  1

// 2. 时间片轮转
#define configUSE_TIME_SLICING  1

// 3. 时间片长度
#define configTICK_RATE_HZ  1000  // 1ms

2. 任务切换

c
// 手动让出 CPU
void vTaskDelay(TickType_t xTicksToDelay);

// 延时到指定时间
void vTaskDelayUntil(TickType_t *pxPreviousWakeTime, TickType_t xTimeIncrement);

// 主动让出 CPU
taskYIELD();

// 示例:周期性任务
void vPeriodicTask(void *pvParameters) {
    TickType_t xLastWakeTime;
    const TickType_t xPeriod = pdMS_TO_TICKS(100);
    
    // 初始化上次唤醒时间
    xLastWakeTime = xTaskGetTickCount();
    
    for(;;) {
        // 执行任务
        vDoSomething();
        
        // 等待下一个周期
        vTaskDelayUntil(&xLastWakeTime, xPeriod);
    }
}

任务间通信

1. 队列(Queue)

c
// 创建队列
QueueHandle_t xQueue = xQueueCreate(10, sizeof(uint32_t));

// 发送数据到队列
void vProducerTask(void *pvParameters) {
    uint32_t ulValue = 0;
    
    for(;;) {
        // 发送数据
        if(xQueueSend(xQueue, &ulValue, portMAX_DELAY) == pdPASS) {
            printf("Sent: %lu\n", ulValue);
            ulValue++;
        }
        
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

// 从队列接收数据
void vConsumerTask(void *pvParameters) {
    uint32_t ulReceivedValue;
    
    for(;;) {
        // 接收数据
        if(xQueueReceive(xQueue, &ulReceivedValue, portMAX_DELAY) == pdPASS) {
            printf("Received: %lu\n", ulReceivedValue);
        }
    }
}

2. 信号量(Semaphore)

c
// 创建二进制信号量
SemaphoreHandle_t xSemaphore = xSemaphoreCreateBinary();

// 释放信号量
void vISR_Handler(void) {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    // 释放信号量
    xSemaphoreGiveFromISR(xSemaphore, &xHigherPriorityTaskWoken);
    
    // 如果需要,进行上下文切换
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

// 获取信号量
void vTaskHandler(void *pvParameters) {
    for(;;) {
        // 等待信号量
        if(xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) {
            // 处理事件
            vHandleEvent();
        }
    }
}

3. 互斥量(Mutex)

c
// 创建互斥量
SemaphoreHandle_t xMutex = xSemaphoreCreateMutex();

// 共享资源
volatile uint32_t ulSharedCounter = 0;

// 任务 1 访问共享资源
void vTask1(void *pvParameters) {
    for(;;) {
        // 获取互斥量
        if(xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
            // 访问共享资源
            ulSharedCounter++;
            printf("Task1: Counter = %lu\n", ulSharedCounter);
            
            // 释放互斥量
            xSemaphoreGive(xMutex);
        }
        
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

// 任务 2 访问共享资源
void vTask2(void *pvParameters) {
    for(;;) {
        // 获取互斥量
        if(xSemaphoreTake(xMutex, portMAX_DELAY) == pdTRUE) {
            // 访问共享资源
            ulSharedCounter += 2;
            printf("Task2: Counter = %lu\n", ulSharedCounter);
            
            // 释放互斥量
            xSemaphoreGive(xMutex);
        }
        
        vTaskDelay(pdMS_TO_TICKS(1500));
    }
}

4. 事件组(Event Group)

c
// 创建事件组
EventGroupHandle_t xEventGroup = xEventGroupCreate();

// 事件位定义
#define EVENT_SENSOR_READY  (1 << 0)
#define EVENT_NETWORK_OK    (1 << 1)
#define EVENT_DATA_READY    (1 << 2)

// 设置事件
void vSensorTask(void *pvParameters) {
    for(;;) {
        // 读取传感器
        vReadSensor();
        
        // 设置事件
        xEventGroupSetBits(xEventGroup, EVENT_SENSOR_READY);
        
        vTaskDelay(pdMS_TO_TICKS(100));
    }
}

// 等待事件
void vProcessingTask(void *pvParameters) {
    EventBits_t uxBits;
    
    for(;;) {
        // 等待所有事件
        uxBits = xEventGroupWaitBits(
            xEventGroup,
            EVENT_SENSOR_READY | EVENT_NETWORK_OK,
            pdTRUE,  // 清除事件
            pdTRUE,  // 等待所有
            portMAX_DELAY
        );
        
        // 处理数据
        vProcessData();
    }
}

软件定时器

1. 定时器创建

c
// 定时器回调函数
void vTimerCallback(TimerHandle_t xTimer) {
    printf("Timer expired\n");
    
    // 获取定时器 ID
    uint32_t ulTimerID = (uint32_t)pvTimerGetTimerID(xTimer);
    printf("Timer ID: %lu\n", ulTimerID);
}

// 创建定时器
TimerHandle_t xTimer = xTimerCreate(
    "Timer1",                    // 定时器名称
    pdMS_TO_TICKS(1000),        // 周期
    pdTRUE,                     // 自动重载
    (void *)0,                  // 定时器 ID
    vTimerCallback              // 回调函数
);

// 启动定时器
xTimerStart(xTimer, 0);

// 停止定时器
xTimerStop(xTimer, 0);

// 改变定时器周期
xTimerChangePeriod(xTimer, pdMS_TO_TICKS(2000), 0);

内存管理

1. 动态内存分配

c
// 创建任务(动态分配)
xTaskCreate(
    vTaskFunction,
    "Task1",
    configMINIMAL_STACK_SIZE,
    NULL,
    tskIDLE_PRIORITY + 1,
    NULL
);

// 创建队列(动态分配)
QueueHandle_t xQueue = xQueueCreate(10, sizeof(uint32_t));

// 创建信号量(动态分配)
SemaphoreHandle_t xSemaphore = xSemaphoreCreateBinary();

2. 静态内存分配

c
// 静态任务创建
StaticTask_t xTaskBuffer;
StackType_t xStack[configMINIMAL_STACK_SIZE];

TaskHandle_t xTask = xTaskCreateStatic(
    vTaskFunction,
    "Task1",
    configMINIMAL_STACK_SIZE,
    NULL,
    tskIDLE_PRIORITY + 1,
    xStack,
    &xTaskBuffer
);

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

QueueHandle_t xQueue = xQueueCreateStatic(
    10,
    sizeof(uint32_t),
    ucQueueStorage,
    &xQueueBuffer
);

3. 内存池

c
// 内存池定义
#define POOL_BLOCK_SIZE  32
#define POOL_BLOCK_COUNT 10

static uint8_t ucMemoryPool[POOL_BLOCK_SIZE * POOL_BLOCK_COUNT];
static uint8_t ucPoolBitmap[POOL_BLOCK_COUNT / 8];

// 内存池分配
void* pvPoolAlloc(void) {
    for(int i = 0; i < POOL_BLOCK_COUNT; i++) {
        int byte_idx = i / 8;
        int bit_idx = i % 8;
        
        if(!(ucPoolBitmap[byte_idx] & (1 << bit_idx))) {
            ucPoolBitmap[byte_idx] |= (1 << bit_idx);
            return &ucMemoryPool[i * POOL_BLOCK_SIZE];
        }
    }
    return NULL;
}

// 内存池释放
void vPoolFree(void *pvBlock) {
    if(pvBlock == NULL) return;
    
    uint32_t ulOffset = (uint8_t*)pvBlock - ucMemoryPool;
    int block_idx = ulOffset / POOL_BLOCK_SIZE;
    
    int byte_idx = block_idx / 8;
    int bit_idx = block_idx % 8;
    
    ucPoolBitmap[byte_idx] &= ~(1 << bit_idx);
}

实际应用示例

1. 多任务系统设计

c
// 系统任务定义
void vSensorTask(void *pvParameters);
void vDisplayTask(void *pvParameters);
void vNetworkTask(void *pvParameters);
void vControlTask(void *pvParameters);

// 系统初始化
void vSystemInit(void) {
    // 创建队列
    QueueHandle_t xSensorQueue = xQueueCreate(10, sizeof(SensorData_t));
    QueueHandle_t xDisplayQueue = xQueueCreate(5, sizeof(DisplayData_t));
    
    // 创建信号量
    SemaphoreHandle_t xNetworkSemaphore = xSemaphoreCreateBinary();
    
    // 创建任务
    xTaskCreate(vSensorTask, "Sensor", 256, xSensorQueue, 3, NULL);
    xTaskCreate(vDisplayTask, "Display", 256, xDisplayQueue, 2, NULL);
    xTaskCreate(vNetworkTask, "Network", 512, xNetworkSemaphore, 1, NULL);
    xTaskCreate(vControlTask, "Control", 256, NULL, 4, NULL);
    
    // 启动调度器
    vTaskStartScheduler();
}

// 传感器任务
void vSensorTask(void *pvParameters) {
    QueueHandle_t xQueue = (QueueHandle_t)pvParameters;
    SensorData_t xData;
    
    for(;;) {
        // 读取传感器
        xData.temperature = fReadTemperature();
        xData.humidity = fReadHumidity();
        xData.timestamp = xTaskGetTickCount();
        
        // 发送到队列
        xQueueSend(xQueue, &xData, portMAX_DELAY);
        
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

2. 中断处理

c
// 中断服务函数
void USART1_IRQHandler(void) {
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;
    
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
        uint8_t data = USART_ReceiveData(USART1);
        
        // 发送到队列
        xQueueSendFromISR(xUartQueue, &data, &xHigherPriorityTaskWoken);
        
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
    
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

// UART 处理任务
void vUartTask(void *pvParameters) {
    uint8_t data;
    
    for(;;) {
        // 从队列接收数据
        if(xQueueReceive(xUartQueue, &data, portMAX_DELAY) == pdPASS) {
            // 处理数据
            vProcessUartData(data);
        }
    }
}

3. 低功耗设计

c
// 空闲任务钩子函数
void vApplicationIdleHook(void) {
    // 进入低功耗模式
    __WFI();
}

// 配置空闲任务钩子
#define configUSE_IDLE_HOOK  1

// 低功耗任务设计
void vLowPowerTask(void *pvParameters) {
    for(;;) {
        // 执行任务
        vDoWork();
        
        // 长时间延时
        vTaskDelay(pdMS_TO_TICKS(10000));
    }
}

调试与优化

1. 任务状态监控

c
// 获取任务状态
TaskStatus_t xTaskStatus;
vTaskGetInfo(xTaskHandle, &xTaskStatus, pdTRUE, eInvalid);

printf("Task: %s\n", xTaskStatus.pcTaskName);
printf("State: %d\n", xTaskStatus.eCurrentState);
printf("Priority: %lu\n", xTaskStatus.uxCurrentPriority);
printf("Stack High Water Mark: %lu\n", xTaskStatus.usStackHighWaterMark);

// 获取系统状态
UBaseType_t uxTaskCount = uxTaskGetNumberOfTasks();
printf("Number of tasks: %lu\n", uxTaskCount);

2. 栈溢出检测

c
// 配置栈溢出检测
#define configCHECK_FOR_STACK_OVERFLOW  2

// 栈溢出钩子函数
void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) {
    // 栈溢出处理
    printf("Stack overflow in task: %s\n", pcTaskName);
    
    // 停止系统
    for(;;);
}

3. 性能分析

c
// 配置运行时间统计
#define configGENERATE_RUN_TIME_STATS  1
#define configUSE_TRACE_FACILITY  1
#define configUSE_STATS_FORMATTING_FUNCTIONS  1

// 获取运行时间统计
char *pcStatsBuffer = pvPortMalloc(1024);
vTaskList(pcStatsBuffer);
printf("Task List:\n%s\n", pcStatsBuffer);

vTaskGetRunTimeStats(pcStatsBuffer);
printf("Run Time Stats:\n%s\n", pcStatsBuffer);
vPortFree(pcStatsBuffer);

总结

通过本系列博客,我们深入学习了嵌入式系统的核心知识:

  1. 嵌入式系统基础:MCU 架构、开发环境、GPIO、中断、定时器、串口
  2. C 语言编程技巧:位操作、内存管理、代码优化、调试技巧
  3. ARM Cortex-M 架构:中断系统、低功耗模式、系统启动、调试接口
  4. 通信协议:UART、I2C、SPI、CAN 的原理和实现
  5. 实时操作系统:FreeRTOS 的任务管理、同步机制、内存管理

这些知识是嵌入式开发的基础,掌握它们将为后续的项目开发打下坚实的基础。