1. FreeRTOS系统-创建任务

前言

本文用来记录自己学习FreeRTOS的过程,目的是给自己学习增加一些动力和乐趣,主要是从使用的方向来学习FreeRTOS,因为之前已经学习了一些基础知识,可能学习的过程比较杂乱,想到哪里就学到哪一步部分,也就写到哪一部分。

第一节 简述

对于FreeRTOS应用到实际中,需要以下几个步骤:

第一个步骤:创建任务

创建任务可以看成两个部分。

第一部分,创建一个开始任务。

        在code中应该先运行开始任务,在开始任务中再创建项目中要使用到的实际任务,开始任务只运行一次,运行完开始任务后就可以将开始任务删除已节省MCU RAM的使用。

第二部分,创建项目中要使用的所有任务。

        第二部分中任务函数的特点分为以下几点:

        a. 任务函数不能返回,是一个无限循环函数;

        b每个任务都有自己的栈,在创建是就已经分配了任务自己的栈,在运行任务函数时局部变量放在自己的栈里,任务函数中内部所有栈的开销都是使用任务自己的栈。其中栈空间是保存多少个字(word),而不是多少个字节(byte)。

        c. 任务函数中使用的全局变量、静态变量存放在内存的某个区域,所有任务都可以共用。(注:不过要防止使用冲突,所以尽量使用局部变量。)

第二节 创建任务函数与删除任务函数

使用创建任务函数xTaskCreate与删除任务函数vTaskDelete直接根据函数参数输入对应的变量就可以创建或删除相应的任务。

1.创建任务函数(xTaskCreate)

BaseType_t xTaskCreate(
    TaskFunction_t pvTaskCode,     
    //任务函数。(函数名就是指向函数的指针)
    const char * const pcNane,     
    //具有描述性的任务名字,一般不会使用它。
    const uint16_t usStackDepth,     
    //任务堆栈的大小,
    void * const pvParameters,     
    //传递给函数的参数
    UBaseType_t uxPriority,     
    //任务运行时的优先级
    xTaskHandle *pvCreatedTask 
    //用于传递任务的句柄,可以引用从而对任务进行其他操作。任务创建成功以后会返回此任务的任务句柄,句柄就是任务的堆栈,其他函数可能会使用到该任务的任务句柄。
)

例,

    //创建开始任务
    xTaskCreate((TaskFunction_t )start_task,            //对应的开始任务函数
                (const char*    )"start_task",          //开始任务的名称
                (uint16_t       ) 512,        //任务堆栈大小
                (void*          )NULL,                  //没有参数
                (UBaseType_t    ) 1,       //任务优先级为1
                (TaskHandle_t*  ) &StartTask_Handler);   //任务的句柄   

2.删除任务函数(vTaskDelete)

void vTaskDelete(

TaskHandle_t xTaskToDelete

//要删除的任务的任务句柄

)

例,vTaskDelete(StartTask_Handler); //删除开始任务

3.创建任务函数(xTaskCreate)详解

任务的创建有两种方法,一种是使用动态创建xTaskCreate,一种是使用静态创建xTaskCreateStatic

函数xTaskCreate

    BaseType_t xTaskCreate(    TaskFunction_t pxTaskCode,
                            const char * const pcName,
                            const uint16_t usStackDepth,
                            void * const pvParameters,
                            UBaseType_t uxPriority,
                            TaskHandle_t * const pxCreatedTask )

    {
    TCB_t *pxNewTCB; //初始化任务控制块Task control block(TCB)
    BaseType_t xReturn; //初始化一个任务句柄,用于对于创建任务的一个句柄返回
        StackType_t *pxStack; //创建任务对应栈的起始位置指针

        pxStack = ( StackType_t * ) pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); 

            if( pxStack != NULL )
            {
                pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) );  //为任务控制块分配堆

                if( pxNewTCB != NULL )
                {
                    pxNewTCB->pxStack = pxStack;
                }
                else
                {
                    vPortFree( pxStack );
                }
            }
            else
            {
                pxNewTCB = NULL;
            }
        }

        if( pxNewTCB != NULL )
        {

            prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL ); //使用此函数初始化新的任务
            prvAddNewTaskToReadyList( pxNewTCB ); //将新创建的任务添加到Ready列表
            xReturn = pdPASS;
        }
        else
        {
            xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
         }
        return xReturn;
    }

