打印
[经验分享]

FreeRTOS任务管理与调度

[复制链接]
57|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-11-1 16:19 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
任务管理基础
在嵌入式系统中,任务管理是操作系统的核心功能之一。FreeRTOS作为一个轻量级的实时操作系统,提供了丰富的任务管理功能,使得多任务处理变得简单高效。任务管理包括任务的创建、删除、挂起、恢复、优先级设置等操作。在FreeRTOS中,每个任务都有自己的任务控制块(TCB),用于存储任务的状态、优先级、堆栈等信息。

任务控制块(TCB)
任务控制块(Task Control Block, TCB)是FreeRTOS中用于管理任务的数据结构。每个任务在创建时都会分配一个TCB,TCB中包含了任务的所有管理信息,如任务状态、优先级、堆栈指针等。以下是一个TCB的简化结构示例:

// 简化的TCB结构示例
typedef struct TCB {
    char *pcTaskName;          // 任务名称
    UBaseType_t uxPriority;    // 任务优先级
    StackType_t *pxStack;      // 任务堆栈指针
    configSTACK_DEPTH_TYPE usStackDepth; // 任务堆栈深度
    ListItem_t xStateItem;     // 任务状态列表项
    ListItem_t xEventListItem; // 任务事件列表项
    TickType_t xBlockTime;     // 任务阻塞时间
    // 其他管理信息
} TCB_t;


任务创建
在FreeRTOS中,任务的创建通过xTaskCreate函数实现。该函数需要提供任务的入口函数、任务名称、堆栈深度、任务参数、任务优先级以及一个指向任务句柄的指针。以下是一个创建任务的示例:

// 任务入口函数
void vTaskFunction(void *pvParameters) {
    // 任务名称
    char *pcTaskName = (char *)pvParameters;

    while (1) {
        // 任务主体代码
        printf("Task %s running\n", pcTaskName);
        vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1000毫秒
    }
}

// 主函数
int main(void) {
    // 创建任务
    TaskHandle_t xHandle;
    xTaskCreate(vTaskFunction, "Task 1", configMINIMAL_STACK_SIZE, (void *)"Task 1", 1, &xHandle);

    // 启动调度器
    vTaskStartScheduler();

    // 应该不会到达这里
    for (;;);
}



任务删除
任务的删除通过vTaskDelete函数实现。该函数会释放任务的堆栈和其他资源,并将任务从任务列表中移除。以下是一个删除任务的示例:

// 任务入口函数
void vTaskFunction(void *pvParameters) {
    // 任务名称
    char *pcTaskName = (char *)pvParameters;

    while (1) {
        // 任务主体代码
        printf("Task %s running\n", pcTaskName);
        vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1000毫秒

        // 删除任务
        vTaskDelete(NULL);
    }
}

// 主函数
int main(void) {
    // 创建任务
    TaskHandle_t xHandle;
    xTaskCreate(vTaskFunction, "Task 1", configMINIMAL_STACK_SIZE, (void *)"Task 1", 1, &xHandle);

    // 启动调度器
    vTaskStartScheduler();

    // 应该不会到达这里
    for (;;);
}



任务挂起与恢复
任务可以被挂起(暂停)或恢复。挂起任务通过vTaskSuspend函数实现,恢复任务通过vTaskResume函数实现。以下是一个挂起和恢复任务的示例:

// 任务入口函数
void vTaskFunction(void *pvParameters) {
    // 任务名称
    char *pcTaskName = (char *)pvParameters;

    while (1) {
        // 任务主体代码
        printf("Task %s running\n", pcTaskName);
        vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1000毫秒
    }
}

// 主函数
int main(void) {
    // 创建任务
    TaskHandle_t xHandle;
    xTaskCreate(vTaskFunction, "Task 1", configMINIMAL_STACK_SIZE, (void *)"Task 1", 1, &xHandle);

    // 启动调度器
    vTaskStartScheduler();

    // 挂起任务
    vTaskSuspend(xHandle);

    // 延迟10秒后恢复任务
    vTaskDelay(pdMS_TO_TICKS(10000));
    vTaskResume(xHandle);

    // 应该不会到达这里
    for (;;);
}



