FreeRTOS任务管理:从入门到实践(标准库版)

引言

在嵌入式实时系统中,任务管理是操作系统的核心功能之一。FreeRTOS作为一款轻量级的实时操作系统,提供了灵活的任务创建、删除、挂起、恢复以及优先级调度机制。本文将以通俗易懂的方式讲解FreeRTOS任务管理的基本概念,并通过一个基于STM32标准外设库的完整示例,帮助读者快速上手。

一、什么是任务?

在FreeRTOS中,**任务(Task)**可以理解为一个独立执行的函数,它拥有自己的栈空间和优先级。每个任务在系统中无限循环执行,由调度器根据优先级和状态决定何时运行。

打个比方:任务就像工厂里的工人,每个工人负责不同的工作(函数),而调度器就是车间主任,负责安排工人的工作和休息。

二、任务的状态

FreeRTOS中的任务有四种主要状态:

  1. 运行态(Running):任务正在使用CPU执行。
  2. 就绪态(Ready):任务准备就绪,等待调度器分配CPU。
  3. 阻塞态(Blocked):任务等待某个事件(如延时、信号量),暂时不参与调度。
  4. 挂起态(Suspended):任务被主动挂起,不会被执行,除非被恢复。

三、任务管理API

FreeRTOS提供了丰富的任务管理函数,常用如下:

函数 功能
xTaskCreate() 创建任务
vTaskDelete() 删除任务
vTaskDelay() 延时(阻塞)
vTaskDelayUntil() 精确延时
vTaskSuspend() 挂起任务
vTaskResume() 恢复挂起的任务
uxTaskPriorityGet() 获取任务优先级
vTaskPrioritySet() 设置任务优先级

四、创建第一个任务

在FreeRTOS中,创建任务使用xTaskCreate()函数,其原型如下:

c 复制代码
BaseType_t xTaskCreate( TaskFunction_t pvTaskCode,
                        const char * const pcName,
                        configSTACK_DEPTH_TYPE usStackDepth,
                        void *pvParameters,
                        UBaseType_t uxPriority,
                        TaskHandle_t *pxCreatedTask );
  • pvTaskCode:任务函数指针。
  • pcName:任务名称(仅用于调试)。
  • usStackDepth:任务栈大小(单位:字,不是字节)。
  • pvParameters:传递给任务的参数。
  • uxPriority:任务优先级,数值越大优先级越高。
  • pxCreatedTask:任务句柄,用于后续操作。

示例:创建一个LED闪烁任务

c 复制代码
void LED_Task(void *pvParameters)
{
    while(1)
    {
        GPIO_SetBits(GPIOC, GPIO_Pin_13);   // LED熄灭
        vTaskDelay(500 / portTICK_PERIOD_MS);
        GPIO_ResetBits(GPIOC, GPIO_Pin_13); // LED点亮
        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
}

int main(void)
{
    // 初始化硬件
    LED_Init();
    
    // 创建任务
    xTaskCreate(LED_Task, "LED", 128, NULL, 2, NULL);
    
    // 启动调度器
    vTaskStartScheduler();
    
    while(1);
}

五、完整工程示例(基于STM32F103标准外设库)

下面给出一个完整的FreeRTOS任务管理示例,包含两个任务:LED闪烁任务和按键扫描任务,演示任务的创建、优先级、挂起与恢复。

5.1 硬件配置

  • 开发板:STM32F103C8T6
  • LED:PC13
  • 按键:PA0(按下为低电平)

5.2 工程文件结构

复制代码
- main.c
- FreeRTOSConfig.h
- stm32f10x_it.c (包含FreeRTOS中断处理)
- 其他标准外设库文件

5.3 代码实现

main.c
c 复制代码
#include "stm32f10x.h"
#include "FreeRTOS.h"
#include "task.h"

// 任务句柄
TaskHandle_t LED_Task_Handle = NULL;
TaskHandle_t KEY_Task_Handle = NULL;

// LED初始化
void LED_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    GPIO_SetBits(GPIOC, GPIO_Pin_13); // 初始熄灭
}

// 按键初始化
void KEY_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

// LED任务:每500ms翻转一次
void LED_Task(void *pvParameters)
{
    while(1)
    {
        GPIO_WriteBit(GPIOC, GPIO_Pin_13, 
                     (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOC, GPIO_Pin_13)));
        vTaskDelay(500 / portTICK_PERIOD_MS);
    }
}

// 按键任务:检测按键,按下时挂起/恢复LED任务
void KEY_Task(void *pvParameters)
{
    static uint8_t key_state = 0;
    while(1)
    {
        if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == Bit_RESET)
        {
            vTaskDelay(20 / portTICK_PERIOD_MS); // 消抖
            if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == Bit_RESET)
            {
                key_state = !key_state;
                if(key_state)
                {
                    vTaskSuspend(LED_Task_Handle); // 挂起LED任务
                }
                else
                {
                    vTaskResume(LED_Task_Handle);  // 恢复LED任务
                }
                while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == Bit_RESET); // 等待释放
            }
        }
        vTaskDelay(10 / portTICK_PERIOD_MS);
    }
}

