【FreeRTOS】基于STM32F103x笔记02---任务管理(静态与动态创建和删除)

目录

前言:

所用工具:

函数包含:

一、FreeRTOS 创建和删除任务相关 API 函数

1.认识ATaskFunction任务函数

2.创建任务相关 API 函数的使用

2.1 动态方式创建 xTaskCreate() 函数

2.2 静态方式创建 xTaskCreateStatic() 函数

3.删除任务相关 API 函数的使用

二、FreeRTOS创建和删除任务实例应用

1.动态和静态创建任务实例

2.使用任务参数创建任务

3.通过vTaskDelete任务的删除


前言:

此笔记通过2个创建任务的实例和1个删除任务的实例,来学习编写FreeRTOS的任务管理相关代码知识以及学习FreeRTOS三个相关任务管理的API函数。

所用工具:

1.FreeRTOS源码(官网下载)

2.MDK-Keil软件

3.STM32F1xx/STM32F4xx库 

4.STM32F103C8T6

5.串口调试助手

函数包含:
FreeRTOS 创建和删除任务相关 API 函数
描述
xTaskCreate()
动态方式创建任务
xTaskCreateStatic()
静态方式创建任务
vTaskDelete()
删除任务

一、FreeRTOS 创建和删除任务相关 API 函数

1.认识ATaskFunction任务函数

FreeRTOS 中,任务就是一个函数,示例如下:
void ATaskFunction( void *pvParameters )
{
/* 对于不同的任务,局部变量放在任务的栈里,有各自的副本 */
int32_t lVariableExample = 0;
/* 任务函数通常实现为一个无限循环,下述函数也就是while(1){}*/
for( ;; )
{
/* 任务的代码 */
}
/* 如果程序从循环中退出,一定要使用vTaskDelete删除自己
* NULL表示删除的是自己
*/
vTaskDelete( NULL );
/* 程序不会执行到这里, 如果执行到这里就出错了 */
}
由此,该函数无返回值, 同一个函数,可以用来创建多个任务(多个任务可以运行同一个函数)
函数内部,尽量使用局部变量;每个任务都有自己的栈,每个任务运行这个函数时,任务A 的局部变量放在任务 A 的栈里、任务 B 的局部变量放在任务 B 的栈里;不同任务的局部变量,有自己的副本,函数使用全局变量、静态变量的话只有一个副本(多个任务使用的是同一个副本要防止冲突)

2.创建任务相关 API 函数的使用

2.1 动态方式创建 xTaskCreate() 函数

此函数用于使用动态的方式创建任务,任务的任务控制块以及任务的栈空间所需的内存,
在  FreeRTOSConfig.h  文件中将宏 configSUPPORT_DYNAMIC_ALLOCATION 配置为 1
函数原型(包含6个参数)如下所示:
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
指向任务函数的指针(示例 Task1Function)
pcName
任务名(示例 "Task1"
usStackDepth
每个任务都有自己的栈,这里指定栈大小。(示例 100)
单位是 word ,比如传入 100 ,表示栈大小为 100 word ,也就是400 字节。
最大值为 uint16_t 的最大值。
确定栈的大小,并不容易,很多时候是估计;精确的办法是看反汇编码。
pvParameters
调用 pvTaskCode 函数指针时用到: pvTaskCode(pvParameters)(示例 NULL)
uxPriority
优先级范围: 0~(confifigMAX_PRIORITIES – 1) 数值越小优先级越低,
如果传入过大的值,xTaskCreate 会把它调整为 (confifigMAX_PRIORITIES – 1)
pxCreatedTask
用来保存 xTaskCreate 的输出结果: task handle
以后如果想操作这个任务,比如修改它的优先级,就需要这个 handle
如果不想使用该 handle ,可以传入 NULL。(示例 &xHandleTask1或者NULL)
返回值
任务创建成功 pdPASS
任务 创建失败 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY(内存不足)

2.2 静态方式创建 xTaskCreateStatic() 函数

此函数用于使用静态的方式创建任务,事先分配好任务控制块,事先提供栈
需要在 FreeRTOSConfig.h 文件中configSUPPORT_STATIC_ALLOCATION 配置为 1。

函数原型(包含7个参数)如下所示:

TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,//任务函数指针
                                const char * const pcName, //任务名
                                const uint32_t ulStackDepth,//任务堆栈大小
                                void * const pvParameters,//传递给任务函数的参数
                                UBaseType_t uxPriority,//优先级
                                StackType_t * const puxStackBuffer,//传入的任务栈指针
                                StaticTask_t * const pxTaskBuffer );//任务控制块指针,内存由用户分配提供

由于当前不作为重点研究对象,具体描述不展开。

3.删除任务相关 API 函数的使用

删除任务时使用的函数如下:

void vTaskDelete( TaskHandle_t xTaskToDelete );
参数描述
pvTaskCode
任务句柄,使用 xTaskCreate 创建任务时可以得到一个句柄。
也可传入 NULL ,这表示删除自己。
自删:     vTaskDelete(NULL)
被删:    别的任务执行 vTaskDelete(pvTaskCode) pvTaskCode 是自己的句柄
删其他:执行 vTaskDelete(pvTaskCode) pvTaskCode 是别的任务的句柄