任务调度机制
FreeRTOS的任务调度机制是基于优先级的抢占式调度。每个任务都有一个优先级,调度器会根据优先级选择最高优先级的就绪任务来执行。如果多个任务具有相同的优先级,调度器会使用时间片轮转机制来调度这些任务。

优先级调度
优先级调度是FreeRTOS中最基本的调度机制。每个任务在创建时都会指定一个优先级,优先级越高的任务越先被调度执行。FreeRTOS支持的任务优先级范围通常从0到(configMAX_PRIORITIES - 1),其中0是最低优先级。

以下是一个优先级调度的示例:

// 任务1入口函数
void vTask1Function(void *pvParameters) {
    while (1) {
        printf("Task 1 running\n");
        vTaskDelay(pdMS_TO_TICKS(500)); // 延迟500毫秒
    }
}

// 任务2入口函数
void vTask2Function(void *pvParameters) {
    while (1) {
        printf("Task 2 running\n");
        vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1000毫秒
    }
}

// 主函数
int main(void) {
    // 创建任务1,优先级为1
    TaskHandle_t xTask1Handle;
    xTaskCreate(vTask1Function, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle);

    // 创建任务2,优先级为2
    TaskHandle_t xTask2Handle;
    xTaskCreate(vTask2Function, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, &xTask2Handle);

    // 启动调度器
    vTaskStartScheduler();

    // 应该不会到达这里
    for (;;);
}



在这个示例中,任务2的优先级高于任务1,因此任务2会优先执行。

时间片轮转
当多个任务具有相同的优先级时,FreeRTOS会使用时间片轮转机制来调度这些任务。每个任务在运行一定时间后会被挂起,调度器会选择下一个就绪的任务来执行。时间片的长度可以通过configTICK_RATE_HZ配置。

以下是一个时间片轮转的示例:

// 任务1入口函数
void vTask1Function(void *pvParameters) {
    while (1) {
        printf("Task 1 running\n");
        vTaskDelay(pdMS_TO_TICKS(500)); // 延迟500毫秒
    }
}

// 任务2入口函数
void vTask2Function(void *pvParameters) {
    while (1) {
        printf("Task 2 running\n");
        vTaskDelay(pdMS_TO_TICKS(500)); // 延迟500毫秒
    }
}

// 主函数
int main(void) {
    // 创建任务1,优先级为1
    TaskHandle_t xTask1Handle;
    xTaskCreate(vTask1Function, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle);

    // 创建任务2,优先级为1
    TaskHandle_t xTask2Handle;
    xTaskCreate(vTask2Function, "Task 2", configMINIMAL_STACK_SIZE, NULL, 1, &xTask2Handle);

    // 启动调度器
    vTaskStartScheduler();

    // 应该不会到达这里
    for (;;);
}



在这个示例中,任务1和任务2具有相同的优先级,因此调度器会使用时间片轮转机制来交替执行这两个任务。

任务优先级的动态调整
FreeRTOS允许在运行时动态调整任务的优先级。可以通过vTaskPrioritySet函数来设置任务的优先级。以下是一个动态调整任务优先级的示例:

// 任务1入口函数
void vTask1Function(void *pvParameters) {
    while (1) {
        printf("Task 1 running\n");
        vTaskDelay(pdMS_TO_TICKS(500)); // 延迟500毫秒
    }
}

// 任务2入口函数
void vTask2Function(void *pvParameters) {
    while (1) {
        printf("Task 2 running\n");
        vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1000毫秒

        // 动态提高任务1的优先级
        vTaskPrioritySet(xTask1Handle, 2);
    }
}

// 主函数
int main(void) {
    // 创建任务1,优先级为1
    TaskHandle_t xTask1Handle;
    xTaskCreate(vTask1Function, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle);

    // 创建任务2,优先级为2
    TaskHandle_t xTask2Handle;
    xTaskCreate(vTask2Function, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, &xTask2Handle);

    // 启动调度器
    vTaskStartScheduler();

    // 应该不会到达这里
    for (;;);
}



