什么是FreeRTOS的任务?
在FreeRTOS中,任务(Task)是系统中执行的基本单元。任务是一段具有独立执行流的代码,它可以在系统中独立运行。每个任务都有自己的栈空间和程序计数器(Program Counter),使得它能够保持自己的上下文并独立于其他任务运行。
在FreeRTOS中,任务的创建和调度由内核负责。任务可以具有不同的优先级,高优先级的任务服务器托管网将在低优先级任务之前执行。FreeRTOS使用抢占式调度(Preemptive Scheduling),这意味着如果有更高优先级的任务准备好运行,它可以抢占当前正在运行的任务。
任务的创建和管理是使用FreeRTOS提供的API函数完成的。以下是一些常见的任务管理函数:
xTaskCreate(): 用于创建任务。
vTaskDelete(): 用于删除任务。
vTaskDelay(): 用于使任务延迟一段时间。
vTaskSuspend()和vTaskResume(): 用于挂起和恢复任务的执行。
vTaskPrioritySet(): 用于设置任务的优先级。
任务可以通过调用vTaskDelay()来使自己暂停一段时间,也可以通过调用vTaskSuspend()挂起自己的执行,然后通过vTaskResume服务器托管网()来恢复执行。
在FreeRTOS中,任务是多线程的基本单位,通过任务的创建、删除、挂起、恢复等操作,可以实现多任务协同工作,提高系统的实时性和并发性。
在FreeRTOS中,任务就是一个函数,原型如下:
void ATaskFunction(void *pvParameters);
要注意的是:
1、这个函数不能返回
2、同一个函数,可以用来创建多个任务;换句话说,多个任务可以运行同一个函数;
3、函数内部,尽量使用局部变量:
1)每个任务都有自己的栈
2)每个任务运行这个函数时
(1)任务A的局部变量放在任务A的栈里、任务B的局部变量放在任务B的栈里
(2)不同任务的局部变量,有自己的副本
3)函数使用全局变量、静态变量的话
(1)只有一个副本:多个任务使用的是同一个副本
(2)要防止冲突(后续会讲)
示例:
void ATaskFunction( void *pvParameters )
{
/* 对于不同的任务,局部变量放在任务的栈里,有各自的副本 */
int32_t lVariableExample = 0;
/* 任务函数通常实现为一个无限循环 */
for( ;; )
{
/* 任务的代码 */
}
/* 如果程序从循环中退出,一定要使用vTaskDelete删除自己
* NULL表示删除的是自己
*/
vTaskDelete( NULL );
/* 程序不会执行到这里, 如果执行到这里就出错了 */
}
任务的创建
创建任务时使用的函数如下:
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode, // 函数指针, 任务函数
const char * const pcName, // 任务的名字
const configSTACK_DEPTH_TYPE usStackDepth, // 栈大小,单位为word,10表示40字节
void * const pvParameters, // 调用任务函数时传入的参数
UBaseType_t uxPriority, // 优先级
TaskHandle_t * const pxCreatedTask ); // 任务句柄, 以后使用它来操作这个任务
参数说明:
参数 | 描述 |
pvTaskCode |
函数指针,可以简单地认为任务就是一个C函数。 它稍微特殊一点:永远不退出,或者退出时要调用”vTaskDelete(NULL)” |
pcName |
任务的名字,FreeRTOS内部不使用它,仅仅起调试作用。 长度为:configMAX_TASK_NAME_LEN |
usStackDepth |
每个任务都有自己的栈,这里指定栈大小。 单位是word,比如传入100,表示栈大小为100 word,也就是400字节。 最大值为uint16_t的最大值。 怎么确定栈的大小,并不容易,很多时候是估计。 精确的办法是看反汇编码。 |
pvParameters | 调用pvTaskCode函数指针时用到:pvTaskCode(pvParameters) |
uxPriority |
优先级范围:0~(configMAX_PRIORITIES – 1) 数值越小优先级越低, 如果传入过大的值,xTaskCreate会把它调整为(configMAX_PRIORITIES – 1) |
pxCreatedTask |
用来保存xTaskCreate的输出结果:task handle。 以后如果想操作这个任务,比如修改它的优先级,就需要这个handle。 如果不想使用该handle,可以传入NULL。 |
返回值 |
成功:pdPASS; 失败:errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY(失败原因只有内存不足) 注意:文档里都说失败时返回值是pdFAIL,这不对。 pdFAIL是0,errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY是-1。 |
创建任务的例子
#include "stm32f1xx.h"
#include "FreeRTOS.h"
#include "task.h"
// 函数原型
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
// 任务函数
void vTask1(void *pvParameters) {
while (1) {
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); // 切换LED状态
vTaskDelay(1000 / portTICK_PERIOD_MS); // 每隔1秒执行一次
}
}
void vTask2(void *pvParameters) {
while (1) {
// 任务2的处理逻辑
vTaskDelay(2000 / portTICK_PERIOD_MS); // 每隔2秒执行一次
}
}
void vTask3(void *pvParameters) {
while (1) {
// 任务3的处理逻辑
vTaskDelay(3000 / portTICK_PERIOD_MS); // 每隔3秒执行一次
}
}
int main(void) {
// 硬件初始化
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
// 创建任务
xTaskCreate(vTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(vTask2, "Task2", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
xTaskCreate(vTask3, "Task3", configMINIMAL_STACK_SIZE, NULL, 3, NULL);
// 启动调度器
vTaskStartScheduler();
// 代码不应该运行到这里,如果运行到这里说明发生了错误
while (1) {
// 处理错误
}
}
任务的删除
删除任务时使用的函数如下:
void vTaskDelete( TaskHandle_t xTaskToDelete );
参数说明:
参数 | 描述 |
pvTaskCode |
任务句柄,使用xTaskCreate创建任务时可以得到一个句柄。 也可传入NULL,这表示删除自己。 |
怎么删除任务?举个不好的例子(例子来自韦东山):
自杀:vTaskDelete(NULL)
被杀:别的任务执行vTaskDelete(pvTaskCode),pvTaskCode是自己的句柄
杀人:执行vTaskDelete(pvTaskCode),pvTaskCode是别的任务的句柄
删除任务的例子
在FreeRTOS中,任务的删除通常是在任务自身的函数中通过调用vTaskDelete()来完成的。其中演示了如何在任务中删除其他任务:
#include "stm32f1xx.h"
#include "FreeRTOS.h"
#include "task.h"
// 函数原型
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
// 任务函数
TaskHandle_t Task1_Handle, Task2_Handle, Task3_Handle;
void vTask1(void *pvParameters) {
while (1) {
// 任务1的处理逻辑
vTaskDelay(1000 / portTICK_PERIOD_MS); // 每隔1秒执行一次
}
}
void vTask2(void *pvParameters) {
while (1) {
// 任务2的处理逻辑
vTaskDelay(2000 / portTICK_PERIOD_MS); // 每隔2秒执行一次
// 删除任务1
vTaskDelete(Task1_Handle);
}
}
void vTask3(void *pvParameters) {
while (1) {
// 任务3的处理逻辑
vTaskDelay(3000 / portTICK_PERIOD_MS); // 每隔3秒执行一次
// 删除任务2
vTaskDelete(Task2_Handle);
}
}
int main(void) {
// 硬件初始化
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
// 创建任务1
xTaskCreate(vTask1, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, &Task1_Handle);
// 创建任务2
xTaskCreate(vTask2, "Task2", configMINIMAL_STACK_SIZE, NULL, 2, &Task2_Handle);
// 创建任务3
xTaskCreate(vTask3, "Task3", configMINIMAL_STACK_SIZE, NULL, 3, &Task3_Handle);
// 启动调度器
vTaskStartScheduler();
// 代码不应该运行到这里,如果运行到这里说明发生了错误
while (1) {
// 处理错误
}
}
// 系统时钟配置
void SystemClock_Config(void) {
// 与前述代码相同,这里省略
}
// GPIO初始化
static void MX_GPIO_Init(void) {
// 与前述代码相同,这里省略
}
在这个例子中,任务2和任务3中分别使用了vTaskDelete()函数删除了任务1和任务2。请注意,在FreeRTOS中,任务只能删除自己或优先级较低的任务,因此任务2可以删除任务1,而任务3可以删除任务2。任务的删除是一种谨慎操作,需要确保被删除的任务没有在其他地方被引用或使用。
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
相关推荐: SpringBoot的Thymeleaf应用Default Title
在现代Web应用中,生成PDF文件是一个常见的需求。为了满足这一需求,我们可以利用Spring Boot集成Thymeleaf和Flying Saucer PDF来生成具有丰富内容的PDF文件。Thymeleaf作为模板引擎,提供了简单而强大的模板语法,而Fl…