二、FreeRTOS创建和删除任务实例应用

下述的实例都是根据【FreeRTOS】基于STM32F103x笔记01---初识与移植的基础上编写

当前先忽略优先级的概念后续会补充上。

1.动态和静态创建任务实例

两个动态创建一个静态创建任务函数如下:

void Task1Function(void * param)
{
	while (1)
	{
		printf("1");
	}
}
void Task2Function(void * param)
{
	while (1)
	{
		printf("2");
	}
}

void Task3Function(void * param)
{
	while (1)
	{
		printf("3");
	}
}
/*-----------------------------------------------------------*/
StackType_t xTask3Stack[100];
StaticTask_t xTask3TCB;

StackType_t xIdleTaskStack[100];
StaticTask_t xIdleTaskTCB;

void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer,
                                    StackType_t ** ppxIdleTaskStackBuffer,
                                    uint32_t * pulIdleTaskStackSize )
{
    *ppxIdleTaskTCBBuffer = &xIdleTaskTCB;
    *ppxIdleTaskStackBuffer = xIdleTaskStack;
    *pulIdleTaskStackSize = 100;
}

主函数如下所示:

int main( void )
{
	TaskHandle_t xHandleTask1;
		
#ifdef DEBUG
  debug();
#endif

	prvSetupHardware();

	printf("Hello, world!\r\n");

	xTaskCreate(Task1Function, "Task1", 100, NULL, 1, &xHandleTask1);
	xTaskCreate(Task2Function, "Task2", 100, NULL, 1, NULL);
	xTaskCreateStatic(Task3Function, "Task3", 100, NULL, 1, xTask3Stack, &xTask3TCB);

	/* Start the scheduler. */
	vTaskStartScheduler();

	/* Will only get here if there was not enough heap space to create the
	idle task. */
	return 0;
}

运行结果如下所示:

2.使用任务参数创建任务

任务函数如下所示:共用一个任务函数

void vTaskFunction( void *pvParameters )
{
    const char *pcTaskText = pvParameters;
    volatile uint32_t ul; /* volatile用来避免被优化掉 */
    /* 任务函数的主体一般都是无限循环 */
    for( ;; )
    {
    /* 打印任务的信息 */
        printf(pcTaskText);
    /* 延迟一会(比较简单粗暴) */
        for( ul = 0; ul < mainDELAY_LOOP_COUNT; ul++ )
         {
         }
    }
}

主函数:

static const char *pcTextForTask1 = "T1 run\r\n";
static const char *pcTextForTask2 = "T2 run\r\n";
int main( void )
{
    prvSetupHardware();
    xTaskCreate(vTaskFunction, "Task 1", 1000, (void *)pcTextForTask1, 1, NULL);
    xTaskCreate(vTaskFunction, "Task 2", 1000, (void *)pcTextForTask2, 1, NULL);
    /* 启动调度器 */
    vTaskStartScheduler();
    /* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
    return 0;
}
不同的任务,pvParameters不一样

同一个函数,可以用来创建多个任务(多个任务可以运行同一个函数)

3.通过vTaskDelete任务的删除

任务1:打印,创建任务2并获取创建的返回值存到ret,继续打印,并进行等待。

任务2:打印,删除自己,会位于任务1等待中运行。

void vTask1( void *pvParameters )
{
    const TickType_t xDelay100ms = pdMS_TO_TICKS( 100UL );
    BaseType_t ret;
    /* 任务函数的主体一般都是无限循环 */
    for( ;; )
    {
        /* 打印任务的信息 */
        printf("Task1 is running\r\n");
        ret = xTaskCreate( vTask2, "Task 2", 1000, NULL, 2, &xTask2Handle );
        if (ret != pdPASS)
        printf("Create Task2 Failed\r\n");
        // 如果不休眠的话, Idle任务无法得到执行
        // Idel任务会清理任务2使用的内存
        // 如果不休眠则Idle任务无法执行, 最后内存耗尽
        vTaskDelay( xDelay100ms );
    }
}
void vTask2( void *pvParameters )
{
    /* 打印任务的信息 */
    printf("Task2 is running and about to delete itself\r\n");
    // 可以直接传入参数NULL, 这里只是为了演示函数用法
    vTaskDelete(xTask2Handle);
}

int main( void )
{
    prvSetupHardware();
    xTaskCreate(vTask1, "Task 1", 1000, NULL, 1, NULL);
    /* 启动调度器 */
    vTaskStartScheduler();
    /* 如果程序运行到了这里就表示出错了, 一般是内存不足 */
    return 0;
}

结果如下:

在任务 1 的函数中,如果不调用 vTaskDelay ,则 Idle 任务用于没有机会执行,它就无法释放创建任务 2 是分配的内存。 而任务1 在不断地创建任务,不断地消耗内存,最终内存耗尽再也无法创建新的任务。
任务 1 的代码中,需要注意的是: xTaskCreate 的返回值。
很多手册里说它失败时返回值是 pdFAIL ,这个宏是 0
其实失败时返回值是 errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY ,这个宏是 -1
为了避免混淆,我们使用返回值跟 pdPASS 来比较,这个宏是 1。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

7yewh

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值