freertos的任务

在公司实际项目中需要用到freertos,这里做一些自己学习的笔记

一、任务

1.每个任务都有自己独立的运行环境,不依赖于系统中其他任务或调度器

2.调度器

  ①:一个时间点只能运行一个任务,具体运行哪个任务由RTOS调度器决定,因此调度器会重复的开启、关闭每个任务

  ②:调度器的职责是确保当前一个任务开始执行的时候,其上下文环境(寄存器值、堆栈内容)和任务上一次退出的时候相同

3.为了做到能够做到2②,每个任务必须有堆栈,这样当任务切换的时候上下文环境保存在堆栈中。任务再次运行的时候就可以从堆栈中取出上下文环境,任务恢复运行

(1)任务的特性

1.简单

2.没有使用限制(任务创建的个数没有限制)

3.支持抢占、支持优先级,使用抢占的话必须仔细考虑重入的问题

4.每个任务都拥有堆栈导致RAM使用量增大

(2)任务的状态

任务有四种状态:运行态、就绪态、阻塞态、挂起态,任务运行时永远处于这四种状态之一

1.运行态

  指正在运行,占用CPU的任务。单片机基本都是单核cpu,所以任何时刻只有一个任务储运运行态

2.就绪态

  指以及主备就绪,可以运行的任务,之所以没有运行是因为时间轮转还没到这个任务(因为有一个同优先级或者更高优先级的任务正在运行)

3.阻塞态

  当一个任务在等待外部事件的时候就处于阻塞态,如等待信号量、队列、事件组等。任务阻塞有超时时间。超过时间会退出阻塞处于就绪态

4.挂起态

  和阻塞态一样,任务进入挂起态后不能被调度器调用进行运行态,挂起没有超时时间。任务的挂起使用vTaskSuspend(),恢复使用xTaskResume,恢复后程序处于就绪态

 

  综上,从图中可知,就绪态是任务的关键状态,其他三种都要和它的转换关系,运行态是最自由的状态,它能够切换到任意状态