int main(void)
{
    // 初始化硬件
    LED_Init();
    KEY_Init();
    
    // 创建LED任务,优先级2
    xTaskCreate(LED_Task, "LED_Task", 128, NULL, 2, &LED_Task_Handle);
    
    // 创建按键任务,优先级3(更高)
    xTaskCreate(KEY_Task, "KEY_Task", 256, NULL, 3, &KEY_Task_Handle);
    
    // 启动调度器
    vTaskStartScheduler();
    
    // 正常情况下不会执行到这里
    while(1);
}
FreeRTOSConfig.h 关键配置
c 复制代码
#define configUSE_PREEMPTION            1
#define configUSE_IDLE_HOOK             0
#define configUSE_TICK_HOOK             0
#define configCPU_CLOCK_HZ              ( ( unsigned long ) 72000000 )
#define configTICK_RATE_HZ              ( ( TickType_t ) 1000 )
#define configMAX_PRIORITIES            ( 5 )
#define configMINIMAL_STACK_SIZE        ( ( unsigned short ) 128 )
#define configTOTAL_HEAP_SIZE           ( ( size_t ) ( 17 * 1024 ) )
#define configMAX_TASK_NAME_LEN          ( 16 )
#define configUSE_TRACE_FACILITY        0
#define configUSE_16_BIT_TICKS          0
#define configIDLE_SHOULD_YIELD          1

5.4 中断服务函数修改(stm32f10x_it.c)

需要将SysTick、PendSV、SVC中断处理函数替换为FreeRTOS版本:

c 复制代码
#include "FreeRTOS.h"
#include "task.h"

void SysTick_Handler(void)
{
    if(xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED)
    {
        xPortSysTickHandler();
    }
}

void PendSV_Handler(void)
{
    xPortPendSVHandler();
}

void SVC_Handler(void)
{
    vPortSVCHandler();
}

六、任务管理进阶

6.1 删除任务

任务可以删除自己或其他任务(需谨慎):

c 复制代码
vTaskDelete(NULL);          // 删除自己
vTaskDelete(TaskHandle);    // 删除指定任务

6.2 修改优先级

c 复制代码
vTaskPrioritySet(TaskHandle, newPriority);
UBaseType_t prio = uxTaskPriorityGet(TaskHandle);

6.3 获取任务状态

c 复制代码
eTaskState state = eTaskGetState(TaskHandle);

七、总结

通过本文,我们了解了FreeRTOS任务的基本概念、状态和常用API,并通过一个完整的STM32标准外设库示例演示了任务的创建、挂起与恢复。任务管理是FreeRTOS的基础,掌握后可以进一步学习队列、信号量等内核对象。

实际开发中,合理划分任务、分配优先级和栈大小是保证系统稳定运行的关键。建议初学者多动手实践,观察任务切换现象,加深理解。


参考资料:


希望这篇博客对你有帮助!如果有疑问,欢迎评论区交流。

相关推荐
ye150127774557 小时前
12V转3V-5V2A电位器无极调光调速WT7027
stm32·单片机·嵌入式硬件
无损检测小白白9 小时前
STM32F407 串口3 DMA收发-标准库
stm32·单片机·嵌入式硬件
hsjiasb10 小时前
FreeRTOS学习(三十五)——系统架构综合项目
学习·学习笔记·freertos
深念Y10 小时前
JMS583 USB-NVMe 桥接芯片 LED 控制探索
嵌入式硬件·嵌入式·led·usb·电子·维修·硬盘盒
嵌入式阿蔡11 小时前
传感器_02:MPU6050 六轴 IMU 姿态入门——从一串看不懂的数,到一个不漂的角度
网络·stm32·单片机·嵌入式硬件·嵌入式实时数据库
江屿风12 小时前
【STM32基础篇】【嵌入式生态问题及历史追溯】流食般投喂
大数据·开发语言·人工智能·笔记·stm32·嵌入式硬件
橘色的喵13 小时前
USB MCU的固件烧写工具:从 vendor 命令到逐字节校验
单片机·嵌入式硬件·嵌入式
意法半导体STM3213 小时前
【官方原创】STM32CubeMX 6.18.0新版本发布
stm32·单片机·嵌入式硬件·stm32cubemx·cube开发工具
恒锐丰小瑞13 小时前
率能SS8833T 15V/1A/双通道H桥驱动芯片,低静态电流与过温报警输出(FAULT),用于POS打印机/机器人/电池玩具
stm32·单片机·机器人