在这个示例中,任务2在运行时会动态提高任务1的优先级,使得任务1的优先级高于任务2,从而被优先调度执行。

任务间的同步与通信
在多任务系统中,任务间的同步与通信是非常重要的。FreeRTOS提供了多种机制来实现任务间的同步与通信,包括信号量、互斥量、事件组、消息队列等。

信号量
信号量用于实现任务间的同步。FreeRTOS提供了二值信号量和计数信号量两种类型。二值信号量通常用于任务间的互斥访问,计数信号量用于计数资源的使用情况。

二值信号量
以下是一个使用二值信号量的示例:

// 任务1入口函数
void vTask1Function(void *pvParameters) {
    while (1) {
        // 等待信号量
        xSemaphoreTake(xBinarySemaphore, portMAX_DELAY);

        // 任务主体代码
        printf("Task 1 running\n");
        vTaskDelay(pdMS_TO_TICKS(500)); // 延迟500毫秒

        // 释放信号量
        xSemaphoreGive(xBinarySemaphore);
    }
}

// 任务2入口函数
void vTask2Function(void *pvParameters) {
    while (1) {
        // 任务主体代码
        printf("Task 2 running\n");
        vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1000毫秒

        // 释放信号量
        xSemaphoreGive(xBinarySemaphore);
    }
}

// 主函数
int main(void) {
    // 创建二值信号量
    xBinarySemaphore = xSemaphoreCreateBinary();

    // 创建任务1
    TaskHandle_t xTask1Handle;
    xTaskCreate(vTask1Function, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle);

    // 创建任务2
    TaskHandle_t xTask2Handle;
    xTaskCreate(vTask2Function, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, &xTask2Handle);

    // 启动调度器
    vTaskStartScheduler();

    // 应该不会到达这里
    for (;;);
}



在这个示例中,任务1和任务2通过二值信号量来同步。任务1在获取信号量后执行,任务2在释放信号量后任务1继续执行。

计数信号量
以下是一个使用计数信号量的示例:

// 任务1入口函数
void vTask1Function(void *pvParameters) {
    while (1) {
        // 等待信号量
        xSemaphoreTake(xCountingSemaphore, portMAX_DELAY);

        // 任务主体代码
        printf("Task 1 running\n");
        vTaskDelay(pdMS_TO_TICKS(500)); // 延迟500毫秒
    }
}

// 任务2入口函数
void vTask2Function(void *pvParameters) {
    while (1) {
        // 任务主体代码
        printf("Task 2 running\n");
        vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1000毫秒

        // 释放信号量
        xSemaphoreGive(xCountingSemaphore);
    }
}

// 主函数
int main(void) {
    // 创建计数信号量,初始值为0,最大值为1
    xCountingSemaphore = xSemaphoreCreateCounting(1, 0);

    // 创建任务1
    TaskHandle_t xTask1Handle;
    xTaskCreate(vTask1Function, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle);

    // 创建任务2
    TaskHandle_t xTask2Handle;
    xTaskCreate(vTask2Function, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, &xTask2Handle);

    // 启动调度器
    vTaskStartScheduler();

    // 应该不会到达这里
    for (;;);
}



在这个示例中,任务1在获取计数信号量后执行,任务2在释放计数信号量后任务1继续执行。

互斥量
互斥量用于保护共享资源,防止多个任务同时访问。以下是一个使用互斥量的示例:

// 任务1入口函数
void vTask1Function(void *pvParameters) {
    while (1) {
        // 获取互斥量
        xSemaphoreTake(xMutex, portMAX_DELAY);

        // 任务主体代码
        printf("Task 1 running\n");
        vTaskDelay(pdMS_TO_TICKS(500)); // 延迟500毫秒

        // 释放互斥量
        xSemaphoreGive(xMutex);
    }
}

// 任务2入口函数
void vTask2Function(void *pvParameters) {
    while (1) {
        // 获取互斥量
        xSemaphoreTake(xMutex, portMAX_DELAY);

        // 任务主体代码
        printf("Task 2 running\n");
        vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1000毫秒

        // 释放互斥量
        xSemaphoreGive(xMutex);
    }
}