函数prvInitialiseNewTask

static void prvInitialiseNewTask(     TaskFunction_t pxTaskCode,
                                    const char * const pcName,
                                    const uint32_t ulStackDepth,
                                    void * const pvParameters,
                                    UBaseType_t uxPriority,
                                    TaskHandle_t * const pxCreatedTask,
                                    TCB_t *pxNewTCB,
                                    const MemoryRegion_t * const xRegions ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */
{
StackType_t *pxTopOfStack; //栈顶指针
UBaseType_t x;

    /* 如果使能了堆栈溢出检测功能或追踪功能的话就使用一个定值来 填充任务堆栈*/
    #if( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) )
    {
        /* Fill the stack with a known value to assist debugging. */
        ( void ) memset( pxNewTCB->pxStack, ( int ) tskSTACK_FILL_BYTE, ( size_t ) ulStackDepth * sizeof( StackType_t ) );
    }
    #endif /* ( ( configCHECK_FOR_STACK_OVERFLOW > 1 ) || ( ( configUSE_TRACE_FACILITY == 1 ) || ( INCLUDE_uxTaskGetStackHighWaterMark == 1 ) ) ) */

    /* 计算栈顶地址。这取决于堆栈是从高内存开始向低内存,还是从低内存开始向高内存。 */
    #if( portSTACK_GROWTH < 0 )
    {

        //获取栈顶地址,并向下做字节对齐
        pxTopOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
        pxTopOfStack = ( StackType_t * ) ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack ) & ( ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) ) ); 

        /* 检查对齐是否正确 */
        configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxTopOfStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );
    }
    #else /* portSTACK_GROWTH */
    {
        pxTopOfStack = pxNewTCB->pxStack;

        /* Check the alignment of the stack buffer is correct. */
        configASSERT( ( ( ( portPOINTER_SIZE_TYPE ) pxNewTCB->pxStack & ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK ) == 0UL ) );

        /* The other extreme of the stack space is required if stack checking is
        performed. */
        pxNewTCB->pxEndOfStack = pxNewTCB->pxStack + ( ulStackDepth - ( uint32_t ) 1 );
    }
    #endif /* portSTACK_GROWTH */

    /*向任务控制块中存储任务名字*/
    for( x = ( UBaseType_t ) 0; x < ( UBaseType_t ) configMAX_TASK_NAME_LEN; x++ )
    {
        pxNewTCB->pcTaskName[ x ] = pcName[ x ];
        if( pcName[ x ] == 0x00 )
        {
            break;
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    pxNewTCB->pcTaskName[ configMAX_TASK_NAME_LEN - 1 ] = '\0';

    pxNewTCB->uxPriority = uxPriority; //任务控制块的优先级

    vListInitialiseItem( &( pxNewTCB->xStateListItem ) ); //初始化任务控制块所在的链表
    vListInitialiseItem( &( pxNewTCB->xEventListItem ) );
    listSET_LIST_ITEM_OWNER( &( pxNewTCB->xStateListItem ), pxNewTCB );  //设置链表的拥有者,即TCB自身
    listSET_LIST_ITEM_VALUE( &( pxNewTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) uxPriority ); //初始化链表的其他内容
    listSET_LIST_ITEM_OWNER( &( pxNewTCB->xEventListItem ), pxNewTCB ); //
//使用下面内容初始化任务所用的堆栈    

#if( portUSING_MPU_WRAPPERS == 1 )
    {
        pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters, xRunPrivileged );
    }
    #else /* portUSING_MPU_WRAPPERS */
    {
        pxNewTCB->pxTopOfStack = pxPortInitialiseStack( pxTopOfStack, pxTaskCode, pvParameters );
    }
    #endif /* portUSING_MPU_WRAPPERS */

    if( ( void * ) pxCreatedTask != NULL )
    {
        *pxCreatedTask = ( TaskHandle_t ) pxNewTCB; //生成任务句柄并返回
    }
    else
    {
        mtCOVERAGE_TEST_MARKER();
    }
}

  • 7
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值