(3)任务的优先级

  1.空闲任务

  说到任务的优先级就需要先了解下空闲任务

  很多人都会问为什么要有空闲任务,其实最初的RTOS设计思路是为了防止所有任务都处于阻塞态,而没有任务处于运行态,而处理器总需要执行些代码,从而空闲任务就孕育而生。

  调用vTaskStartScheduler()后RTOS会自动创建一个空闲任务,空闲任务代码量很短小,是最小的任务,其任务的优先级是0(最低优先级),能够保障一旦有其他任务进入就绪态能够迅速切换到就绪任务。在空闲任务中可以添加钩子函数,每一次空闲任务调用时会调用钩子函数

  2.任务的优先级(重要

 (1)每个任务可以分配一个0~configMAX_PRIORITIES-1的优先级

 (2)优先级数字越低,优先级越低,0的优先级最低,configMAX_PRIORITIES-1的优先级最高

 (3)freertos的调度器能够确保处于就绪态或运行态的高优先级的任务获得处理器的使用权

 (4)当宏configUSE_TIME_SLICING定义为1的时候多个任务可以共用一个优先级,任务数量不限

 (5)在任务函数中不能返回或退出,一定要退出任务需要调用vTaskDelete(NULL)来删除此任务

 

(4)任务控制块

(1)freertos的每个任务都有一些属性要存储,freertos将这些属性存储到了一个结构体中,这个结构体就是任务控制块TCB_t

(2)使用任务创建函数时就会自动的给每个任务分配一个任务控制块

(3)

 1 typedef struct tskTaskControlBlock
 2 {
 3     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. */
 4 
 5     #if ( portUSING_MPU_WRAPPERS == 1 )
 6         xMPU_SETTINGS    xMPUSettings;        /*< The MPU settings are defined as part of the port layer.  THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
 7     #endif
 8 
 9     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 ). */
10     ListItem_t            xEventListItem;        /*< Used to reference a task from an event list. */
11     UBaseType_t            uxPriority;            /*< The priority of the task.  0 is the lowest priority. */
12     StackType_t            *pxStack;            /*< Points to the start of the stack. */
13     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. */
14 
15     #if ( ( portSTACK_GROWTH > 0 ) || ( configRECORD_STACK_HIGH_ADDRESS == 1 ) )
16         StackType_t        *pxEndOfStack;        /*< Points to the highest valid address for the stack. */
17     #endif
18 
19     #if ( portCRITICAL_NESTING_IN_TCB == 1 )
20         UBaseType_t        uxCriticalNesting;    /*< Holds the critical section nesting depth for ports that do not maintain their own count in the port layer. */
21     #endif
22 
23     #if ( configUSE_TRACE_FACILITY == 1 )
24         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. */
25         UBaseType_t        uxTaskNumber;        /*< Stores a number specifically for use by third party trace code. */
26     #endif
27 
28     #if ( configUSE_MUTEXES == 1 )
29         UBaseType_t        uxBasePriority;        /*< The priority last assigned to the task - used by the priority inheritance mechanism. */
30         UBaseType_t        uxMutexesHeld;
31     #endif
32 
33     #if ( configUSE_APPLICATION_TASK_TAG == 1 )
34         TaskHookFunction_t pxTaskTag;
35     #endif
36 
37     #if( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )
38         void            *pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
39     #endif
40 
41     #if( configGENERATE_RUN_TIME_STATS == 1 )
42         uint32_t        ulRunTimeCounter;    /*< Stores the amount of time the task has spent in the Running state. */
43     #endif
44 
45     #if ( configUSE_NEWLIB_REENTRANT == 1 )
46         /* Allocate a Newlib reent structure that is specific to this task.
47         Note Newlib support has been included by popular demand, but is not
48         used by the FreeRTOS maintainers themselves.  FreeRTOS is not
49         responsible for resulting newlib operation.  User must be familiar with
50         newlib and must provide system-wide implementations of the necessary
51         stubs. Be warned that (at the time of writing) the current newlib design
52         implements a system-wide malloc() that must be provided with locks. */
53         struct    _reent xNewLib_reent;
54     #endif
55 
56     #if( configUSE_TASK_NOTIFICATIONS == 1 )
57         volatile uint32_t ulNotifiedValue;
58         volatile uint8_t ucNotifyState;
59     #endif
60 
61     /* See the comments above the definition of
62     tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE. */
63     #if( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e731 Macro has been consolidated for readability reasons. */
64         uint8_t    ucStaticallyAllocated;         /*< Set to pdTRUE if the task is a statically allocated to ensure no attempt is made to free the memory. */
65     #endif
66 
67     #if( INCLUDE_xTaskAbortDelay == 1 )
68         uint8_t ucDelayAborted;
69     #endif
70 
71 } tskTCB;

 

(5)任务堆栈

  freertos之所以能正确的恢复一个任务运行就是因为有任务堆栈保驾护航。任务调度器在进行任务切换的时候会将当前任务的上下文保存在此任务的任务堆栈中,等到此任务下次运行的时候就会先用堆栈中保存的值来恢复现场,恢复现场后任务会接着从上次中断的地方开始执行。注意观察在调用xTaskCreate时堆栈大小参数的类型,实际堆栈大小是:用户输入的大小  x 4

 

二、任务相关的API函数

(1)xTaskCreate()

  此函数用来创建一个任务,任务需要RAM来保存与任务有关的状态信息,任务也需要一定的RAM来作为任务堆栈。

  使用此函数会自动的从freertos的堆中分配,默认使用heap4.c内存管理文件,而且configSUPPORT_DYNAMIC_ALLOCATION必须为1

  说明:新建的任务是就绪态的,如果没有比它更高优先级的任务运行,那么此任务会立即进入运行态

 

(2)vTaskDelete()

  删除任务,被删除了的任务不再存在,再也不会进入就绪态。此任务被删除以后此任务之前申请的堆栈和控制块会在空闲任务中被注释掉,

因此调用vTaskDelete删除任务以后必须给空闲任务一定的运行时间。内核分配给任务的内存会在任务删除后自动释放,用户自行分配的内存需要

用户自行释放,否则会导致内存泄漏。

 

(3)vTaskSuspend

  此函数用于将某个任务设置为挂起态,进入挂起态的任务永远不会进入运行态

挂起时起上下文环境及任务通知块完整的保存在堆栈中

 1 void vTaskSuspned(TaskHandle_t TaskToSuspend) 2 3 参数:需要挂起的任务的句柄 4 5 返回:无 

 

(4)vTaskResume

  将一个任务从挂起态恢复为就绪态

1 void vTaskResume(TaskHandle_t xTaskToResume)
2 
3 参数:
4 xTaskResume:要恢复任务的句柄
5 
6 返回:无

 

  

posted @ 2019-02-13 12:25  竹引  阅读(1105)  评论(0编辑  收藏  举报