// 主函数
int main(void) {
    // 创建互斥量
    xMutex = xSemaphoreCreateMutex();

    // 创建任务1
    TaskHandle_t xTask1Handle;
    xTaskCreate(vTask1Function, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle);

    // 创建任务2
    TaskHandle_t xTask2Handle;
    xTaskCreate(vTask2Function, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, &xTask2Handle);

    // 启动调度器
    vTaskStartScheduler();

    // 应该不会到达这里
    for (;;);
}



在这个示例中,任务1和任务2通过互斥量来保护共享资源,确保同一时间只有一个任务在访问资源。

事件组
事件组用于实现任务之间的复杂同步机制。每个事件组可以包含多个事件位,任务可以通过设置或清除这些事件位来进行同步。以下是一个使用事件组的示例:

// 任务1入口函数
void vTask1Function(void *pvParameters) {
    while (1) {
        // 等待事件组中的某个事件
        EventBits_t uxBits = xEventGroupWaitBits(
            xEventGroup,       // 事件组句柄
            0x01,              // 等待的事件位
            pdTRUE,            // 清除事件位
            pdFALSE,           // 仅等待指定的事件位
            portMAX_DELAY      // 等待时间
        );

        // 任务主体代码
        printf("Task 1 running\n");
        vTaskDelay(pdMS_TO_TICKS(500)); // 延迟500毫秒
    }
}

// 任务2入口函数
void vTask2Function(void *pvParameters) {
    while (1) {
        // 任务主体代码
        printf("Task 2 running\n");
        vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1000毫秒

        // 设置事件组中的某个事件
        xEventGroupSetBits(xEventGroup, 0x01);
    }
}

// 主函数
int main(void) {
    // 创建事件组
    xEventGroup = xEventGroupCreate();

    // 创建任务1
    TaskHandle_t xTask1Handle;
    xTaskCreate(vTask1Function, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle);

    // 创建任务2
    TaskHandle_t xTask2Handle;
    xTaskCreate(vTask2Function, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, &xTask2Handle);

    // 启动调度器
    vTaskStartScheduler();

    // 应该不会到达这里
    for (;;);
}



在这个示例中,任务1在等待事件组中的某个事件位被设置后执行,任务2在运行时设置事件组中的某个事件位。

消息队列
消息队列用于任务间的通信。任务可以通过消息队列发送和接收消息。以下是一个使用消息队列的示例:

// 任务1入口函数
void vTask1Function(void *pvParameters) {
    while (1) {
        // 发送消息到队列
        int message = 1;
        xQueueSend(xQueue, &message, portMAX_DELAY);

        // 任务主体代码
        printf("Task 1 running, sent message: %d\n", message);
        vTaskDelay(pdMS_TO_TICKS(500)); // 延迟500毫秒
    }
}

// 任务2入口函数
void vTask2Function(void *pvParameters) {
    while (1) {
        // 从队列接收消息
        int message;
        if (xQueueReceive(xQueue, &message, portMAX_DELAY)) {
            // 任务主体代码
            printf("Task 2 running, received message: %d\n", message);
        }

        vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1000毫秒
    }
}

// 主函数
int main(void) {
    // 创建消息队列,队列长度为10,每个消息的大小为4字节
    xQueue = xQueueCreate(10, sizeof(int));

    // 创建任务1
    TaskHandle_t xTask1Handle;
    xTaskCreate(vTask1Function, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle);

    // 创建任务2
    TaskHandle_t xTask2Handle;
    xTaskCreate(vTask2Function, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, &xTask2Handle);

    // 启动调度器
    vTaskStartScheduler();

    // 应该不会到达这里
    for (;;);
}



在这个示例中,任务1通过消息队列发送消息,任务2从消息队列接收消息。任务1和任务2通过消息队列进行通信,确保任务2在接收到消息后执行相应的操作。

任务调度与调度器配置
FreeRTOS的调度器负责管理任务的执行顺序和时间。调度器的配置可以通过修改FreeRTOSConfig.h文件中的宏定义来实现。以下是一些重要的配置选项:

配置选项
configMAX_PRIORITIES: 定义系统支持的最大优先级数。默认值为5,可以根据需要调整。
configTICK_RATE_HZ: 定义系统时钟的频率,单位为Hz。例如,设置为1000表示每秒1000个时钟滴答。
configMINIMAL_STACK_SIZE: 定义系统中最小的堆栈大小。不同平台和任务的需求可能不同,可以根据实际情况调整。
configUSE_PREEMPTION: 启用或禁用抢占式调度。启用抢占式调度可以提高系统的实时性。
调度器启动与运行
调度器通过vTaskStartScheduler函数启动。启动后,调度器会根据任务的优先级和状态来调度任务。调度器的运行依赖于系统时钟中断,通过时钟中断来触发任务的切换。

// 主函数
int main(void) {
    // 创建任务1
    TaskHandle_t xTask1Handle;
    xTaskCreate(vTask1Function, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle);

    // 创建任务2
    TaskHandle_t xTask2Handle;
    xTaskCreate(vTask2Function, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, &xTask2Handle);

    // 启动调度器
    vTaskStartScheduler();

    // 如果调度器启动失败,会到达这里
    for (;;);
}



调度器的停止
在某些情况下,可能需要停止调度器。可以通过vTaskEndScheduler函数来停止调度器。需要注意的是,停止调度器后,系统将不再调度任何任务,所有任务都会停止执行。

// 任务1入口函数
void vTask1Function(void *pvParameters) {
    while (1) {
        // 任务主体代码
        printf("Task 1 running\n");
        vTaskDelay(pdMS_TO_TICKS(500)); // 延迟500毫秒

        // 停止调度器
        vTaskEndScheduler();
    }
}

// 任务2入口函数
void vTask2Function(void *pvParameters) {
    while (1) {
        // 任务主体代码
        printf("Task 2 running\n");
        vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1000毫秒
    }
}

// 主函数
int main(void) {
    // 创建任务1
    TaskHandle_t xTask1Handle;
    xTaskCreate(vTask1Function, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle);

    // 创建任务2
    TaskHandle_t xTask2Handle;
    xTaskCreate(vTask2Function, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, &xTask2Handle);

    // 启动调度器
    vTaskStartScheduler();

    // 应该不会到达这里
    for (;;);
}



在这个示例中,任务1在运行一段时间后会调用vTaskEndScheduler函数来停止调度器,所有任务将不再执行。

任务调度的性能优化
为了提高系统的实时性和性能,FreeRTOS提供了一些优化机制和技巧。以下是一些常见的性能优化方法:

优先级继承
优先级继承是一种防止优先级反转的机制。当一个低优先级任务持有互斥量,而高优先级任务需要访问该互斥量时,低优先级任务的优先级会被临时提高到高优先级任务的优先级,以加快互斥量的释放。

// 任务1入口函数
void vTask1Function(void *pvParameters) {
    while (1) {
        // 获取互斥量
        xSemaphoreTake(xMutex, portMAX_DELAY);

        // 任务主体代码
        printf("Task 1 running\n");
        vTaskDelay(pdMS_TO_TICKS(500)); // 延迟500毫秒

        // 释放互斥量
        xSemaphoreGive(xMutex);
    }
}

// 任务2入口函数
void vTask2Function(void *pvParameters) {
    while (1) {
        // 获取互斥量
        xSemaphoreTake(xMutex, portMAX_DELAY);

        // 任务主体代码
        printf("Task 2 running\n");
        vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1000毫秒

        // 释放互斥量
        xSemaphoreGive(xMutex);
    }
}

// 任务3入口函数
void vTask3Function(void *pvParameters) {
    while (1) {
        // 获取互斥量
        xSemaphoreTake(xMutex, portMAX_DELAY);

        // 任务主体代码
        printf("Task 3 running\n");
        vTaskDelay(pdMS_TO_TICKS(1500)); // 延迟1500毫秒

        // 释放互斥量
        xSemaphoreGive(xMutex);
    }
}

