文章目录
- 1、任务的三要素:主体函数、任务栈、任务控制块。
- 2、与任务相关的部分API函数
- (1)xTaskCreate
- (2)void vTaskDelete( TaskHandle_t xTaskToDelete )
- 3、任务的创建
- (1)使用静态任务创建函数进行任务创建(使用这个函数创建任务后,会返回一个任务句柄,这个句柄实际上就是一个指针,指向对应任务的任务控制块这个结构体)
- 1)定义任务函数
- 2)定义任务栈(这个是静态创建时需要进行的,即静态创建的时候任务控制块和栈空间都需要先定义好)
- 3)定义任务控制块
- 4)使用xTaskCreateStatic来创建一个任务
- (2)使用动态任务创建函数进行任务创建(使用这个函数创建任务时,需要传进去预先定义好的任务句柄)
- 动态内存空间的堆
- 1)定义任务函数
- 2)定义任务句柄(作为任务创建时创进去的实参,创建成功后其指向的是任务控制块)
- 3)使用xTaskCreate()函数来创建一个任务。
- 4、任务的删除vTaskDelete(xHandle Taskx)
- 5、需要注意的几个点
- (1)任务创建成功后对任务的各种操作都是通过任务句柄来实现的
- (2)可以使用同一个函数创建两个任务(这时候因为两个函数的栈不一样,所以他们互不影响)
- 6、动态创建任务函数解析
1、任务的三要素:主体函数、任务栈、任务控制块。
重要:每个任务中所有局部变量占用的空间必须要比其栈空间小,否则可能会出现这个任务内存的溢出而影响其他任务。
2、与任务相关的部分API函数
(1)xTaskCreate
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName,
const configSTACK_DEPTH_TYPE usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask );
(2)void vTaskDelete( TaskHandle_t xTaskToDelete )
3、任务的创建
(1)使用静态任务创建函数进行任务创建(使用这个函数创建任务后,会返回一个任务句柄,这个句柄实际上就是一个指针,指向对应任务的任务控制块这个结构体)
即任务使用的栈和任务控制块都事先定义好,即使用的是静态内存。
1)定义任务函数
任务函数实际为一个无限循环且不带返回值的函数。
且在任务函数里面尽量使用局部变量。
2)定义任务栈(这个是静态创建时需要进行的,即静态创建的时候任务控制块和栈空间都需要先定义好)
/* 定义LED 任务堆栈 */
static StackType_t LED_Task_Stack[128];
3)定义任务控制块
/* AppTaskCreate 任务控制块 */
static StaticTask_t AppTaskCreate_TCB;
/* AppTaskCreate 任务控制块 */
static StaticTask_t LED_Task_TCB;
4)使用xTaskCreateStatic来创建一个任务
int main(void)
{
/* 开发板硬件初始化 */
BSP_Init();
/* 创建 AppTaskCreate 任务 */
AppTaskCreate_Handle = xTaskCreateStatic((TaskFunction_t )AppTaskCreate, //任务函数
(const char* )"AppTaskCreate", //任务名称
(uint32_t )128, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )3, //任务优先级
(StackType_t* )AppTaskCreate_Stack, //任务堆栈
(StaticTask_t* )&AppTaskCreate_TCB);//任务控制块
if(NULL != AppTaskCreate_Handle)/* 创建成功 */
vTaskStartScheduler(); /* 启动任务,开启调度 */
while(1); /* 正常不会执行到这里 */
}
static void AppTaskCreate(void)
{
taskENTER_CRITICAL(); //进入临界区
/* 创建LED_Task任务 */
LED_Task_Handle = xTaskCreateStatic((TaskFunction_t )LED_Task, //任务函数
(const char* )"LED_Task", //任务名称
(uint32_t )128, //任务堆栈大小
(void* )NULL, //传递给任务函数的参数
(UBaseType_t )4, //任务优先级
(StackType_t* )LED_Task_Stack, //任务堆栈
(StaticTask_t* )&LED_Task_TCB); //任务控制块
if(NULL != LED_Task_Handle)/* 创建成功 */
printf("LED_Task任务创建成功!\n");
else
printf("LED_Task任务创建失败!\n");
vTaskDelete(AppTaskCreate_Handle); //删除AppTaskCreate任务
taskEXIT_CRITICAL(); //退出临界区
}
任务创建成功后,是处于任务就绪状态,此时任务可以参与操作系统的调度。
若此时还没有开启调度任务就不会被执行。上面在主函数创建任务成功之后开启了调度器。
(2)使用动态任务创建函数进行任务创建(使用这个函数创建任务时,需要传进去预先定义好的任务句柄)
动态内存空间的堆
FreeRTOS在SRAM里面定义一个大数组,即堆内存,供FreeRTOS的动态分配函数使用。
在第一次使用时系统会将堆内存进行初始化。例如
#define configTOTAL_HEAP_SIZE ((size_t)(36*1024))
static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
if ( pxEnd == NULL ){
prvHeapInit();
}
else
{
mtCOVERAGE_TEST_MARKER();
}
1)定义任务函数
任务函数实际为一个无限循环且不带返回值的函数。
且在任务函数里面尽量使用局部变量。
2)定义任务句柄(作为任务创建时创进去的实参,创建成功后其指向的是任务控制块)
使用动态任务创建函数的时候,最后一个参数传递的是对应任务的任务句柄的地址,即这个动态任务创建函数的返回值是一个是否成功创建任务的信息,所以需要传进去一个任务句柄,这个任务句柄指向的还是对应任务的任务控制块。
static TaskHandle_t AppTaskCreate_Handle = NULL;
static TaskHandle_t LED_Task_Handle = NULL;
3)使用xTaskCreate()函数来创建一个任务。
int main(void)
{
BaseType_t xReturn = pdPASS;
BSP_Init();
printf("这是一个[野火]-STM32 全系列开发板-FreeRTOS-工程模板!\r\n");
xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate,
(const char* )"AppTaskCreate",
(uint16_t )512,
(void* )NULL,
(UBaseType_t )1,
(TaskHandle_t* )&AppTaskCreate_Handle);
if (pdPASS == xReturn)
vTaskStartScheduler();
else
return -1;
while (1);
}
static void AppTaskCreate(void)
{
BaseType_t xReturn = pdPASS;
taskENTER_CRITICAL();
xReturn = xTaskCreate((TaskFunction_t )LED_Task,
(const char* )"LED_Task",
(uint16_t )512,
(void* )NULL,
(UBaseType_t )2,
(TaskHandle_t* )&LED_Task_Handle);
if (pdPASS == xReturn)
printf("创建 LED_Task 任务成功!\r\n");
vTaskDelete(AppTaskCreate_Handle);
taskEXIT_CRITICAL();
}
4、任务的删除vTaskDelete(xHandle Taskx)
需要使用到任务创建时的任务句柄。即这个函数需要传递的参数是任务句柄
对于静态创建任务函数来说它的返回值为其任务句柄;而动态创建任务函数是吧定义好的任务句柄作为实参的,也可以为空即NULL。
当这个函数传入的参数为NULL时表示删除自身任务。
5、需要注意的几个点
(1)任务创建成功后对任务的各种操作都是通过任务句柄来实现的
(2)可以使用同一个函数创建两个任务(这时候因为两个函数的栈不一样,所以他们互不影响)
6、动态创建任务函数解析
(1)创建任务时的入口函数在定义中的形参可以是 void *类型,表示的是可以传递任何类型的参数
(2)任务函数里面的局部变量是存放在对应任务的栈空间里面的
(3)如何大概确定栈的大小:栈的大小取决于局部变量的大小和调用深度(即任务里面的调用函数的关系)传递进来的栈的深度为N,但实际上这个栈具有4N字节空间
(4)栈是从哪里分配出来的:动态创建时每个任务的栈是从一个预先分配好的巨大的数据(堆)中分配的,这个数组的大小可以用户自己设置,具体如下图
(5)使用动态创建任务时,第一个参数为任务函数入口,即任务需要执行函数的地址,当任务执行的时候即让PC寄存器的值等于这个函数地址;
(6)这个函数为对应若任务分配了TCB结构体、栈,并在栈里写入了函数地址、参数
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)