xTaskCreate()动态方式创建任务
xTaskCreateStatic()静态方式创建任务
xTasDelete()删除任务
动态创建任务函数
BaseType_t xTaskCreate
(
TaskFunction_t pxTaskCode, /* 指向任务函数的指针 */
const char * const pcName, /* 任务名字,最大长度configMAX_TASK_NAME_LEN */
const configSTACK_DEPTH_TYPE usStackDepth, /* 任务堆栈大小,注意字为单位 */
void * const pvParameters, /* 传递给任务函数的参数 */
UBaseType_t uxPriority, /* 任务优先级,范围:0 ~ configMAX_PRIORITIES - 1 */
TaskHandle_t * const pxCreatedTask /* 任务句柄,就是任务的任务控制块 */
)
pdPASS 任务创建成功
errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY 任务创建失败
实现动态创建任务流程
1.将configSUPPORT_DYNAMIC_ALLOCATION配置为1
2.定义函数入口参数
3.编写任务函数
此函数创建的任务会立刻进入就绪态,由任务调度器调度运行
动态创建任务函数内部实现
1、申请堆栈内存&任务控制块内存
2、TCB结构体成员赋值
3、添加新任务到就绪列表中
任务控制快结构体成员的基本介绍
typedef struct tskTaskControlBlock
{
volatile StackType_t * pxTopOfStack; /* 任务栈栈顶,必须为TCB的第一个成员 */
ListItem_t xStateListItem; /* 任务状态列表项 */
ListItem_t xEventListItem; /* 任务事件列表项 */
UBaseType_t uxPriority; /* 任务优先级,数值越大,优先级越大 */
StackType_t * pxStack; /* 任务栈起始地址 */
char pcTaskName[ configMAX_TASK_NAME_LEN ]; /* 任务名字 */
…
省略很多条件编译的成员
} tskTCB;
任务栈栈顶,在任务切换时的任务上下文保存、任务恢复息息相关
注意:每个任务都有属于自己的任务控制块,类似身份证
静态创建任务函数
TaskHandle_t xTaskCreateStatic
(
TaskFunction_t pxTaskCode, /* 指向任务函数的指针 */
const char * const pcName, /* 任务函数名 */
const uint32_t ulStackDepth, /* 任务堆栈大小注意字为单位 */
void * const pvParameters, /* 传递的任务函数参数 */
UBaseType_t uxPriority, /* 任务优先级 */
StackType_t * const puxStackBuffer, /* 任务堆栈,一般为数组,由用户分配 */
StaticTask_t * const pxTaskBuffer /* 任务控制块指针,由用户分配 */
);
NULL:用户没有提供相应的内存,任务创建失败
其他值:任务句柄,任务创建成功
静态创建任务函数
1、需将宏configSUPPORT_STATIC_ALLOCATION 配置为 1
2、定义空闲任务&定时器任务的任务堆栈及TCB
3、实现两个接口函数 vApplicationGetIdleTaskMemory( ) vApplicationGetTimerTaskMemory ( )
4、定义函数入口参数
5、编写任务函数
此函数创建的任务会立刻进入就绪态,由任务调度器调度运行
静态创建内部实现
1、TCB结构体成员赋值
2、添加新任务到就绪列表中
任务删除函数
void vTaskDelete(TaskHandled_t xTaskToDelete);
形参 描述
xTaskToDelete 待删除任务的任务句柄
用于删除已被创建的任务
被删除的任务将从就绪态任务列表、阻塞态任务列表、挂起态任务列表和事件列表中移除
注意
1、当传入的参数为NULL,则代表删除任务自身(当前正在运行的任务)
2、空闲任务会负责释放被删除任务中由系统分配的内存,但是由用户在任务删除前申请的内存, 则需要由用户在任务被删除前提前释放,否则将导致内存泄露
删除任务流程
1.删除函数INCLUDE_vTaskDelete配置为1
2.入口参数输入需要删除的任务句柄(NULL代表删除本身)
删除任务实现过程
1、获取所要删除任务的控制块 通过传入的任务句柄,判断所需要删除哪个任务,NULL代表删除自身
2、将被删除任务,移除所在列表 将该任务在所在列表中移除,包括:就绪、阻塞、挂起、事件等列表
3、判断所需要删除的任务 (1) 删除任务自身,需先添加到等待删除列表,内存释放将在空闲任务执行 (2)删除其他任务,释放内存,任务数量--
4、更新下个任务的阻塞时间 更新下一个任务的阻塞超时时间,以防被删除的任务就是下一个阻塞超时的任务
vTaskSuspend() 挂起任务
vTaskResume() 恢复被挂起的任务
vTaskResumeFromlSR() 在中断中恢复被挂起的任务
任务挂起函数
void vTaskSuspend(TaskHandle_t xTaskToSuspend)
形参 描述
xTaskToSuspend 待挂起任务的任务句柄
此函数用于挂起任务,使用时需将宏 INCLUDE_vTaskSuspend 配置为 1。
无论优先级如何,被挂起的任务都将不再被执行,直到任务被恢复 。
注意:当传入的参数为NULL,则代表挂起任务自身(当前正在运行的任务)
任务恢复函数介绍(任务中恢复)
任务中恢复被挂起函数:void vTaskResume(TaskHandle_t xTaskToResume)
形参 描述
xTaskToResume 待恢复任务的任务句柄
使用该函数注意宏:INCLUDE_vTaskSuspend必须定义为 1
注意:任务无论被 vTaskSuspend() 挂起多少次,只需在任务中调用 vTakResume() 恢复一次,就可以继续运行。且被恢复的任务会进入就绪态!
任务恢复函数介绍(中断中恢复)
中断中恢复被挂起函数: BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)
形参 描述
xTaskToResume 待恢复任务的句柄
返回值 描述
pdTRUE 任务恢复后需要进行任务切换
pdFALSE 任务恢复后不需要进行任务切换
使用该函数注意宏:INCLUDE_vTaskSuspend 和 INCLUDE_xTaskResumeFromISR 必须定义为 1
该函数专用于中断服务函数中,用于解挂被挂起任务
注意:中断服务程序中要调用freeRTOS的API函数则中断优先级不能高于FreeRTOS所管理的最高优先级(任务是数字越大优先级越来高,中断(nvic)相反)
BASEPRI:屏蔽优先级低于某一个阈值的中断,当设置为0时,则不关闭任何中断
关中断程序示例
#define portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm
{
msr basepri, ulNewBASEPRI
dsb
isb
}
}
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 /* FreeRTOS可管理的最高中断优先级 */
BASEPRI:屏蔽优先级低于某一个阈值的中断,当设置为0时,则不关闭任何中断
开中断程序示例:
#define portENABLE_INTERRUPTS() vPortSetBASEPRI( 0 )
static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )
{
__asm
{
msr basepri, ulBASEPRI
}
}
临界段代码保护函数
tasENTER_CRITICAL() 任务级进入临界段
taskEXIT_CRITICAL() 任务级退出临界段
taskENTER_CRITICAL_FROM_ISR() 中断级进入临界段
taskEXIT_CRITICAL_FROM_ISR() 中断级退出临界段
任务调度器的挂起和恢复
vTaskSuspendAll() 挂起任务调度器
vTaskResumeAll() 恢复任务调度器
1、与临界区不一样的是,挂起任务调度器,未关闭中断;
2、它仅仅是防止了任务之间的资源争夺,中断照样可以直接响应;
3、挂起调度器的方式,适用于临界区位于任务与任务之间;既不用去延时中断,又可以做到临界区的安全
列表结构示意图
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE /* 校验值 */
volatile UBaseType_t uxNumberOfItems; /* 列表中的列表项数量 */
ListItem_t * configLIST_VOLATILE pxIndex /* 用于遍历列表项的指针 */
MiniListItem_t xListEnd /* 末尾列表项 */
listSECOND_LIST_INTEGRITY_CHECK_VALUE /* 校验值 */
} List_t;
1、在该结构体中, 包含了两个宏,这两个宏是确定的已知常量, FreeRTOS通过检查这两个常量的值,
来判断列表的数据在程序运行过程中,是否遭到破坏 ,该功能一般用于调试, 默认是不开启的
2、成员uxNumberOfItems,用于记录列表中列表项的个数(不包含 xListEnd)
3、成员 pxIndex 用于指向列表中的某个列表项,一般用于遍历列表中的所有列表项
4、成员变量 xListEnd 是一个迷你列表项,排在最末尾
列表项
列表项是列表中用于存放数据的地方,在 list.h 文件中,有列表项的相关结构体定义:
struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /* 用于检测列表项的数据完整性 */
configLIST_VOLATILE TickType_t xItemValue /* 列表项的值 */
struct xLIST_ITEM * configLIST_VOLATILE pxNext /* 下一个列表项 */
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious /* 上一个列表项 */
void * pvOwner /* 列表项的拥有者 */
struct xLIST * configLIST_VOLATILE pxContainer; /* 列表项所在列表 */
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /* 用于检测列表项的数据完整性 */
};
typedef struct xLIST_ITEM ListItem_t;
迷你列表像
迷你列表项也是列表项,但迷你列表项仅用于标记列表的末尾和挂载其他插入列表中的列表项
struct xMINI_LIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /* 用于检测数据完整性 */
configLIST_VOLATILE TickType_t xItemValue; /* 列表项的值 */
struct xLIST_ITEM * configLIST_VOLATILE pxNext; /* 上一个列表项 */
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /* 下一个列表项 */
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;
1、成员变量 xItemValue 为列表项的值,这个值多用于按升序对列表中的列表项进行排序
2、成员变量 pxNext 和 pxPrevious 分别用于指向列表中列表项的下一个列表项和上一个列表项
3、迷你列表项只用于标记列表的末尾和挂载其他插入列表中的列表项,因此不需要成员变量 pxOwner 和 pxContainer,以节省内存开销
列表相关API函数介绍(掌握)
vListInitialise() 初始化列表
vListInitialiseItem() 初始化列表项
vListInsertEnd() 列表末尾插入列表项
vListInsert() 列表插入列表项
uxListRemove() 列表移除列表项
延时函数介绍
vTaskDelay() 相对延时
xTaskDelayUntil() 绝对延时
相对延时:指每次延时都是从执行函数vTaskDelay()开始,直到延时指定的时间结束
绝对延时:指将整个任务的运行周期看成一个整体,适用于需要按照一定频率运行的任务
队列简介
写队列:
xQueueSend( )
{
// 进入临界区(关中断)
写队列实际操作
// 退出临界区(开中断
}
读队列:
xQueueReceive( )
{
// 进入临界区(关中断)
读队列实际操作
// 退出临界区(开中断)
}
队列结构体介绍
typedef struct QueueDefinition
{
int8_t * pcHead /* 存储区域的起始地址 */
int8_t * pcWriteTo; /* 下一个写入的位置 */
union
{
QueuePointers_t xQueue;
SemaphoreData_t xSemaphore;
} u ;
List_t xTasksWaitingToSend; /* 等待发送列表 */
List_t xTasksWaitingToReceive; /* 等待接收列表 */
volatile UBaseType_t uxMessagesWaiting; /* 非空闲队列项目的数量 */
UBaseType_t uxLength; /* 队列长度 */
UBaseType_t uxItemSize; /* 队列项目的大小 */
volatile int8_t cRxLock; /* 读取上锁计数器 */
volatile int8_t cTxLock; /* 写入上锁计数器 */
/* 其他的一些条件编译 */
} xQUEUE;
当用于队列使用时:
typedef struct QueuePointers
{
int8_t * pcTail; /* 存储区的结束地址 */
int8_t * pcReadFrom; /* 最后一个读取队列的地址 */
} QueuePointers_t;
当用于互斥信号量和递归互斥信号量时 :
typedef struct SemaphoreData
{
TaskHandle_t xMutexHolder; /* 互斥信号量持有者 */
UBaseType_t uxRecursiveCallCount; /* 递归互斥信号量的获取计数器 */
} SemaphoreData_t;
队列相关API函数介绍
使用队列的主要流程:创建队列 写队列 读队列。
xQueueCreate() 动态方式创建队列
xQueueCreateStatic() 静态方式创建队列
#define xQueueCreate ( uxQueueLength, uxItemSize ) \
xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), (queueQUEUE_TYPE_BASE ))
此函数用于使用动态方式创建队列,队列所需的内存空间由 FreeRTOS 从 FreeRTOS 管理的堆中分配
uxQueueLength 队列长度
uxItemSize 队列项目的大小
NULL 队列创建失败
其他值 队列创建成功,返回队列句柄
前面说 FreeRTOS 基于队列实现了多种功能,每一种功能对应一种队列类型,队列类型的 queue.h 文件中有定义:
#define queueQUEUE_TYPE_BASE ( ( uint8_t ) 0U ) /* 队列 */
#define queueQUEUE_TYPE_SET ( ( uint8_t ) 0U ) /* 队列集 */
#define queueQUEUE_TYPE_MUTEX ( ( uint8_t ) 1U ) /* 互斥信号量 */
#define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( ( uint8_t ) 2U ) /* 计数型信号量 */
#define queueQUEUE_TYPE_BINARY_SEMAPHORE ( ( uint8_t ) 3U ) /* 二值信号量 */
#define queueQUEUE_TYPE_RECURSIVE_MUTEX ( ( uint8_t ) 4U ) /* 递归互斥信号量 */
往队列写入消息API函数:
xQueueSend() 往队列的尾部写入消息
xQueueSendToBack() 同 xQueueSend()
xQueueSendToFront() 往队列的头部写入消息
xQueueOverwrite() 覆写队列消息(只用于队列长度为 1 的情况)
xQueueSendFromISR() 在中断中往队列的尾部写入消息
xQueueSendToBackFromISR() 同 xQueueSendFromISR()
xQueueSendToFrontFromISR()在中断中往队列的头部写入消息
xQueueOverwriteFromISR() 在中断中覆写队列消息(只用于队列长度为 1 的情况)
队列写入消息
#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) \
xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
#define xQueueSendToBack( xQueue, pvItemToQueue, xTicksToWait ) \
xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
#define xQueueSendToFront( xQueue, pvItemToQueue, xTicksToWait ) \
xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )
#define xQueueOverwrite( xQueue, pvItemToQueue ) \
xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), 0, queueOVERWRITE )
可以看到这几个写入函数调用的是同一个函数xQueueGenericSend( ),只是指定了不同的写入位置!
队列一共有 3 种写入位置 :
#define queueSEND_TO_BACK ( ( BaseType_t ) 0 ) /* 写入队列尾部 */
#define queueSEND_TO_FRONT ( ( BaseType_t ) 1 ) /* 写入队列头部 */
#define queueOVERWRITE ( ( BaseType_t ) 2 ) /* 覆写队列*/
注意:覆写方式写入队列,只有在队列的队列长度为 1 时,才能够使用
往队列写入消息函数入口参数解析:
BaseType_t xQueueGenericSend( QueueHandle_t xQueue,
const void * const pvItemToQueue,
TickType_t xTicksToWait,
const BaseType_t xCopyPosition );
xQueue 待写入的队列
pvItemToQueue 待写入消息
xTicksToWait 阻塞超时时间
xCopyPosition 写入的位置
pdTRUE
errQUEUE_FULL 队列写入失败
从队列读取消息API函数:
xQueueReceive() 从队列头部读取消息,并删除消息
xQueuePeek() 从队列头部读取消息
xQueueReceiveFromISR() 在中断中从队列头部读取消息,并删除消息
xQueuePeekFromISR() 在中断中从队列头部读取消息
BaseType_t xQueueReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait )
此函数用于在任务中,从队列中读取消息,并且消息读取成功后,会将消息从队列中移除。
xQueue 待读取的队列
pvBuffer 信息读取缓冲区
xTicksToWait 阻塞超时时间
pdTRUE 读取成功
pdFALSE 读取失败
BaseType_t xQueuePeek( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait )
此函数用于在任务中,从队列中读取消息, 但与函数 xQueueReceive()不同,此函数在成功读取消息后,并不会移除已读取的消息!
xQueue 待读取的队列
pvBuffer 信息读取缓冲区
xTicksToWait 阻塞超时时间
pdTRUE 读取成功
pdFALSE 读取失败
二值信号量相关API函数
使用二值信号量的过程:创建二值信号量 释放二值信号量 获取二值信号量
xSemaphoreCreateBinary() 使用动态方式创建二值信号量
xSemaphoreCreateBinaryStatic() 使用静态方式创建二值信号量
xSemaphoreGive() 释放信号量
xSemaphoreGiveFromISR() 在中断中释放信号量
xSemaphoreTake() 获取信号量
xSemaphoreTakeFromISR() 在中断中获取信号量
创建二值信号量函数:SemaphoreHandle_t xSemaphoreCreateBinary( void )
define xSemaphoreCreateBinary( ) \
xQueueGenericCreate( 1 , semSEMAPHORE_QUEUE_ITEM_LENGTH ,
#define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( uint8_t ) 0U )
#define queueQUEUE_TYPE_BASE ( ( uint8_t ) 0U ) /* 队列 */
#define queueQUEUE_TYPE_SET ( ( uint8_t ) 0U ) /* 队列集 */
#define queueQUEUE_TYPE_MUTEX ( ( uint8_t ) 1U ) /* 互斥信号量 */
#define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( ( uint8_t ) 2U ) /* 计数型信号量 */
#define queueQUEUE_TYPE_BINARY_SEMAPHORE ( ( uint8_t ) 3U ) /* 二值信号量 */
#define queueQUEUE_TYPE_RECURSIVE_MUTEX ( ( uint8_t ) 4U ) /* 递归互斥信号量
NULL 创建失败
其他值 创建成功返回二值信号量的句柄
释放二值信号量函数:BaseType_t xSemaphoreGive( xSemaphore )
#define xSemaphoreGive ( xSemaphore ) \
xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ) , NULL , semGIVE_BLOCK_TIME ,
#define semGIVE_BLOCK_TIME ( ( TickType_t ) 0U
xSemaphore 要释放的信号量句柄
pdPASS 释放信号量成功
errQUEUE_FULL 释放信号量失败
获取二值信号量函数:BaseType_t xSemaphoreTake( xSemaphore, xBlockTime )
xSemaphore 要获取的信号量句柄
xBlockTime 阻塞时间
pdTRUE 获取信号量成功
pdFALSE 超时,获取信号量失败
计数型信号量相关API函数
使用计数型信号量的过程:创建计数型信号量 释放信号量 获取信号量
xSemaphoreCreateCounting() 使用动态方法创建计数型信号量
xSemaphoreCreateCountingStatic() 使用静态方法创建计数型信号量
uxSemaphoreGetCount() 获取信号量的计数值
计数型信号量的释放和获取与二值信号量相同 !
计数型信号量创建API函数
#define xSemaphoreCreateCounting( uxMaxCount , uxInitialCount ) \
xQueueCreateCountingSemaphore( ( uxMaxCount ) , ( uxInitialCount ) )
此函数用于创建一个计数型信号量 。
uxMaxCount 计数值的最大值限定
uxInitialCount 计数值的初始值
NULL 创建失败
其他值 创建成功返回计数型信号量的句柄
#define uxSemaphoreGetCount( xSemaphore ) \
uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) )
此函数用于获取信号量当前计数值大小
xSemaphore 信号量句柄
整数 当前信号量的计数值大小
互斥信号量相关API函数
使用互斥信号量:首先将宏configUSE_MUTEXES置一
使用流程:创建互斥信号量 (task)获取信号量 (give)释放信号量
创建互斥信号量函数:
xSemaphoreCreateMutex() 使用动态方法创建互斥信号量
xSemaphoreCreateMutexStatic() 使用静态方法创建互斥信号量
互斥信号量的释放和获取函数与二值信号量相同 !只不过互斥信号量不支持中断中调用
注意:创建互斥信号量时,会主动释放一次信号量
队列集相关API函数介绍
xQueueCreateSet() 创建队列集
xQueueAddToSet() 队列添加到队列集中
xQueueRemoveFromSet() 从队列集中移除队列
xQueueSelectFromSet() 获取队列集中有有效消息的队列
xQueueSelectFromSetFromISR() 在中断中获取队列集中有有效消息的队列
QueueSetHandle_t xQueueCreateSet( const UBaseType_t uxEventQueueLength );
此函数用于创建队列集
uxEventQueueLength 队列集可容纳的队列数量
NULL 队列集创建失败
其他值 队列集创建成功,返回队列集句柄
BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore ,
QueueSetHandle_t xQueueSet );
此函数用于往队列集中添加队列,要注意的时,队列在被添加到队列集之前,队列中不能有有效的消息
xQueueOrSemaphore 待添加的队列句柄
xQueueSet 队列集
pdPASS 队列集添加队列成功
pdFAIL 队列集添加队列失败
BaseType_t xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore ,
QueueSetHandle_t xQueueSet );
函数用于从队列集中移除队列, 要注意的是,队列在从队列集移除之前,必须没有有效的消息
xQueueOrSemaphore 待移除的队列句柄
xQueueSet 队列集
pdPASS 队列集移除队列成功
pdFAIL 队列集移除队列失败
QueueSetMemberHandle_t xQueueSelectFromSet( QueueSetHandle_t xQueueSet,
此函数用于在任务中获取队列集中有有效消息的队列
xQueueSet 队列集
xTicksToWait 阻塞超时时间
NULL 获取消息失败
其他值 获取到消息的队列句柄
队列集使用流程
1、启用队列集功能需要将宏configUSE_QUEUE_SETS 配置为 1
2、创建队列集
3、创建队列或信号量
4、往队列集中添加队列或信号量
5、往队列发送信息或释放信号量
6、获取队列集的消息
任务通知值的更新方式:
不覆盖接受任务的通知值
覆盖接受任务的通知值
更新接受任务通知值的一个或多个bit
增加接受任务的通知值
只要合理,灵活的利用任务通知的特点,可以在一些场合中替代队列、信号量、事件标志组!
任务通知值和通知状态
任务通知值和通知状态
typedef struct tskTaskControlBlock
{
… …
#if ( configUSE_TASK_NOTIFICATIONS == 1 )
volatile uint32_t ulNotifiedValue [ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
volatile uint8_t ucNotifyState [ configTASK_NOTIFICATION_ARRAY_ENTRIES ];
endif
… …
} tskTCB;
#define configTASK_NOTIFICATION_ARRAY_ENTRIES 1 /* 定义任务通知数组的大小, 默认: 1 */
一个是 uint32_t 类型,用来表示通知值
一个是 uint8_t 类型,用来表示通知状态
任务通知状态
其中任务通知状态共有3种取值:
#define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 ) /* 任务未等待通知 */
#define taskWAITING_NOTIFICATION ( ( uint8_t ) 1 ) /* 任务在等待通知 */
#define taskNOTIFICATION_RECEIVED ( ( uint8_t ) 2 ) /* 任务在等待接收 */
任务未等待通知 :任务通知默认的初始化状态
等待通知:接收方已经准备好了(调用了接收任务通知函数),等待发送方给个通知
等待接收:发送方已经发送出去(调用了发送任务通知函数),等待接收方接收
任务通知相关API函数介绍
任务通知API函数主要有两类:①发送通知 ,②接收通知。
注意:发送通知API函数可以用于任务和中断服务函数中;接收通知API函数只能用在任务中。
发送通知相关API函数:
xTaskNotify()发送通知,带有通知值
xTaskNotifyAndQuery() 发送通知,带有通知值并且保留接收任务的原通知值
xTaskNotifyGive()发送通知,不带通知值
xTaskNotifyFromISR()在中断中发送任务通知
xTaskNotifyAndQueryFromISR() 在中断中发送任务通知
vTaskNotifyGiveFromISR()在中断中发送任务通知
define xTaskNotifyAndQuery( xTaskToNotify , ulValue , eAction , pulPreviousNotifyValue ) \
xTaskGenericNotify( ( xTaskToNotify ),
( tskDEFAULT_INDEX_TO_NOTIFY ),
( ulValue ),
( eAction ),
( pulPreviousNotifyValue ) )
#define xTaskNotify ( xTaskToNotify , ulValue , eAction ) \
xTaskGenericNotify( ( xTaskToNotify ) , ( tskDEFAULT_INDEX_TO_NOTIFY ) , ( ulValue ) , ( eAction ) , NULL
#define xTaskNotifyGive( xTaskToNotify ) \
xTaskGenericNotify( ( xTaskToNotify ) , ( tskDEFAULT_INDEX_TO_NOTIFY ) , ( 0 ) , eIncrement , NULL )
BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify,
UBaseType_t uxIndexToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t * pulPreviousNotificationValue )
xTaskToNotify 接收任务通知的任务句柄
uxIndexToNotify任务的指定通知(任务通知相关数组成员)
ulValue 任务通知值
eAction通知方式(通知值更新方式)
pulPreviousNotificationValue 用于保存更新前的任务通知值(为NULL则不保存)
任务通知方式共有以下几种:
typedef enum
{
eNoAction = 0, /* 无操作 */
eSetBits /* 更新指定bit */
eIncrement /* 通知值加一 */
eSetValueWithOverwrite /* 覆写的方式更新通知值 */
eSetValueWithoutOverwrite /* 不覆写通知值 */
} eNotifyAction;
接收通知相关API函数:
ulTaskNotifyTake()获取任务通知,可以设置在退出此函数的时候将任务通知值清零或者减一。
当任务通知用作二值信号量或者计数信号量的时候,使用此函数来获取信号量。
xTaskNotifyWait()获取任务通知,比 ulTaskNotifyTak()更为复杂,可获取通知值和清除通知值的指定位
总结
当任务通知用作于信号量时,使用函数获取信号量:ulTaskNotifyTake()
当任务通知用作于事件标志组或队列时,使用此函数来获取: xTaskNotifyWait()
#define ulTaskNotifyTake( xClearCountOnExit , xTicksToWait ) \
ulTaskGenericNotifyTake( ( tskDEFAULT_INDEX_TO_NOTIFY ), \
( xClearCountOnExit ), \
( xTicksToWait ) )
此函数用于接收任务通知值,可以设置在退出此函数的时候将任务通知值清零或者减一
uxIndexToWaitOn任务的指定通知(任务通知相关数组成员)
xClearCountOnExit指定在成功接收通知后,将通知值清零或减 1,
pdTRUE:把通知值清零;pdFALSE:把通知值减一
xTicksToWait 阻塞等待任务通知值的最大时间
0 接收失败
非 0 接收成功,返回任务通知的通知值
#define xTaskNotifyWait( ulBitsToClearOnEntry, \
ulBitsToClearOnExit, \
pulNotificationValue, \
xTicksToWait) \
xTaskGenericNotifyWait( tskDEFAULT_INDEX_TO_NOTIFY, \
( ulBitsToClearOnEntry ), \
( ulBitsToClearOnExit ), \
( pulNotificationValue ), \
( xTicksToWait ) )
BaseType_t xTaskGenericNotifyWait( UBaseType_t uxIndexToWaitOn,
uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t * pulNotificationValue,
TickType_t xTicksToWait );
uxIndexToWaitOn 任务的指定通知(任务通知相关数组成员)
ulBitesToClearOnEntry等待前清零指定任务通知值的比特位(旧值对应bit清0)
ulBitesToClearOnExit 成功等待后清零指定的任务通知值比特位(新值对应bit清0
pulNotificationValue用来取出通知值(如果不需要取出,可设为NULL)
xTicksToWait 阻塞等待任务通知值的最大时间
pdTRUE 等待任务通知成功
pdFALSE 等待任务通知失败
软件定时器的相关配置
当FreeRTOS 的配置项 configUSE_TIMERS 设置为1,在启动任务调度器时,会自动创建软件定时器的服务/守护任务prvTimerTask( ) ;
软件定时器服务任务的优先级为 configTIMER_TASK_PRIORITY = 31;
定时器的命令队列长度为 configTIMER_QUEUE_LENGTH = 5 ;
注意:软件定时器的超时回调函数是在软件定时器服务任务中被调用的,服务任务不是专为某个定时器服务的,它还要处理其他定时器。
所以,定时器的回调函数不要影响其他“人”:
1、回调函数要尽快实行,不能进入阻塞状态,即不能调用那些会阻塞任务的 API 函数,如:vTaskDelay()
2、访问队列或者信号量的非零阻塞时间的 API 函数也不能调用。
软件定时器结构体成员介绍
typedef struct
{
const char * pcTimerName /* 软件定时器名字 */
ListItem_t xTimerListItem /* 软件定时器列表项 */
TickType_t xTimerPeriodInTicks; /* 软件定时器的周期 */
void * pvTimerID /* 软件定时器的ID */
TimerCallbackFunction_t pxCallbackFunction; /* 软件定时器的回调函数 */
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxTimerNumber /* 软件定时器的编号,调试用 */
#endif
uint8_t ucStatus; /* 软件定时器的状态 */
} xTIMER;
FreeRTOS软件定时器相关API函数
xTimerCreate() 动态方式创建软件定时器
xTimerCreateStatic() 静态方式创建软件定时器
xTimerStart() 开启软件定时器定时
xTimerStartFromISR()在中断中开启软件定时器定时
xTimerStop() 停止软件定时器定时
xTimerStopFromISR() 在中断中停止软件定时器定时
xTimerReset() 复位软件定时器定时
xTimerResetFromISR() 中断中复位软件定时器定时
xTimerChangePeriod() 更改软件定时器的定时超时时间
xTimerChangePeriodFromISR() 在中断中更改定时超时时间
创建软件定时器API函数
TimerHandle_t xTimerCreate( const char * const pcTimerName,
const TickType_t xTimerPeriodInTicks,
const UBaseType_t uxAutoReload,
void * const pvTimerID,
TimerCallbackFunction_t pxCallbackFunction );
pcTimerName软件定时器名
xTimerPeriodInTicks定时超时时间,单位:系统时钟节拍
uxAutoReload定时器模式, pdTRUE:周期定时器, pdFALSE:单次定时器
pvTimerID 软件定时器 ID,用于多个软件定时器公用一个超时回调函数
pxCallbackFunction 软件定时器超时回调函数
NULL 软件定时器创建失败
其他值 软件定时器创建成功,返回其句柄
开启软件定时器API函数
BaseType_t xTimerStart( TimerHandle_t xTimer,
const TickType_t xTicksToWait );
xTimer 待开启的软件定时器的句柄
xTickToWait 发送命令到软件定时器命令队列的最大等待时间
pdPASS软件定时器开启成功
pdFAIL软件定时器开启失败
停止软件定时器API函数
BaseType_t xTimerStop( TimerHandle_t xTimer,
const TickType_t xTicksToWait);
xTimer待停止的软件定时器的句柄
xTickToWait 发送命令到软件定时器命令队列的最大等待时间
pdPASS 软件定时器停止成功
pdFAIL 软件定时器停止失败
复位软件定时器API函数
BaseType_t xTimerReset( TimerHandle_t xTimer,
const TickType_t xTicksToWait);
该功能将使软件定时器的重新开启定时,复位后的软件定时器以复位时的时刻作为开启时刻重新定时
xTimer 待复位的软件定时器的句柄
xTickToWait 发送命令到软件定时器命令队列的最大等待时间
pdPASS软件定时器复位成功
pdFAIL 软件定时器复位失败
更改软件定时器超时时间API函数
BaseType_t xTimerChangePeriod( TimerHandle_t xTimer,
const TickType_t xNewPeriod,
const TickType_t xTicksToWait);
xTimer 待更新的软件定时器的句柄
xNewPeriod新的定时超时时间,单位:系统时钟节拍
xTickToWait 发送命令到软件定时器命令队列的最大等待时间
pdPASS 软件定时器定时超时时间更改成功
pdFAIL软件定时器定时超时时间更改失败
Tickless模式相关配置项
configUSE_TICKLESS_IDLE
此宏用于使能低功耗 Tickless 模式
configEXPECTED_IDLE_TIME_BEFORE_SLEEP
此宏用于定义系统进入相应低功耗模式的最短时长
configPRE_SLEEP_PROCESSING(x)
此宏用于定义需要在系统进入低功耗模式前执行的事务,如:进入低功耗前关闭外设时钟,以达到降低功耗的目的
configPOSR_SLEEP_PROCESSING(x)
此宏用于定义需要在系统退出低功耗模式后执行的事务,如:退出低功耗后开启之前关闭的外设时钟,以使系统能够正常运行