·33 分钟
嵌入式实时操作系统(RTOS):FreeRTOS 入门与实战
嵌入式RTOSFreeRTOS任务管理实时系统嵌入式
实时操作系统概述
实时操作系统(RTOS)是一种专门为实时应用设计的操作系统,能够在确定的时间内响应外部事件。
1. RTOS 特性
code
RTOS 核心特性:
1. 实时性
- 确定性响应时间
- 可预测的任务调度
- 严格的时间约束
2. 多任务管理
- 任务调度
- 任务间通信
- 资源管理
3. 可靠性
- 错误处理
- 内存保护
- 看门狗机制
2. 常见 RTOS 对比
| RTOS | 特点 | 许可证 | 典型应用 |
|---|---|---|---|
| FreeRTOS | 免费、小巧、易用 | MIT | IoT、消费电子 |
| 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);
总结
通过本系列博客,我们深入学习了嵌入式系统的核心知识:
- 嵌入式系统基础:MCU 架构、开发环境、GPIO、中断、定时器、串口
- C 语言编程技巧:位操作、内存管理、代码优化、调试技巧
- ARM Cortex-M 架构:中断系统、低功耗模式、系统启动、调试接口
- 通信协议:UART、I2C、SPI、CAN 的原理和实现
- 实时操作系统:FreeRTOS 的任务管理、同步机制、内存管理
这些知识是嵌入式开发的基础,掌握它们将为后续的项目开发打下坚实的基础。