自学内容网 自学内容网

《FreeRTOS任务基础知识篇》

FreeRTOS的核心是任务管理,以下介绍FreeRTOS任务的一些基础知识。

1. 什么是多任务系统?

  • FreeRTOS是一个抢占式多任务系统,它的任务调度器也是抢占式的。
  • 基本原理:
    1. 高优先级的任务可以打断低优先级的任务,取得CPU的使用权,从而保证紧急任务的运行。
    2. 高优先级的任务执行完成后,重新释放CPU的使用权,低优先级的任务才可以继续执行。
      在这里插入图片描述

2. FreeRTOS任务

  • 每个实时应用都可以作为一个独立的任务。
  • 任何一个时间点只能有一个任务运行,具体运行哪一个任务是由任务调度器来决定的,因此任务调度器会不断地的开启、关闭每个任务。
  • 任务调度器的职责是确保每个任务开始执行时其上下文环境(寄存器值、堆栈内容等)和任务上一次退出的时候相同。为了做到这一点,每个任务都必须有个堆栈,当任务切换时将上下文环境保存到堆栈中,这样任务再次执行时就可以从堆栈中取出上下文环境,任务恢复执行。

3. 任务状态

3.1 运行态

  • 一个任务运行时,就处于就绪态,处于运行态的任务就是当前正在执行的任务。

3.2 就绪态

  • 处于就绪态的任务就是那些已经准备就绪的任务(未被挂起或者阻塞),但是还没有运行是因为有一个同优先级或者更高优先级的任务正在运行。

3.3 阻塞态

  • 如果一个任务正在等候某一个外部事件,则该任务处于阻塞态。任务进入阻塞态会有一个超时时间,超过这个超时时间任务会退出阻塞态,即使所等待的事件还没有来临。

3.4 挂起态

  • 任务进入挂起态后不能被任务调度器调用进入运行态,但是进入挂起态的任务没有超时时间。
  • 任务进入和退出挂起态只有通过调用函数 vTaskSuspend() 和 vTaskResume() 来实现。
    在这里插入图片描述

4. 任务优先级

  • 每个任务都可以分配一个从0 ~ (configMAX_PRIORITIES - 1) 的优先级。
  • 优先级的数字越低表示任务的优先级越低,0是最低优先级。
  • 空闲任务的优先级最低,为0。
  • FreeROTS调度器确保处于就绪态或者运行态的高优先级的任务获取处理器使用权。处于就绪态的高优先级任务才会运行。
  • 当宏 configUSE_TIME_SLICING 定义为1,多个任务可以共用一个优先级,数量不限。系统默认设置为1,处于就绪态的优先级相同的多个任务会使用时间片轮转调度器获取运行时间。

5. 任务的实现

  • 使用FreeRTOS过程中,创建任务会使用函数 xTaskCreate() 或 xTaskCreateStatic() 。
  • 两个函数的第一个参数都是 pxTaskCode,表示任务的任务函数,任务函数就是完成本任务工作的函数。
/* 任务函数示例 */
/* 函数返回值类型一定要为void类型,任务的参数也是void指针类型。 */
void vTaskCode( void * pvParameters )
{
    for( ;; )
    {
        /* Task code goes here. */
        vTaskDelay(); /* 此处只要是能让FreeRTOS发生任务切换的函数即可。 */
    }

/* 正常任务不允许退出循环,如果要跳出,则需要删除任务 */
vTaskDelete(NULL);
}

6. 任务控制块

  • FreeRTOS每个任务都有一个属性需要存储,把这些属性集合到一起用一个结构体来表示,这个结构体就是任务控制块:TCB_t。
  • 使用任务创建函数时,会自动给每个任务分配一个任务控制块。
typedef struct tskTaskControlBlock       /* The old naming convention is used to prevent breaking kernel aware debuggers. */
{
    volatile StackType_t * pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack.  THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */

    #if ( portUSING_MPU_WRAPPERS == 1 )
        xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer.  THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
    #endif

    ListItem_t xStateListItem;                  /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
    ListItem_t xEventListItem;                  /*< Used to reference a task from an event list. */
    UBaseType_t uxPriority;                     /*< The priority of the task.  0 is the lowest priority. */
    StackType_t * pxStack;                      /*< Points to the start of the stack. */
    char pcTaskName[ configMAX_TASK_NAME_LEN ]; /*< Descriptive name given to the task when created.  Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */

    #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
        StackType_t * pxEndOfStack; /*< Points to the highest valid address for the stack. */
    #endif

    #if ( portCRITICAL_NESTING_IN_TCB == 1 )
        UBaseType_t uxCriticalNesting; /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
    #endif

    #if ( configUSE_TRACE_FACILITY == 1 )
        UBaseType_t uxTCBNumber;  /*< Stores a number that increments each time a TCB is created.  It allows debuggers to determine when a task has been deleted and then recreated. */
        UBaseType_t uxTaskNumber; /*< Stores a number specifically for use by third party trace code. */
    #endif

    #if ( configUSE_MUTEXES == 1 )
        UBaseType_t uxBasePriority; /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
        UBaseType_t uxMutexesHeld;
    #endif

    #if ( configUSE_APPLICATION_TASK_TAG == 1 )
        TaskHookFunction_t pxTaskTag;
    #endif

    #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
        void * pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
    #endif

    #if ( configGENERATE_RUN_TIME_STATS == 1 )
        configRUN_TIME_COUNTER_TYPE ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */
    #endif

    #if ( ( configUSE_NEWLIB_REENTRANT == 1 ) || ( configUSE_C_RUNTIME_TLS_SUPPORT == 1 ) )
        configTLS_BLOCK_TYPE xTLSBlock; /*< Memory block used as Thread Local Storage (TLS) Block for the task. */
    #endif

    #if ( configUSE_TASK_NOTIFICATIONS == 1 )
        volatile uint32_t ulNotifiedValue[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
        volatile uint8_t ucNotifyState[ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
    #endif

    /* See the comments in FreeRTOS.h with the definition of
     * tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
    #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 !e9029 Macro has been consolidated for readability reasons. */
        uint8_t ucStaticallyAllocated;                     /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
    #endif

    #if ( INCLUDE_xTaskAbortDelay == 1 )
        uint8_t ucDelayAborted;
    #endif

    #if ( configUSE_POSIX_ERRNO == 1 )
        int iTaskErrno;
    #endif
} tskTCB;

/* The old tskTCB name is maintained above then typedefed to the new TCB_t name
 * below to enable the use of older kernel aware debuggers. */
typedef tskTCB TCB_t;

7. 任务堆栈

  • FreeRTOS之所以能够正确恢复一个任务的运行,就是因为有任务堆栈。
  • 创建任务的时候需要指定任务堆栈,如果使用动态创建任务的方式,任务堆栈会有函数自动分配。如果使用静态创建任务的方式,需要程序员手动分配任务堆栈。
  • 任务堆栈的数据类型为StackType_t,以下为该类型在DSP中的定义。
typedef unsigned int   __uint16_t;
typedef__uint16_tuint16_t;
#define portSTACK_TYPE  uint16_t
typedef portSTACK_TYPE StackType_t;

原文地址:https://blog.csdn.net/zhz_java/article/details/143789031

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!