用了半天时间对FreeRTOS有了一个初步的认识,大概总结一下,其中混杂了系统实现和实际应用方面的问题。
现只是以应用为目的,实现方面待以后进一步研究。
1.FreeRTOS提供的功能包括:任务管理、时间管理、信号量、消息队列、内存管理。与平台有关的文件包含在portable文件夹中,主要是port.c, portmacro.h 两个文件。平台无关的文件主要是:list.c(基本链表结构), queue.c(包括消息队列,信号量的实现), croutine.c,tasks.c(任务管理,时间管理)。
命名协定
RTOS内核与范例程序源代码使用下面的协定:
变量
char类型的变量以c 为前缀
short类型的变量以s 为前缀
long类型的变量以l 为前缀
float类型的变量以f 为前缀
double类型的变量以d 为前缀
枚举变量以e 为前缀
其他类型(如结构体)以x 为前缀
指针有一个额外的前缀p , 例如short类型的指针前缀为ps
无符号类型的变量有一个额外的前缀u , 例如无符号short类型的变量前缀为us
函数
文件内部函数以prv为前缀
API函数以其返回值类型为前缀,按照前面对变量的定义
函数的名字以其所在的文件名开头。如vTaskDelete函数在Task.c文件中定义数据类型
数据类型并不直接在RTOS内核内部引用。相反,每个平台都有其自身的定义方式。例如,char类型定义为portCHAR,short类型定义为portSHORT等。范例程序源代码使用的就是这种符号,但这并不是必须的,你可以在你的程序中使用任何你喜欢的符号。
此外,有两种额外的类型要为每种平台定义。分别是:
portTickType
可配置为16位的无符号类型或32位的无符号类型。参考API文档中的定制部
分获取详细信息。
portBASE_TYPE
为特定体系定义的最有效率的数据类型。
如果portBASE_TYPE定义为char则必须要特别小心的保证用来作为函数返回值的signed char可以为负数,用于指示错误。
2. FreeRTOS内核支持优先级调度算法,每个任务可根据重要程度的不同被赋
予一定的优先级,CPU总是让处于就绪态的、优先级最高的任务先运行。FreeRT0S内核同时支持轮换调度算法,系统允许不同的任务使用相同的优先级,在没有更高优先级任务就绪的情况下,同一优先级的任务共享CPU的使用时间。
3.freertos既可以配置为可抢占内核也可以配置为不可抢占内核。当FreeRTOS 被设置为可剥夺型内核时,处于就绪态的高优先级任务能剥夺低优先级任务的CPU使用权,这样可保证系统满足实时性的要求;当FreeRTOS被设置为不可剥夺型内核时,处于就绪态的高优先级任务只有等当前运行任务主动释放CPU
的使用权后才能获得运行,这样可提高CPU的运行效率。
4.任务管理
系统为每个任务分配一个TCB结构
typedef struct tskTaskControlBlock
{
volatile portSTACK_TYPE *pxTopOfStack;//指向堆栈顶
xListItem xGenericListItem; //通过它将任务连入就绪链表或者延时链表或
者挂起链表中,xListItem包含其TCB指针
xListItem xEventListItem;//通过它把任务连入事件等待链表
unsigned portBASE_TYPE uxPriority;//优先级
portSTACK_TYPE *pxStack; //指向堆栈起始位置
signed portCHAR pcTaskName[ configMAX_TASK_NAME_LEN ]; 。。。。。。。。。。。。。。。。省略一些次要结构
} tskTCB;
系统的全局变量:
static xList pxReadyTasksLists[ configMAX_PRIORITIES ]; 就绪队列
static xList xDelayedTaskList1;
static xList xDelayedTaskList2; 两个延时任务队列
static xList * volatile pxDelayedTaskList;
static xList * volatile pxOverflowDelayedTaskList; 两个延时队列的指针,应该是可互换的。
static xList xPendingReadyList;
static volatile xList xTasksWaitingTermination; 等待结束队列
static volatile unsigned portBASE_TYPE uxTasksDeleted = ( unsigned portBASE_TYPE ) 0; 结束队列中的个数?????
static xList xSuspendedTaskList; 挂起队列
static volatile unsigned portBASE_TYPE uxCurrentNumberOfTasks;记录了当前系统任务的数目
static volatile portTickType xTickCount;是自启动以来系统运行的ticks数static unsigned portBASE_TYPE uxTopUsedPriority;记录当前系统中被使用的最高优先级,
static volatile unsigned portBASE_TYPE uxTopReadyPriority;记录当前系统中处于就绪状态的最高优先级。
static volatile signed portBASE_TYPE xSchedulerRunning ;表示当前调度器是否在运行,也即内核是否启动了
任务建立和删除,挂起和唤醒
5.时间管理
操作系统总是需要个时钟节拍的,这个需要硬件支持。freertos同样需要一个time tick产生器,通常是用处理器的硬件定时器来实现这个功能。(时间片轮转调度中和延时时间控制??)
它周期性的产生定时中断,所谓的时钟节拍管理的核心就是这个定时中断的服务程序。freertos的时钟节拍isr中除去保存现场,灰度现场这些事情外,核心的
工作就是调用vTaskIncrementTick()函数。vTaskIncrementTick()函数主要做两
件事情:维护系统时间(以tick为单位,多少个节拍);处理那些延时的任务,如果延时到期,则唤醒任务。
任务可用的延时函数:vTaskDelay();vTaskDelayUntil();
特别之处在于vTaskDelayUntil()是一个周期性任务可以利用它可以保证一个固
定的(确定的)常数执行频率,而vTaskDelay()无法保证。
6.任务间的通信(详见“FreeR TOS任务间通讯”)
1)当然可以用全局变量的形式通信,但是不安全。
2)队列(xQueueHandle)是FreeRTOS中通信所需的主要数据结构。
3)信号量(xSemaphoreHandle),有二进制信号量,计数信号量和互斥信号量,其都是以队列为基础结构建立。
二进制信号量可以用于中断和任务间的同步。也就是说希望任务随外部中断而执行。即外设给出“数据已就绪”信号,系统中断,任务收到此中断信号接收数据。互斥一般用于都共享资源或数据结构的保护。因为任务调度不能保证数据不被破坏。当一个任务需要访问资源,它必须先获得('take') 令牌;当访问结束后,它必须释放令牌- 允许其他任务能够访问这个资源。(对此还有待进一步实验研究)。
7.系统配置
freeRTOS 配置在:FREERTOS_CONFIG.H 里面,条目如下:
/* 是否配置成抢先先多任务内核,是1的时候,优先级高的任务优先执行。为0任务就没有优先级之说,用时间片轮流执行*/
#define configUSE_PREEMPTION 1
/* IDLE任务的HOOK函数,用于OS功能扩展,需要你自己编相应函数,名字是void vApplicationIdleHook( void ) */
#define configUSE_IDLE_HOOK 0
/* SYSTEM TICK的HOOK函数,用于OS功能扩展,需要你自己编相应函数,名字是void vApplicationTickHook(void ) */
#define configUSE_TICK_HOOK 0
/* 系统CPU频率,单位是Hz */
#define configCPU_CLOCK_HZ 58982400
/* 系统SYSTEM TICK每秒钟的发生次数,数值越大系统反应越快,但是CPU 用在任务切换的开销就越多*/
#define configTICK_RATE_HZ 250
/* 系统任务优先级数。5 说明任务有5级优先度。这个数目越大耗费RAM越多*/
#define configMAX_PRIORITIES 5
/* 系统最小堆栈尺寸,注意128不是128字节,而是128个入栈。比如ARM32位,128个入栈就是512字节*/
#define configMINIMAL_STACK_SIZE 128
/* 系统可用内存。一般设成除了操作系统和你的程序所用RAM外的最大RAM。比如20KRAM你用了2K,系统用了3K,剩下15就是最大HEAP 尺寸。你可以先设小然后看编译结果往大里加*/
#define configTOTAL_HEAP_SIZE 10240
/* 任务的PC名字最大长度,因为函数名编译完了就不见了,所以追踪时不知道哪个名字。16表示16个char */
#define configMAX_TASK_NAME_LEN 16
/* 是否设定成追踪,由PC端TraceCon.exe记录,也可以转到系统显示屏上*/
#define configUSE_TRACE_FACILITY 0
/* 就是SYSTEM TICK的长度,16是16位,如果是16位以下CPU,一般选1;如果是32位系统,一般选0 */
#define configUSE_16_BIT_TICKS 0
/* 简单理解以下就是和IDLE TASK同样优先级的任务执行情况。建议设成1,对系统影响不大*/
#define configIDLE_SHOULD_YIELD 1
/* 是否用MUTEXES。MUTEXES是任务间通讯的一种方式,特别是用于任务共享资源的应用,比如打印机,任务A用的时候就排斥别的任务应用,用完了别的任务才可以应用*/
#define configUSE_MUTEXES 0
/* 确定是否用递归式的MUTEXES */
#define configUSE_RECURSIVE_MUTEXES 0
/* 是否用计数式的SEMAPHORES,SEMAPHORES也是任务间通讯的一种方式*/
#define configUSE_COUNTING_SEMAPHORES 0
/* 是否应用可切换式的API。freeRTOS 同一功能API有多个,有全功能但是需求资源和时间较多的,此项使能后就可以用较简单的API,节省资源和时间,但是应用限制较多*/
#define configUSE_ALTERNATIVE_API 0
/* 此项用于DEBUG,来看是否有栈溢出,需要你自己编相应检查函数void vApplicationStackOverflowHook(xTaskHandle *pxTask, signed portCHAR
*pcTaskName ) */
#define configCHECK_FOR_STACK_OVERFLOW 0
/* 用于DEBUG,登记SEMAPHORESQ和QUEUE的最大个数,需要在任务用应用函数vQueueAddToRegistry()和vQueueUnregisterQueue() */
#define configQUEUE_REGISTRY_SIZE 10
/* 设定可以改变任务优先度*/
#define INCLUDE_vTaskPrioritySet 1
/* 设定可以查询任务优先度*/
#define INCLUDE_uxTaskPriorityGet 1
/* 设定可以删除任务*/
#define INCLUDE_vTaskDelete 1
/* 据说是可以回收删除任务后的资源(RAM等)*/
#define INCLUDE_vTaskCleanUpResources 0
/* 设置可以把任务挂起*/
#define INCLUDE_vTaskSuspend 1
/* 设置可以从中断恢复(比如系统睡眠,由中断唤醒*/
#define INCLUDE_vResumeFromISR 1
/* 设置任务延迟的绝对时间,比如现在4:30,延迟到5:00。时间都是绝对时间*/
#define INCLUDE_vTaskDelayUntil 1
/* 设置任务延时,比如延迟30分钟,相对的时间,现在什么时间,不需要知道*/
#define INCLUDE_vTaskDelay 1
/* 设置取得当前任务分配器的状态*/
#define INCLUDE_xTaskGetSchedulerState 1
/* 设置当前任务是由哪个任务开启的*/
#define INCLUDE_xTaskGetCurrentTaskHandle 1
/* 是否使能这一函数,还数的目的是返回任务执行后任务堆栈的最小未用数量,同样是为防止堆栈溢出*/
#define INCLUDE_uxTaskGetStackHighWaterMark 0
/* 是用用协程。协程公用堆栈,节省RAM,但是没有任务优先级高,也无法和任务通讯*/
#define configUSE_CO_ROUTINES 0
/* 所有协程的最大优先级数,协程优先级永远低于任务。就是系统先执行任务,所有任务执行完了才执行协程。*/
#define configMAX_CO_ROUTINE_PRIORITIES 1
/* 系统内核的中断优先级,中断优先级越低,越不会影响其他中断。一般设成最低*/
#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor]
/* 系统SVC中断优先级,这两项都在在M3和PIC32上应用*/
#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and application]
#endif /* FREERTOS_CONFIG_H */
配置FreeRTOS
FreeRTOS 是高度可配置的。所有的可配置项都在FreeRTOSConfig.h 文件中。每一个Demo 程序中都包含了一个配置好的FreeRTOSConfig.h 文件,可以以Demo程序中的FreeRTOSConfig.h 文件作为模板,在其基础上加以修改。
下面先给出一个典型的FreeRTOSConfig.h 文件,然后再逐项加以说明。
[cpp]view plaincopy
1.#ifndef FREERTOS_CONFIG_H
2.#define FREERTOS_CONFIG_H
3.
4./* Here is a good place to include header files that are required across
5.your application. */
6.#include "something.h"
7.
8.#define configUSE_PREEMPTION 1
9.#define configUSE_IDLE_HOOK 0
10.#define configUSE_TICK_HOOK 0
11.#define configCPU_CLOCK_HZ 58982400
12.#define configTICK_RATE_HZ 250
13.#define configMAX_PRIORITIES 5
14.#define configMINIMAL_STACK_SIZE 128
15.#define configTOTAL_HEAP_SIZE 10240
16.#define configMAX_TASK_NAME_LEN 16
17.#define configUSE_TRACE_FACILITY 0
18.#define configUSE_16_BIT_TICKS 0
19.#define configIDLE_SHOULD_YIELD 1
20.#define configUSE_MUTEXES 0
21.#define configUSE_RECURSIVE_MUTEXES 0
22.#define configUSE_COUNTING_SEMAPHORES 0
23.#define configUSE_ALTERNATIVE_API 0
24.#define configCHECK_FOR_STACK_OVERFLOW 0
25.#define configQUEUE_REGISTRY_SIZE 10
26.#define configGENERATE_RUN_TIME_STATS 0
27.
28.#define configUSE_CO_ROUTINES 0
29.#define configMAX_CO_ROUTINE_PRIORITIES 1
30.
31.#define configUSE_TIMERS 1
32.#define configTIMER_TASK_PRIORITY 3
33.#define configTIMER_QUEUE_LENGTH 10
34.#define configTIMER_TASK_STACK_DEPTH configMINIMAL_STACK_SIZE
35.
36.#define configKERNEL_INTERRUPT_PRIORITY [dependent of processor]
37.#define configMAX_SYSCALL_INTERRUPT_PRIORITY [dependent on processor and
application]
38.
39.#define configASSERT( ( x ) ) if( ( x ) == 0 ) vCallAssert( __
FILE__, __LINE__ )
40.
41.#define INCLUDE_vTaskPrioritySet 1
42.#define INCLUDE_uxTaskPriorityGet 1
43.#define INCLUDE_vTaskDelete 1
44.#define INCLUDE_vTaskSuspend 1
45.#define INCLUDE_xResumeFromISR 1
46.#define INCLUDE_vTaskDelayUntil 1
47.#define INCLUDE_vTaskDelay 1
48.#define INCLUDE_xTaskGetSchedulerState 1
49.#define INCLUDE_xTaskGetCurrentTaskHandle 1
50.#define INCLUDE_uxTaskGetStackHighWaterMark 0
51.#define INCLUDE_xTaskGetIdleTaskHandle 0
52.#define INCLUDE_xTimerGetTimerDaemonTaskHandle 0
53.#define INCLUDE_pcTaskGetTaskName 0
54.
55.#endif /* FREERTOS_CONFIG_H */
可配置的参数
configUSE_PREEMPTION
设为1则采用抢占式调度器, 设为0则采用协作式调度器。
configUSE_IDLE_HOOK
设为1则使能idle hook,设为0则禁止idle hook。
configUSE_TICK_HOOK
设为1则使能tick hook,设为0则禁止tick hook。
configCPU_CLOCK_HZ
设置为MCU 内核的工作频率,以Hz为单位。配置FreeRTOS的时钟Tick时会用到。对不同的移植代码也可能不使用这个参数。如果确定移植代码中不用它就可以注释掉这行。configTICK_RATE_HZ
FreeRTOS的时钟Tick的频率,也就是FreeRTOS用到的定时中断的产生频率。这个频率越高则定时的精度越高,但是由此带来的开销也越大。FreeRTOS 自带的Demo 程序中将TickRate 设为了1000Hz只是用来测试内核的性能的。实际的应用程序应该根据需要改为较小的数值。
当多个任务共用一个优先级时,内核调度器回来每次时钟中断到来后轮转切换任务(round robin),因此,更高的Tick Rate 会导致任务的时间片“time slice”变短。
configMAX_PRIORITIES
程序中可以使用的最大优先级。FreeRTOS 会为每个优先级建立一个链表,因此没多一个优先级都会增加些RAM 的开销。所以,要根据程序中需要多少种不同的优先级来设置这个参数。
configMINIMAL_STACK_SIZE
任务堆栈的最小大小,FreeRTOS根据这个参数来给idle task 分配堆栈空间。这个值如果设置的比实际需要的空间小,会导致程序挂掉。因此,最好不要减小Demo 程序中给出的大小。
configTOTAL_HEAP_SIZE
设置堆空间(Heap)的大小。只有当程序中采用FreeRTOS 提供的内存分配算法时才会用到。
configMAX_TASK_NAME_LEN
任务名称最大的长度,这个长度是以字节为单位的,并且包括最后的NULL 结束字节。configUSE_TRACE_FACILITY
如果程序中需要用到TRACE功能,则需将这个宏设为1。否则设为0。开启TRACE功能后,RAM占用量会增大许多,因此在设为1之前请三思。
configUSE_16_BIT_TICKS
将configUSE_16_BIT_TICKS设为1后portTickType 将被定义为无符号的16位整形类型,configUSE_16_BIT_TICKS 设为0 后portTickType 则被定义为无符号的32位整型。configIDLE_SHOULD_YIELD
这个参数控制那些优先级与idle 任务相同的任务的行为,并且只有当内核被配置为抢占式任务调度时才有实际作用。
内核对具有同样优先级的任务会采用时间片轮转调度算法。当任务的优先级高于idle任务时,各个任务分到的时间片是同样大小的。
但当任务的优先级与idle任务相同时情况就有些不同了。当configIDLE_SHOULD_YIELD 被配置为1时,当任何优先级与idle 任务相同的任务处于就绪态时,idle任务会立刻要求调度器进行任务切换。这会使idle任务占用最少的CPU时间,但同时会使得优先级与idle 任务相同的任务获得的时间片不是同样大小的。因为idle任务会占用某个任务的部分时间片。configUSE_MUTEXES
设为1 则程序中会包含mutex 相关的代码,设为0 则忽略相关的代码。
configUSE_RECURSIVE_MUTEXES
设为1 则程序中会包含recursive mutex 相关的代码,设为0 则忽略相关的代码。configUSE_COUNTING_SEMAPHORES
设为1 则程序中会包含semaphore 相关的代码,设为0 则忽略相关的代码。configUSE_ALTERNATIVE_API
设为1 则程序中会包含一些关于队列操作的额外API函数,设为0 则忽略相关的代码。这些额外提供的API运行速度更快,但是临界区(关中断)的长度也更长。有利也有弊,是否要采用需要用户自己考虑了。
configCHECK_FOR_STACK_OVERFLOW
控制是否检测堆栈溢出。
configQUEUE_REGISTRY_SIZE
队列注册表有两个作用,但是这两个作用都依赖于调试器的支持:
1. 给队列一个名字,方便调试时辨认是哪个队列。
2. 包含调试器需要的特定信息用来定位队列和信号量。
如果你的调试器没有上述功能,哪个这个注册表就毫无用处,还占用的宝贵的RAM空间。configGENERATE_RUN_TIME_STATS
设置是否产生运行时的统计信息,这些信息只对调试有用,会保存在RAM 中,占用RAM 空间。因此,最终程序建议配置成不产生运行时统计信息。
configUSE_CO_ROUTINES
设置为1则包含co-routines 功能,如果包含了co-routines功能,则编译时需包含croutine.c 文件
configMAX_CO_ROUTINE_PRIORITIES
co-routines 可以使用的优先级的数量。
configUSE_TIMERS
设置为1则包含软件定时器功能。
configTIMER_TASK_PRIORITY
设置软件定时器任务的优先级。
configTIMER_QUEUE_LENGTH
设置软件定时器任务中用到的命令队列的长度。
configTIMER_TASK_STACK_DEPTH
设置软件定时器任务需要的任务堆栈大小。
configKERNEL_INTERRUPT_PRIORITY 和
configMAX_SYSCALL_INTERRUPT_PRIORITY
Cortex-M3, PIC24, dsPIC, PIC32, SuperH 和RX600 的移植代码中会使用到configKERNEL_INTERRUPT_PRIORITY.
PIC32, RX600 和Cortex-M系列会使用到
configMAX_SYSCALL_INTERRUPT_PRIORITY
configKERNEL_INTERRUPT_PRIORITY应该被设为最低优先级。
对那些只定义了configKERNEL_INTERRUPT_PRIORITY 的系统:
configKERNEL_INTERRUPT_PRIORITY决定了FreeRTOS内核使用的优先级。
所有调用API函数的中断的优先级都应设为这个值,不调用API函数的中断可以设为更高的优先级。
对那些定义了configKERNEL_INTERRUPT_PRIORITY 和
configMAX_SYSCALL_INTERRUPT_PRIORITY的系统:
configKERNEL_INTERRUPT_PRIORITY决定了FreeRTOS内核使用的优先级。configMAX_SYSCALL_INTERRUPT_PRIORITY决定了可以调用API函数的中断的最高优先级。高于这个值的中断处理函数不能调用任何API 函数。
configASSERT
宏configASSERT()的作用类似C语言标准库中的宏assert(),configASSERT() 可以帮助调试,但是定义了configASSERT()后会增加程序代码,也会使程序变慢。
以INCLUDE 开头参数
以'INCLUDE' 开头的宏允许我们将部分不需要的API 函数排除在编译生成的代码之外。这可以使内核代码占用更少的ROM 和RAM。
比如,如果代码中需要用到vTaskDelete 函数则这样写:
#defineINCLUDE_vTaskDelete 1
如果不需要,则这样写:
#defineINCLUDE_vTaskDelete 0
一、任务创建
1. xTaskCreate
task. h
portBASE_TYPE xTaskCreate(
pdTASK_CODE pvTaskCode,
const portCHAR * const pcName,
unsigned portSHORT usStackDepth,
void *pvParameters,
unsigned portBASE_TYPE uxPriority,
xTaskHandle *pvCreatedTask
);
创建新的任务并添加到任务队列中,准备运行
Parameters:
返回: pdPASS 是如果任务成功创建并且添加到就绪列中,另外错误代码在projdefs. H文件定义
2. vTaskDelete
task. h
void vTaskDelete( xTaskHandle pxTask );
INCLUDE_vTaskDelete必须定义为1,这个函数才能可用。查看配置部分获得更多信息。
从RTOS实时内核管理中移除任务。要删除的任务将从就绪,封锁,挂起,事件列表中移除。
注意:空闲任务负责释放内核分配给已删除任务的内存。因此,如果应用程序调用了vTaskDelete (),微控制器执行时间,空闲任务不假死是很重要的。内存分配给任务的代码不会自动释放,应该在任务删除之前。
参数:
vTaskDelay() 有关,而vTaskDelayUntil() 指定是一个绝对时间(任务希望开
启) vTaskDelay()中断任务从调用这个函数开始到指定时间。很难使用vTaskDelay()自身来产生一个固定的执行频率,因为:随着调用vTaskDelay()一个任务开启的时间和任务下一次调用vTaskDelay()的时间,这两者之间可能不是固定的【任务可能采取不同方式,可能通过调用,可能来自中断,或者优先取得每次任务执行的时间】。而vTaskDelay()指定的时间与调用这个函数相关,vTaskDelayUntil() 指定的是绝对时间(任务希望开启的)。
应该注意:vTaskDelayUntil() 如果指定的苏醒时间使用完,将立即返回。因此,一个使用vTaskDelayUntil() 来周期性的执行的任务,如果执行周期因为任何原因(例如任务是临时为悬挂状态)暂停而导致任务错过一个或多个执行周期,那么需要重新计算苏醒时间。通过检查像pxPreviousWakeTime可变的参数来组织当前时间片计数。然而在大多数使用中并不是必须的。产量 portTICK_RATE_MS 用来计算时间片频率的实时时间- 按照一个时间片周期。
参数:
Returns:
pxTask的优先级
6. vTaskPrioritySet
task. h
void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority );
设置INCLUDE_vTaskPrioritySet为1,才能使用此函数。参考配置获得更多信息。设置任务的优先级。如果设置的优先级高于当前执行任务的优先级,则上下文切换将在此函数返回之前发生。
参数:
唤醒挂起的任务。必须是调用 vTaskSuspend () 后挂起的任务,才有可能通过调用 vTaskResume ()重新运行。
Parameters:
Returns:
xTaskCallApplicationTaskHook
task. H
#define traceTASK_SWITCHED_OUT() xTaskCallApplicationTaskHook( pxCurrentTCB, 0 )
portBASE_TYPE xTaskCallApplicationTaskHook( xTaskHandle xTask, void *pvParamete r );
configUSE_APPLICATION_TASK_TAG必须设置为1,这个函数才能使用。参考配置获得更多信息。
每个任务可以分配一个标签值。正常情况下,这个值仅用于应用程序,内核并不存储。然而,可以使用标签赋值给钩子(或回调)函数给任务——钩子函数将通过调用xTaskCallApplicationTaskHook()执行。每个任务定义自己的返回值,或者仅仅定义一个返回值。尽管可以使用第一个函数参数来调用任务中的钩子函数,最常见的使用是任务钩子函数——描述钩子宏,像每个如下的例子。任务钩子函数必须使用pdTASK_HOOK_CODE 类型,传递void *参数,和返回portBASE_TYPE类型的值。Void *参数用来传递给钩子函数的任何信息。
参数:
三、内核控制
11. vTaskStartScheduler