// 主函数
int main(void) {
    // 创建互斥量
    xMutex = xSemaphoreCreateMutex();

    // 创建任务1,优先级为1
    TaskHandle_t xTask1Handle;
    xTaskCreate(vTask1Function, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle);

    // 创建任务2,优先级为2
    TaskHandle_t xTask2Handle;
    xTaskCreate(vTask2Function, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, &xTask2Handle);

    // 创建任务3,优先级为3
    TaskHandle_t xTask3Handle;
    xTaskCreate(vTask3Function, "Task 3", configMINIMAL_STACK_SIZE, NULL, 3, &xTask3Handle);

    // 启动调度器
    vTaskStartScheduler();

    // 应该不会到达这里
    for (;;);
}





在这个示例中,任务3的优先级最高,任务1的优先级最低。当任务1持有互斥量,任务3需要访问该互斥量时,任务1的优先级会被临时提高到任务3的优先级,以加快互斥量的释放。

空闲任务和内存管理
FreeRTOS提供了一个空闲任务(Idle Task),它在没有其他任务可运行时执行。空闲任务通常用于处理系统空闲时的一些后台任务,如内存管理。FreeRTOS还支持动态内存分配和静态内存分配,可以根据系统的实际需求选择合适的内存管理方式。

动态内存分配
动态内存分配使用pvPortMalloc和vPortFree函数来分配和释放内存。动态内存分配提供了灵活性,但可能会导致内存碎片。

// 任务入口函数
void vTaskFunction(void *pvParameters) {
    while (1) {
        // 动态分配内存
        char *pcMessage = (char *)pvPortMalloc(100 * sizeof(char));
        if (pcMessage != NULL) {
            sprintf(pcMessage, "Task %s running", (char *)pvParameters);
            printf("%s\n", pcMessage);

            // 释放内存
            vPortFree(pcMessage);
        }

        vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1000毫秒
    }
}

// 主函数
int main(void) {
    // 创建任务
    TaskHandle_t xHandle;
    xTaskCreate(vTaskFunction, "Task 1", configMINIMAL_STACK_SIZE, (void *)"Task 1", 1, &xHandle);

    // 启动调度器
    vTaskStartScheduler();

    // 应该不会到达这里
    for (;;);
}



静态内存分配
静态内存分配使用预先分配的内存区域来创建任务。静态内存分配可以避免内存碎片,但需要在创建任务时提供内存区域。

// 任务入口函数
void vTaskFunction(void *pvParameters) {
    while (1) {
        // 任务主体代码
        printf("Task %s running\n", (char *)pvParameters);
        vTaskDelay(pdMS_TO_TICKS(1000)); // 延迟1000毫秒
    }
}

// 主函数
int main(void) {
    // 预先分配的任务堆栈和TCB
    StaticTask_t xTaskBuffer;
    StackType_t xStack[configMINIMAL_STACK_SIZE];

    // 创建任务
    TaskHandle_t xHandle = xTaskCreateStatic(
        vTaskFunction,          // 任务入口函数
        "Task 1",               // 任务名称
        configMINIMAL_STACK_SIZE, // 堆栈深度
        (void *)"Task 1",        // 任务参数
        1,                      // 任务优先级
        xStack,                  // 任务堆栈
        &xTaskBuffer             // 任务控制块
    );

    // 启动调度器
    vTaskStartScheduler();

    // 应该不会到达这里
    for (;;);
}



在这个示例中,任务1的堆栈和TCB是在创建任务时预先分配的,使用xTaskCreateStatic函数创建任务,可以避免动态内存分配带来的内存碎片问题。

总结
FreeRTOS的多任务管理与调度功能非常强大,提供了丰富的API来创建、删除、挂起、恢复任务,以及设置任务的优先级。通过使用信号量、互斥量、事件组和消息队列,可以实现任务间的同步与通信。合理配置调度器和优化内存管理方式,可以提高系统的实时性和性能。理解这些基本概念和机制,有助于开发高效、可靠的嵌入式实时系统。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_42749425/article/details/142647388

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1867

主题

15482

帖子

11

粉丝