不可被忽视的操作系统( FreeRTOS )【2】
本文章总结基于官方FreeRTOS手册,测试系统为ESP32的IDF 4.0
本篇续上一篇《不可被忽视的操作系统( FreeRTOS )【1】》
其中上一篇主要内容为:
- FreeRTOS介绍
- FreeRTOS在ESP32中的特殊性
- 任务相关函数
- 队列相关函数
本篇内容主要有:
- 信号量相关函数
- 计时器相关函数
- 事件组相关函数
- 任务通知相关函数
信号量
reertos / include / freertos / semphr.h
信号量是操作系统中重要的一部分,信号量一般用来进行资源管理和任务同步, FreeRTOS中信号量又分为
l 二值信号量、
l 计数型信号量、
l 互斥信号量、
l 递归互斥信号量
不同的信号量其应用场景不同,但有些应用场景是可以互换着使用的
创建二值信号量
创建一个新的二进制信号量(二值信号量)实例,并返回一个句柄,通过该句柄可以引用新的信号量。
通过使用现有队列机制创建信号量的函数。队列长度为1,因为它是二进制信号量。数据大小为0,因为实际上没有任何存储-重要的是队列是否为空或已满(二进制信号量是否可用)。
这种信号量可用于任务之间或中断与任务之间的纯同步。信号量不必一经获得就退还,因此一个任务/中断可以连续地“提供”该信号量,而另一任务/中断则可以连续地“获取”该信号量。因此,这种信号量不使用优先级继承机制。有关不使用优先级继承的替代方法,请参见xSemaphoreCreateMutex()。
东小东使用说明:
二值信号量即可以实现事件的计数,通过xSemaphoreGive()相关函数释放信号量也就是将计数值加一,当前其最大值为1,通过xSemaphoreTake()相关函数获取信号量也就是将计数值减一,当xSemaphoreTake()最终将计数值减到0时,将会触发xSemaphoreTake()参数的超时等待。
SemaphoreHandle_t xSemaphoreCreateBinary ()
创建计数型信号量
创建一个新的计数信号量实例,并返回一个句柄,通过该句柄可以引用新的计数信号量。
计数信号量通常用于两件事:
1)计数事件。
在这种使用情况下,事件处理程序将在每次事件发生时“给出”信号量(增加信号量计数值),而处理程序任务将在每次处理事件时“获得”信号量(减少信号量计数值)。因此,计数值是已发生的事件数与已处理的事件数之间的差。在这种情况下,期望初始计数值为零。
2)资源管理。
在这种使用情况下,计数值指示可用资源的数量。为了获得对资源的控制,任务必须首先获得一个信号量-减少信号量计数值。当计数值达到零时,将没有可用资源。当任务使用资源完成时,它将“给予”信号量-增加信号量计数值。在这种情况下,期望初始计数值等于最大计数值,指示所有资源都是空闲的。
东小东使用说明:
计数型信号量即可以实现事件的计数,通过xSemaphoreGive()相关函数释放信号量也就是将计数值加一,其最大值为创建时设置的uxMaxCount,通过xSemaphoreTake()相关函数获取信号量也就是将计数值减一,当xSemaphoreTake()最终将计数值减到0时,将会触发xSemaphoreTake()参数的超时等待。
参数:
uxMaxCount:可以达到的最大计数值。当信号量达到此值时,就不能再“给予”它了。
uxInitialCount:初值,创建信号时分配给信号量的计数值
返回:
计数型信号量句柄,失败则返回null
SemaphoreHandle_t xSemaphoreCreateCounting( uxMaxCount,uxInitialCount )
获取计数型信号量的当前计数值
如果该信号量是一个计数信号量,则uxSemaphoreGetCount()返回其当前计数值。如果该信号量是二进制信号量,那么如果该信号量可用,则uxSemaphoreGetCount()返回1;如果该信号量不可用,则返回0。
参数:信号量句柄
UBaseType_t uxSemaphoreGetCount( xSemaphore )
获取信号量
作用于二值信号量、计数型信号量、互斥信号量
宏获取信号量。信号量必须事先通过调用vSemaphoreCreateBinary(),xSemaphoreCreateMutex()或xSemaphoreCreateCounting()来创建
通过xSemaphoreGive释放后才有效,才能获取为pdTRUE
参数:
xSemaphore:获取信号量的句柄-创建信号量时获得。
xBlockTime:等待信号量可用的时间(以毫秒为单位)。宏端口TICK_PERIOD_MS可用于将其转换为实时。零的阻止时间可用于轮询信号量。portMAX_DELAY的阻塞时间可以无限期地阻塞(在FreeRTOSConfig.h中将INCLUDE_vTaskSuspend设置为1)。
返回
如果获得了信号量,则为pdTRUE。如果xBlockTime到期而信号灯不可用,则为pdFALSE。
BaseType_t xSemaphoreTake( xSemaphore,xBlockTime )
中断服务函数中获取信号量
作用于二值信号量、计数型信号量、互斥信号量
用于从ISR获取信号量的宏。信号量必须事先通过调用vSemaphoreCreateBinary()或xSemaphoreCreateCounting()来创建。
互斥类型信号量(通过调用xSemaphoreCreateMutex()创建的信号量)不得与此宏一起使用。
可以从ISR使用此宏,但是从ISR获取信号量并不常见。仅当中断从资源池中获取对象时(当信号量指示可用资源的数量时),才使用计数信号量。
参数:
xSemaphore:正在使用的信号量的句柄。这是创建信号量时返回的句柄。
pxHigherPriorityTaskWoken:如果采用信号量导致任务取消阻止,并且未阻止任务的优先级高于当前运行的任务,则xSemaphoreTakeFromISR()会将* pxHigherPriorityTaskWoken设置为pdTRUE。如果xSemaphoreTakeFromISR()将此值设置为pdTRUE,则应在退出中断之前请求上下文切换。
返回
如果成功获取了信号,则为pdTRUE,否则为pdFALSE
BaseType_t xSemaphoreTakeFromISR( xSemaphore,pxHigherPriorityTaskWoken )
释放信号量
作用于二值信号量、计数型信号量、互斥信号量
释放信号量的宏。信号量必须事先通过调用vSemaphoreCreateBinary(),xSemaphoreCreateMutex()或xSemaphoreCreateCounting()来创建。并使用sSemaphoreTake()获得。
不得从ISR使用此宏。有关可以从ISR使用的替代方法,请参见xSemaphoreGiveFromISR()。
此宏也不得用于使用xSemaphoreCreateRecursiveMutex()创建的信号量。
参数:
xSemaphore:释放信号量的句柄。这是创建信号量时返回的句柄。
返回:
如果已释放信号,则为pdTRUE。如果发生错误,则为pdFALSE。信号量是使用队列实现的。如果队列上没有空间可发布消息,则可能会发生错误-指示未正确正确获取信号量。
BaseType_t xSemaphoreGive( xSemaphore)
中断服务函数中释放信号量
作用于二值信号量、计数型信号量、互斥信号量
释放信号量的宏。信号量必须事先通过调用vSemaphoreCreateBinary()或xSemaphoreCreateCounting()来创建。
互斥类型信号量(通过调用xSemaphoreCreateMutex()创建的信号量)不得与此宏一起使用。
可以从ISR使用此宏。
参量
xSemaphore:释放信号量的句柄。这是创建信号量时返回的句柄。
pxHigherPriorityTaskWoken:如果提供信号量导致任务取消阻止,并且未阻止的任务的优先级高于当前运行的任务,则xSemaphoreGiveFromISR()会将* pxHigherPriorityTaskWoken设置为pdTRUE。如果xSemaphoreGiveFromISR()将此值设置为pdTRUE,则应在退出中断之前请求上下文切换。
返回
如果成功提供了信号量,则为pdTRUE,否则为errQUEUE_FULL。
BaseType_t xSemaphoreGiveFromISR( xSemaphore,pxHigherPriorityTaskWoken )
小试牛刀之二值信号量任务同步测试
输出效果为3S间隔输出两条,分别为1条释放,1条获取,实现任务间的运行同步
必须先释放才能获取
1 #include <stdio.h> 2 #include "freertos/FreeRTOS.h"//freertos相关 3 #include "freertos/task.h" 4 #include "freertos/semphr.h" 5 //二值信号量句柄 6 SemaphoreHandle_t xSemaphore = NULL; 7 8 //创建二值信号量来保护共享资源。 9 void dong_creat_binary() 10 { 11 //调用创建函数,二进制值信号量 12 xSemaphore = xSemaphoreCreateBinary (); 13 if(xSemaphore != NULL) 14 { 15 printf("信号量 xSemaphore 创建成功了"); 16 } 17 } 18 //任务0处理函数 19 void Task_Run_0(){ 20 uint32_t num=0; 21 while(1){ 22 num++; 23 //死等获取二值信号量 24 xSemaphoreTake(xSemaphore,portMAX_DELAY); 25 printf("【task 0】二值信号量获取成功啦,触发次数:%d\r\n",num); 26 } 27 } 28 //主函数,优先级为1 29 void app_main() 30 { 31 printf("\r\n--------------DONGIXAODONG FreeRTOS-----------------\r\n"); 32 //创建二值信号量 33 dong_creat_binary(); 34 35 //启动任务0,简化 36 //函数,名字,字节大小,参数,优先级[0,16](16最优先),任务句柄 37 BaseType_t t0res=xTaskCreate(Task_Run_0,"DONG Task_Run_0",1024*2,NULL,7,NULL); 38 if(t0res==pdPASS){ 39 printf("任务0启动成功....\r\n"); 40 } 41 while(1){ 42 vTaskDelay(3000 / portTICK_PERIOD_MS);//延时3S 43 xSemaphoreGive(xSemaphore); 44 printf("【main】释放一次二值信号量,获取将立即执行一次\r\n"); 45 } 46 }
小试牛刀之二值信号量任务共享资源保护
测试公共资源访问
测试可见,公共资源在什么任务里开始,必须在当前任务里接收后才能被其它任务开始,起到资源保护作用
1 #include <stdio.h> 2 #include "freertos/FreeRTOS.h"//freertos相关 3 #include "freertos/task.h" 4 #include "freertos/semphr.h" 5 6 //二值信号量句柄 7 SemaphoreHandle_t xSemaphore = NULL; 8 9 //创建二值信号量来保护共享资源。 10 void dong_creat_binary() 11 { 12 //调用创建函数,二进制值信号量 13 xSemaphore = xSemaphoreCreateBinary (); 14 if(xSemaphore != NULL) 15 { 16 printf("信号量 xSemaphore 创建成功了"); 17 } 18 } 19 //任务0处理函数 20 void Task_Run_0(){ 21 while(1){ 22 //延时3S,延时的时候将会使得低优先级main获取CPU 23 vTaskDelay(3000 / portTICK_PERIOD_MS); 24 printf("【task 0】开始信号量等待---\r\n"); 25 //死等获取二值信号量 26 xSemaphoreTake(xSemaphore,portMAX_DELAY); 27 printf("【task 0】*****公共资源开始*****-----\r\n"); 28 vTaskDelay(6000 / portTICK_PERIOD_MS); 29 printf("【task 0】*****公共资源结束*****------\r\n"); 30 xSemaphoreGive(xSemaphore);//释放信号量 31 printf("【task 0】结束信号量等待---\r\n"); 32 taskYIELD();//在超时之处尽量调用任务切换检查 33 } 34 } 35 //主函数,优先级为1 36 void app_main() 37 { 38 printf("\r\n--------------DONGIXAODONG FreeRTOS-----------------\r\n"); 39 //创建二值信号量 40 dong_creat_binary(); 41 xSemaphoreGive(xSemaphore);//释放信号量,刚启动是必须释放一次才能获取 42 //启动任务0,简化 43 //函数,名字,字节大小,参数,优先级[0,16](16最优先),任务句柄 44 BaseType_t t0res=xTaskCreate(Task_Run_0,"DONG Task_Run_0",1024*2,NULL,7,NULL); 45 if(t0res==pdPASS){ 46 printf("任务0启动成功....\r\n"); 47 } 48 while(1){ 49 printf("【main】开始信号量等待//////\r\n"); 50 //死等获取二值信号量 51 xSemaphoreTake(xSemaphore,portMAX_DELAY); 52 printf("【main】*****公共资源开始*****//////\r\n"); 53 vTaskDelay(6000 / portTICK_PERIOD_MS); 54 printf("【main】*****公共资源结束*****//////\r\n"); 55 xSemaphoreGive(xSemaphore);//释放信号量 56 printf("【main】结束信号量等待//////\r\n"); 57 } 58 }
计时器
freertos / include / freertos / timers.h
相关的一些宏
#define configUSE_TIMERS 1 #define configTIMER_TASK_PRIORITY 1 #define configTIMER_QUEUE_LENGTH 10 #define configTIMER_TASK_STACK_DEPTH 2048 第一个:表示是否启动计时器 第二个:表示计时器任务的优先级 第三个:表示计时器队列长度 第四个:定时器堆栈,2048个字节
硬件定时器
CPU内部自带的定时器模块,通过初始化、配置可以实现定时,定时时间到以后就会执行相应的定时器中断处理函数。硬件定时器一般都带有其它功能,比如PWM输出、输入捕获等等功能。但是缺点是硬件定时器数量少!
软件定时器
软件定时器允许设置一段时间,当设置的时间到达之后就执行指定的功能函数,被定时器调用的这个功能函数叫做定时器的回调函数。回调函数的两次执行间隔叫做定时器的定时周期,简而言之,当定时器的定时周期到了以后就会执行回调函数。
创建计时器实例
创建一个新的软件计时器实例,并返回一个句柄,通过该句柄可以引用创建的软件计时器。
在FreeRTOS的内部实现中,软件计时器使用一块内存,其中存储着计时器数据结构。如果使用xTimerCreate()创建软件计时器,则所需的内存将自动在xTimerCreate()函数内部动态分配。
创建后计时器处于休眠状态。xTimerStart(),xTimerReset(),xTimerStartFromISR(),xTimerResetFromISR(),xTimerChangePeriod()和xTimerChangePeriodFromISR()API函数均可用于将计时器转换为活动状态。
参数
pcTimerName:分配给计时器的文本名称。这样做纯粹是为了协助调试。内核本身仅通过其句柄引用计时器,而从未通过其名称引用计时器。
xTimerPeriodInTicks:计时器时间段。时间以滴答周期定义,因此常数portTICK_PERIOD_MS可用于转换以毫秒为单位指定的时间。例如,如果计时器必须在100个滴答之后过期,则xTimerPeriodInTicks应该设置为100。或者,如果计时器必须在500ms之后过期,则可以将xPeriod设置为(500 / portTICK_PERIOD_MS),前提是configTICK_RATE_HZ小于或等于1000。
uxAutoReload:如果将uxAutoReload设置为pdTRUE,则计时器将以xTimerPeriodInTicks参数设置的频率重复终止。如果将uxAutoReload设置为pdFALSE,则该计时器将是单次计时器,并在其到期后进入休眠状态。
pvTimerID:分配给正在创建的计时器的标识符。通常,在将同一回调函数分配给多个计时器时,将在计时器回调函数中使用它来标识哪个计时器到期。
pxCallbackFunction:计时器到期时要调用的函数。回调函数必须具有由TimerCallbackFunction_t定义的原型,即“ void vCallbackFunction(TimerHandle_t xTimer);”。
TimerHandle_t xTimerCreate(const char * const pcTimerName,const TickType_t xTimerPeriodInTicks,const UBaseType_t uxAutoReload,void * const pvTimerID,TimerCallbackFunction_t pxCallbackFunction )
获取计时器的ID
使用用于创建计时器的xTimerCreated()调用的pvTimerID参数将ID分配给计时器。
如果将同一个回调函数分配给多个计时器,则可以在回调函数中使用计时器ID来标识实际终止了哪个计时器。
参量
xTimer:计时器句柄
返回
查询的计时器的ID
void *pvTimerGetTimerID( const TimerHandle_t xTimer )
设置计时器ID
设置分配给计时器的ID。
使用用于创建计时器的xTimerCreated()调用的pvTimerID参数将ID分配给计时器。
如果将相同的回调函数分配给多个计时器,则计时器ID可用作特定时间(本地计时器)的存储。
参量
xTimer:计时器句柄
pvNewID:分配给计时器的ID。
void vTimerSetTimerID( TimerHandle_t xTimer, void *pvNewID )
启动计时器
必须将configUSE_TIMERS配置常量设置为1,xTimerStart()才可用。
xTimerStart()启动一个计时器,该计时器先前是使用xTimerCreate()API函数创建的。如果计时器已经启动并且已经处于活动状态,则xTimerStart()具有与xTimerReset()API函数等效的功能。
启动计时器可确保计时器处于活动状态。如果同时没有停止,删除或重置计时器,则在调用xTimerStart()之后,与计时器关联的回调函数将被称为“ n”滴答,其中“ n”是计时器定义的时间段。
在启动调度程序之前调用xTimerStart()是有效的,但是完成此操作后,计时器将不会真正启动,直到启动调度程序为止,并且计时器的到期时间将与启动调度程序有关,而不是与启动调度程序有关当xTimerStart()被调用时。
参量
xTimer:正在启动/重新启动的计时器的句柄。
xTicksToWait:指定在调用xTimerStart()时,如果队列已满,则调用任务应保持在Blocked状态的时间,以等待启动命令成功发送到计时器命令队列的时间(以秒为单位)。如果在调度程序启动之前调用了xTimerStart(),则xTicksToWait将被忽略,该参数的值请参考队列
返回
如果即使经过xTicksToWait滴答声后仍无法将启动命令发送到计时器命令队列,则将返回pdFAIL。如果命令已成功发送到计时器命令队列,则将返回pdPASS。实际处理命令的时间将取决于计时器服务/守护程序任务相对于系统中其他任务的优先级,尽管计时器的到期时间与实际调用xTimerStart()有关。计时器服务/守护程序任务优先级由configTIMER_TASK_PRIORITY配置常量设置。
BaseType_t xTimerStart( xTimer, xTicksToWait )
停止计时器
必须将configUSE_TIMERS配置常量设置为1,xTimerStop()才可用。
xTimerStop()停止使用xTimerStart(),xTimerReset(),xTimerStartFromISR(),xTimerResetFromISR(),xTimerChangePeriod()或xTimerChangePeriodFromISR()API函数之一启动的计时器。
停止计时器可确保计时器未处于活动状态。
参量
xTimer:定时器的句柄正在停止。
xTicksToWait:指定在调用xTimerStop()时,如果队列已满,则调用任务应保持在Blocked状态的时间,以等待stop命令成功发送到计时器命令队列。如果在调度程序启动之前调用了xTimerStop(),则xTicksToWait将被忽略。
返回
如果即使经过xTicksToWait滴答声也无法将stop命令发送到计时器命令队列,则将返回pdFAIL。如果命令已成功发送到计时器命令队列,则将返回pdPASS。实际处理命令的时间将取决于计时器服务/守护程序任务相对于系统中其他任务的优先级。计时器服务/守护程序任务优先级由configTIMER_TASK_PRIORITY配置常量设置。该参数的值请参考队列
BaseType_t xTimerStop( xTimer,xTicksToWait )
重置计时器
必须将configUSE_TIMERS配置常量设置为1,xTimerReset()才可用
xTimerReset()重新启动以前使用xTimerCreate()API函数创建的计时器。如果计时器已经启动并且已经处于活动状态,则xTimerReset()将使计时器重新评估其到期时间,以使其与调用xTimerReset()的时间有关。如果计时器处于休眠状态,则xTimerReset()具有与xTimerStart()API函数等效的功能。
重置计时器可确保计时器处于活动状态。如果同时没有停止,删除或重置计时器,则在调用xTimerReset()之后,与计时器关联的回调函数将被称为“ n”滴答,其中“ n”是计时器定义的时间段。
在启动调度程序之前调用xTimerReset()是有效的,但是完成此操作后,计时器将不会真正启动,直到启动调度程序为止,并且计时器的到期时间将与启动调度程序的时间有关,而不是相对于启动调度程序的时间当xTimerReset()被调用时。
参数:
xTimer:正在重置/启动/重新启动的计时器的句柄。
xTicksToWait:指定在调用xTimerReset()时,如果队列已满,则调用任务应保持在Blocked状态的时间,以等待重置命令成功发送到计时器命令队列的时间(以秒为单位)。如果在调度程序启动之前调用了xTimerReset(),则xTicksToWait将被忽略。
返回
如果即使经过xTicksToWait滴答声后仍无法将重置命令发送到计时器命令队列,则将返回pdFAIL。如果命令已成功发送到计时器命令队列,则将返回pdPASS。实际处理命令的时间将取决于计时器服务/守护程序任务相对于系统中其他任务的优先级,尽管计时器的到期时间与实际调用xTimerStart()有关。计时器服务/守护程序任务优先级由configTIMER_TASK_PRIORITY配置常量设置。
BaseType_t xTimerReset( xTimer,xTicksToWait )
删除计时器
必须将configUSE_TIMERS配置常量设置为1,xTimerDelete()才可用。
xTimerDelete()删除以前使用xTimerCreate()API函数创建的计时器。
参量
xTimer:定时器的句柄被删除。
xTicksToWait:指定在调用xTimerDelete()时,如果队列已满,则调用任务应保持在Blocked状态的时间,以等待删除命令成功发送到计时器命令队列。如果在启动调度程序之前调用了xTimerDelete(),则xTicksToWait将被忽略。
返回
如果即使经过xTicksToWait滴答声后仍无法将删除命令发送到计时器命令队列,则将返回pdFAIL。如果命令已成功发送到计时器命令队列,则将返回pdPASS。实际处理命令的时间将取决于计时器服务/守护程序任务相对于系统中其他任务的优先级。计时器服务/守护程序任务优先级由configTIMER_TASK_PRIORITY配置常量设置
BaseType_t xTimerDelete( xTimer,xTicksToWait )
查看计时器的状态
计时器处于休眠状态。xTimerStart(),xTimerReset(),xTimerStartFromISR(),xTimerResetFromISR(),xTimerChangePeriod()和xTimerChangePeriodFromISR()API函数均可用于将计时器转换为活动状态。
参量
xTimer:计时器句柄
返回
如果计时器处于休眠状态,则将返回pdFALSE。如果计时器处于活动状态,则将返回pdFALSE以外的值。
BaseType_t xTimerIsTimerActive(TimerHandle_t xTimer )
更改计时器周期
必须将configUSE_TIMERS配置常量设置为1,xTimerChangePeriod()才可用
xTimerChangePeriod()更改以前使用xTimerCreate()API函数创建的计时器的周期。
可以调用xTimerChangePeriod()来更改活动或休眠状态计时器的周期。
参数
xTimer:正在更改其周期的计时器的句柄。
xNewPeriod:xTimer的新时期。计时器周期以滴答周期指定,因此常数portTICK_PERIOD_MS可用于转换以毫秒为单位指定的时间。例如,如果计时器必须在100个滴答之后过期,则xNewPeriod应该设置为100。或者,如果计时器必须在500ms之后过期,那么可以将xNewPeriod设置为(500 / portTICK_PERIOD_MS),前提是configTICK_RATE_HZ小于或等于1000。 。
xTicksToWait:指定在调用xTimerChangePeriod()时队列已满的情况下,调用任务应保持在“阻塞”状态,等待更改周期命令成功发送到计时器命令队列的时间(以滴答为单位)。如果在调度程序启动之前调用了xTimerChangePeriod(),则xTicksToWait将被忽略。
返回
如果即使经过xTicksToWait滴答声之后仍无法将更改周期命令发送到计时器命令队列,则将返回pdFAIL。如果命令已成功发送到计时器命令队列,则将返回pdPASS。实际处理命令的时间将取决于计时器服务/守护程序任务相对于系统中其他任务的优先级。计时器服务/守护程序任务优先级由configTIMER_TASK_PRIORITY配置常量设置。
BaseType_t xTimerChangePeriod( xTimer,xNewPeriod,xTicksToWait )
获取定时器周期(嘀嗒数)
参量
xTimer:计时器句柄
返回
计时器的周期,以滴答为单位
TickType_t xTimerGetPeriod(TimerHandle_t xTimer )
获取定时器周期(秒)
以秒为单位返回计时器将到期的时间。如果小于当前滴答计数,则到期时间从当前时间开始溢出。
参量
xTimer:计时器句柄
返回
如果计时器正在运行,则将返回计时器下一次到期的时间(以秒为单位)。如果计时器未运行,则返回值不确定
TickType_t xTimerGetExpiryTime(TimerHandle_t xTimer )
获取计时器名称
返回创建计时器时分配给计时器的名称。
参量
xTimer:计时器句柄
返回
分配给xTimer参数指定的计时器的名称
const char * pcTimerGetTimerName(TimerHandle_t xTimer )
计时器启动/停止/重置对应的中断函数有
参数
xTimer:正在启动/重新启动的计时器的句柄。
pxHigherPriorityTaskWoken:计时器服务/守护程序任务的大部分时间都处于“阻塞”状态,等待消息到达计时器命令队列。调用xTimerStartFromISR()会将消息写入计时器命令队列,因此有可能将计时器服务/守护程序任务转换为“已阻止”状态。如果调用xTimerStartFromISR()导致计时器服务/守护程序任务退出“阻塞”状态,并且计时器服务/守护程序任务的优先级等于或大于当前正在执行的任务(被中断的任务),则* pxHigherPriorityTaskWoken将获得在xTimerStartFromISR()函数内部将其设置为pdTRUE。如果xTimerStartFromISR()将此值设置为pdTRUE,则应在中断退出之前执行上下文切换。
返回:
如果无法将启动命令发送到计时器命令队列,则将返回pdFAIL。如果命令已成功发送到计时器命令队列,则将返回pdPASS。实际处理命令的时间将取决于计时器服务/守护程序任务相对于系统中其他任务的优先级,尽管计时器的到期时间与实际调用xTimerStartFromISR()的时间有关。计时器服务/守护程序任务优先级由configTIMER_TASK_PRIORITY配置常量设置
启动计时器
TickType_t xTimerStartFromISR( xTimer,pxHigherPriorityTaskWoken )
停止计时器
TickType_t xTimerStopFromISR( xTimer,pxHigherPriorityTaskWoken )
重置计时器
TickType_t xTimerResetFromISR( xTimer,pxHigherPriorityTaskWoken )
计时器设置周期中断使用函数
参量
xTimer:正在更改其周期的计时器的句柄。
xNewPeriod:xTimer的新时期。计时器周期以滴答周期指定,因此常数portTICK_PERIOD_MS可用于转换以毫秒为单位指定的时间。例如,如果计时器必须在100个滴答之后过期,则xNewPeriod应该设置为100。或者,如果计时器必须在500ms之后过期,那么可以将xNewPeriod设置为(500 / portTICK_PERIOD_MS),前提是configTICK_RATE_HZ小于或等于1000。 。
pxHigherPriorityTaskWoken:计时器服务/守护程序任务的大部分时间都处于“阻塞”状态,等待消息到达计时器命令队列。调用xTimerChangePeriodFromISR()会将消息写入计时器命令队列,因此有可能将计时器服务/守护程序任务从“阻塞”状态转换出来。如果调用xTimerChangePeriodFromISR()导致计时器服务/守护程序任务退出“阻塞”状态,并且计时器服务/守护程序任务的优先级等于或大于当前正在执行的任务(被中断的任务),则* pxHigherPriorityTaskWoken将获得在xTimerChangePeriodFromISR()函数内部将其设置为pdTRUE。如果xTimerChangePeriodFromISR()将此值设置为pdTRUE,则应在中断退出之前执行上下文切换。
返回:
如果无法将更改计时器周期的命令发送到计时器命令队列,则将返回pdFAIL。如果命令已成功发送到计时器命令队列,则将返回pdPASS。实际处理命令的时间将取决于计时器服务/守护程序任务相对于系统中其他任务的优先级。计时器服务/守护程序任务优先级由configTIMER_TASK_PRIORITY配置常量设置
TickType_t xTimerChangePeriodFromISR( xTimer,xNewPeriod,pxHigherPriorityTaskWoken )
小试牛刀
1 #include <stdio.h> 2 #include "freertos/FreeRTOS.h"//freertos相关 3 #include "freertos/task.h" 4 #include "freertos/semphr.h" 5 #include "freertos/timers.h" 6 7 //计时器器句柄 8 TimerHandle_t onetimer = NULL; 9 TimerHandle_t cirtimer = NULL; 10 11 //计时器回调函数 12 void oneTimerCallback( TimerHandle_t pxTimer ) 13 { 14 uint32_t timerid=(uint32_t)pvTimerGetTimerID(pxTimer);//获取ID 15 16 printf("【单次计时任务 onetimer】 回调函数触发,ID为:%d\r\n",timerid); 17 if( xTimerReset( pxTimer, 100 ) == pdPASS ) 18 { 19 printf("【单次计时任务 onetimer】 重置成功*****\r\n"); 20 } 21 } 22 23 //计时器回调函数 24 void cirTimerCallback( TimerHandle_t pxTimer ) 25 { 26 printf("【循环计时任务 cirtimer】 回调函数触发\r\n"); 27 28 } 29 30 void dong_create_timer() 31 { 32 //创建一个一次性计时任务 33 onetimer = xTimerCreate("dong_onetimer", // 设置一个名词,便于调试 34 ( 2000 / portTICK_PERIOD_MS), //定时周期 35 pdFALSE, // pdFALSE为单次,pdTRUE为循环 36 (void *)100, //设置一个ID用于标识 37 oneTimerCallback //回调函数 38 ); 39 if( onetimer != NULL ) 40 { 41 printf("【单次计时任务 onetimer】 创建成功\r\n"); 42 xTimerStart( onetimer, 10 );//开启计数器 43 } 44 45 //创建一个循环计时任务 46 cirtimer = xTimerCreate("dong_cirtimer", // 设置一个名词,便于调试 47 ( 4000 / portTICK_PERIOD_MS), //定时周期 48 pdTRUE, // pdFALSE为单次,pdTRUE为循环 49 (void *)11, //设置一个ID用于标识 50 cirTimerCallback //回调函数 51 ); 52 if( cirtimer != NULL ) 53 { 54 printf("【循环计时任务 cirtimer】 创建成功\r\n"); 55 xTimerStart( cirtimer, 10 );//开启计时器 56 } 57 } 58 59 //主函数,优先级为1 60 void app_main() 61 { 62 printf("\r\n--------------DONGIXAODONG FreeRTOS-----------------\r\n"); 63 64 //创建并开始计时器 65 dong_create_timer(); 66 67 while(1){ 68 //taskYIELD();//任务调度 69 vTaskDelay(10);//还是的用延时函数进行任务调度 70 } 71 }
在上述例程中添加延时函数
1 //计时器回调函数 2 void oneTimerCallback( TimerHandle_t pxTimer ) 3 { 4 uint32_t timerid=(uint32_t)pvTimerGetTimerID(pxTimer);//获取ID 5 6 printf("【单次计时任务 onetimer】 回调函数触发,ID为:%d\r\n",timerid); 7 8 printf("【单次计时任务 onetimer】10///秒延时开始啦\r\n"); 9 vTaskDelay(10000 / portTICK_PERIOD_MS); 10 printf("【单次计时任务 onetimer】10///秒延时结束啦\r\n"); 11 12 if( xTimerReset( pxTimer, 100 ) == pdPASS ) 13 { 14 printf("【单次计时任务 onetimer】 重置成功*****\r\n"); 15 } 16 }
输出:
可见:
延时函数将阻塞定时任务,会影响到其它定时任务功能,所以定时回调函数中操作尽量少
事件组
freertos / include / freertos / event_groups.h
以数据位标志事件
创建事件组
尽管事件组与滴答无关,但出于内部实现的原因,事件组中可使用的位数取决于FreeRTOSConfig.h中的configUSE_16_BIT_TICKS设置。如果configUSE_16_BIT_TICKS为1,则每个事件组包含8个可用位(位0至位7)。如果configUSE_16_BIT_TICKS设置为0,则每个事件组都有24个可用位(位0到位23)。EventBits_t类型用于在事件组中存储事件位。
返回:事件组句柄,创建失败为NULL
EventGroupHandle_t xEventGroupCreate()
等待事件位
[可能]阻止等待先前创建的事件组中的一个或多个位设置。
不能从中断中调用此函数
参数:
xEventGroup:事件组句柄。事件组必须先前已通过调用xEventGroupCreate()创建
uxBitsToWaitFor:按位的值,指示事件组中要测试的一位或多位。例如,要等待位0和/或位2,请将uxBitsToWaitFor设置为0x05。要等待位0和/或位1和/或位2,请将uxBitsToWaitFor设置为0x07。等等
xClearOnExit:如果xClearOnExit设置为pdTRUE,则如果满足等待条件(如果函数由于超时以外的原因返回),则在xEventGroupWaitBits()返回之前,将清除事件组中设置的uxBitsToWaitFor中的任何位。如果xClearOnExit设置为pdFALSE,则在对xEventGroupWaitBits()的调用返回时,事件组中设置的位不会更改。
xWaitForAllBits:如果xWaitForAllBits设置为pdTRUE,则当uxBitsToWaitFor中的所有位都已设置或指定的块时间到期时,xEventGroupWaitBits()将返回。如果将xWaitForAllBits设置为pdFALSE,则当设置uxBitsToWaitFor中设置的任何一位或指定的块时间到期时,xEventGroupWaitBits()将返回。阻止时间由xTicksToWait参数指定
xTicksToWait:等待设置uxBitsToWaitFor指定的位中的一个/全部(取决于xWaitForAllBits值)的最长时间(以“ ticks”指定),与其它设置等待时间一致,可以立即、一段、永远。
返回
在等待位被置位或块时间到期时事件组的值。测试返回值以了解设置了哪些位。如果xEventGroupWaitBits()由于其超时到期而返回,则不会设置所有等待的位。如果由于设置了xEventGroupWaitBits()而等待的位而返回,则在xClearOnExit参数设置为pdTRUE的情况下,返回值是在自动清除任何位之前的事件组值。
EventBits_t xEventGroupWaitBits(EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToWaitFor,const BaseType_t xClearOnExit,const BaseType_t xWaitForAllBits,TickType_t xTicksToWait )
获取事件组中当前值
返回事件组中位的当前值。不能从中断使用此功能。
参量
xEventGroup:正在查询的事件组
返回
调用xEventGroupGetBits()时的事件组位
EventBits_t xEventGroupGetBits( xEventGroup )
清除事件组中的位
清除事件组中的位。不能从中断中调用此函数。
参数:
xEventGroup:事件组句柄,其中的位将被清除
uxBitsToClear:按位表示在事件组中要清除的一个或多个位。例如,仅清除位3,将uxBitsToClear设置为0x08。要清除位3和位0,请将uxBitsToClear设置为0x09。
返回:
清除指定位之前的事件组的值
EventBits_t xEventGroupClearBits(EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToClear )
设置事件组中的位
设置事件组中的位。不能从中断中调用此函数。xEventGroupSetBitsFromISR()是可以从中断中调用的版本。
在事件组中设置位将自动解除阻止等待这些位的任务。
参数:
xEventGroup:要设置位的事件组。
uxBitsToSet:按位的值,指示要设置的一个或多个位。例如,要仅设置位3,请将uxBitsToSet设置为0x08。要设置位3和位0,请将uxBitsToSet设置为0x09。
返回
返回xEventGroupSetBits()调用时事件组的值。返回值可能清除了uxBitsToSet参数指定的位有两个原因。首先,如果设置一个位导致正在等待该位离开阻塞状态的任务,则有可能该位将被自动清除(请参阅xEventGroupWaitBits()的xClearBitOnExit参数)。其次,任何优先级高于被称为xEventGroupSetBits()的任务的无阻塞(或就绪状态)任务都将执行,并且可能会在调用xEventGroupSetBits()返回之前更改事件组的值。
EventBits_t xEventGroupSetBits(EventGroupHandle_t xEventGroup,const EventBits_t uxBitsToSet )
删除事件组
删除以前通过调用xEventGroupCreate()创建的事件组。在事件组上被阻止的任务将被取消阻止,并获得0作为事件组的值。
参数:
xEventGroup事件组句柄
Void vEventGroupDelete(EventGroupHandle_t xEventGroup )
中断中获取事件组的位
可以从ISR调用的xEventGroupGetBits()版本
参量
xEventGroup:正在查询的事件组
返回
调用xEventGroupGetBitsFromISR()时的事件组位
EventBits_t xEventGroupGetBitsFromISR(EventGroupHandle_t xEventGroup )
中断中清除数据组的位
可以从中断中调用的xEventGroupClearBits()版本。
在事件组中设置位不是确定性操作,因为可能有未知数量的任务正在等待设置一个或多个位。FreeRTOS不允许在禁用中断时执行不确定的操作,因此通过挂起调度程序而不是禁用中断来保护从任务访问的事件组。结果,不能从中断服务程序直接访问事件组。因此,xEventGroupClearBitsFromISR()向计时器任务发送一条消息,以在计时器任务的上下文中执行清除操作。
参量
xEventGroup:事件组,其中的位将被清除。
uxBitsToClear:按位的值,指示要清除的一个或多个位。例如,仅清除位3,将uxBitsToClear设置为0x08。要清除位3和位0,请将uxBitsToClear设置为0x09
返回
如果成功执行了执行功能的请求,则返回pdPASS,否则返回pdFALSE。如果计时器服务队列已满,则将返回pdFALSE
xEventGroupClearBitsFromISR( xEventGroup,uxBitsToClear )
中断中设置事件组的位
可以从中断中调用的xEventGroupSetBits()版本。
在事件组中设置位不是确定性操作,因为可能有未知数量的任务正在等待设置一个或多个位。FreeRTOS不允许在中断或关键部分执行不确定的操作。因此,xEventGroupSetBitFromISR()向计时器任务发送一条消息,以在计时器任务的上下文中执行设置操作-在该上下文中,使用调度程序锁来代替关键节。
参量
xEventGroup:要设置位的事件组。
uxBitsToSet:按位的值,指示要设置的一个或多个位。例如,要仅设置位3,请将uxBitsToSet设置为0x08。要设置位3和位0,请将uxBitsToSet设置为0x09。
pxHigherPriorityTaskWoken:如上所述,调用此函数将导致消息发送到计时器守护程序任务。如果计时器守护程序任务的优先级高于当前正在运行的任务(中断被中断的任务)的优先级,则xEventGroupSetBitsFromISR()将* pxHigherPriorityTaskWoken设置为pdTRUE,指示应在中断退出之前请求上下文切换。因此,必须将* pxHigherPriorityTaskWoken初始化为pdFALSE。
返回
如果成功执行了执行功能的请求,则返回pdPASS,否则返回pdFALSE。如果计时器服务队列已满,则将返回pdFALSE。
xEventGroupSetBitsFromISR( xEventGroup,uxBitsToSet,pxHigherPriorityTaskWoken )
小试牛刀
1 #include <stdio.h> 2 #include "freertos/FreeRTOS.h"//freertos相关 3 #include "freertos/task.h" 4 #include "freertos/event_groups.h" 5 //事件组句柄 6 EventGroupHandle_t eventgroup=NULL; 7 8 //管理的位, 9 #define BIT_0 (1 << 0) 10 #define BIT_5 (1 << 5) 11 12 //任务0处理函数 13 void Task_Run_0(){ 14 while(1){ 15 printf("【task 0】事件标志组等待开始---\r\n"); 16 xEventGroupWaitBits( 17 eventgroup, // 事件标志组句柄 18 BIT_0 | BIT_5, //时间标志位 19 pdTRUE, //pdTRUE为满足条件则清除返回,pdFALSE为不清除返回 20 pdTRUE, //pdTRUE为所有标志位满足才有效,pdFALSE为部分满足有效 21 portMAX_DELAY); //等待时间,portMAX_DELAY为一直等待,0为立即返回,其它为节拍数 22 23 printf("【task 0】事件标志组等待结束---\r\n"); 24 printf("【task 0】开始动作啦---\r\n"); 25 printf("【task 0】.......................---\r\n"); 26 printf("【task 0】结束动作啦---\r\n"); 27 } 28 } 29 //主函数,优先级为1 30 void app_main() 31 { 32 printf("\r\n--------------DONGIXAODONG FreeRTOS-----------------\r\n"); 33 //创建时间组 34 eventgroup=xEventGroupCreate(); 35 36 //启动任务0,简化 37 //函数,名字,字节大小,参数,优先级[0,16](16最优先),任务句柄 38 BaseType_t t0res=xTaskCreate(Task_Run_0,"DONG Task_Run_0",1024*2,NULL,7,NULL); 39 if(t0res==pdPASS){ 40 printf("任务0启动成功....\r\n"); 41 } 42 while(1){ 43 printf("【main】///////开始设置位//////\r\n"); 44 45 printf("【main】设置位:BIT_0\r\n"); 46 xEventGroupSetBits(eventgroup, BIT_0); 47 vTaskDelay(2000 / portTICK_PERIOD_MS); 48 49 printf("【main】设置位:BIT_5\r\n"); 50 xEventGroupSetBits(eventgroup, BIT_5); 51 vTaskDelay(3000 / portTICK_PERIOD_MS); 52 53 printf("【main】设置位:BIT_5|BIT_0 \r\n"); 54 xEventGroupSetBits(eventgroup, BIT_5|BIT_0); 55 vTaskDelay(3000 / portTICK_PERIOD_MS); 56 } 57 }
任务通知
任务通知在FreeRTOS中是一个可选的功能,要使用任务通知的话就需要将宏contfigUSE TASK NOTIFICATIONS定义为1
FreeRTOS的每个任务都有一个32位的通知值,任务控制块中的成员变量ulNotifiedValue就是这个通知值。任务通知是一个事件,假如某个任务通知的接收任务因为等待任务通知而阻塞的话,向这个接收任务发送任务通知以后就会解除这个任务的阻塞状态。也可以更新接收任务的任务通知值,任务通知可以通过如下方法更新接收任务的通知值:
不覆盖接收任务的通知值(如果上次发送给接收任务的通知还没被处理)。
覆盖接收任务的通知值。
更新接收任务通知值的一个或多个bit.增加接收任务的通知值。
合理、灵活的使用上面这些更改任务通知值的方法可以在一些场合中替代队列、二值信号·量、计数型信号量和事件标志组。使用任务通知来实现二值信号量功能的时候,解除任务阻塞的时间比直接使用二值信号量要快45%(FreeRTOS官方测试结果,使用v8.1.2版本中的二值信号量, GCC编译器,-02优化的条件下测试的,没有使能断言函数configASSERTO),并且使用的RAM更少!
任务通知的发送使用函数xTaskNotify)或者xTaskNotifyGive)(还有此函数的中断版本)来完成,这个通知值会一直被保存着,直到接收任务调用函数xTaskNotifyWait)或者ulTaskNotifyTake)来获取这个通知值。假如接收任务因为等待任务通知而阻塞的话那么在接收到任务通知以后就会解除阻塞态。任务通知虽然可以提高速度,并且减少RAM的使用,但是任务通知也是有使用限制的:
FreeRTOS的任务通知只能有一个接收任务,其实大多数的应用都是这种情况。
接收任务可以因为接收任务通知而进入阻塞态,但是发送任务不会因为任务通知发送失败而阻塞
发送任务通知
configUSE_TASK_NOTIFICATIONS必须未定义或定义为1才能使此功能可用。
将configUSE_TASK_NOTIFICATIONS设置为1时,每个任务都有其自己的专用“通知值”,该值是32位无符号整数(uint32_t)。
可以使用中介对象将事件发送到任务。此类对象的示例是队列,信号量,互斥对象和事件组。任务通知是一种将事件直接发送到任务而无需此类中介对象的方法。
发送给任务的通知可以选择执行某项操作,例如更新,覆盖或增加任务的通知值。这样,任务通知可用于将数据发送到任务,或用作轻量级和快速二进制或计数信号量。
发送给任务的通知将保持待处理状态,直到任务调用xTaskNotifyWait()或ulTaskNotifyTake()将其清除为止。如果通知到达时任务已经处于“阻止”状态以等待通知,则该任务将自动从“阻止”状态中删除(取消阻止),并清除通知。
任务可以使用xTaskNotifyWait()来[可选地]阻塞以等待通知挂起,或者使用ulTaskNotifyTake()来[可选地]阻塞以等待其通知值具有非零值。处于“阻塞”状态时,该任务不会消耗任何CPU时间。
参数:
xTaskToNotify:通知任务的句柄。可以从用于创建任务的xTaskCreate()API函数返回任务的句柄,并且可以通过调用xTaskGetCurrentTaskHandle()获得当前正在运行的任务的句柄。
ulValue:可以随通知一起发送的数据。数据的使用方式取决于eAction参数的值。
eAction:指定通知如何更新任务的通知值(如果有的话)。eAction的有效值如下:
eNoAction = 0,无动作,通知任务而不更新其通知值。始终返回pdPASS。
eSetBits, 任务的通知值与ulValue按位或,始终返回pdPASS。
eIncrement, 任务的通知值增加1,始终返回pdPASS。
eSetValueWithOverwrite, 复写方式更新通知值,不管任务是否读取该值,都将更新通知值,始终返回pdPASS
esetvaluewithoutoverwrite果任务已经读取了之前的值,则设置任务的通知值。如果被通知的任务尚未有待处理的通知,则该任务的通知值将设置为ulValue,xTaskNotify()将返回pdPASS。如果要通知的任务已经有待处理的通知,则不执行任何操作,并返回pdFAIL。
BaseType_t xTaskNotify(TaskHandle_t xTaskToNotify,uint32_t ulValue,eNotifyAction eAction )
ISR发送任务通知
configUSE_TASK_NOTIFICATIONS必须未定义或定义为1才能使此功能可用。
相较于xTaskNotify多了如下参数:
pxHigherPriorityTaskWoken:如果发送通知导致发送通知的任务离开阻塞状态,并且未阻塞任务的优先级高于当前运行的任务,则xTaskNotifyFromISR()会将* pxHigherPriorityTaskWoken设置为pdTRUE。如果xTaskNotifyFromISR()将此值设置为pdTRUE,则应在退出中断之前请求上下文切换。从ISR请求上下文切换的方式取决于端口-有关正在使用的端口,请参阅文档页面
BaseType_t xTaskNotifyFromISR(TaskHandle_t xTaskToNotify,uint32_t ulValue,eNotifyAction eAction,BaseType_t * pxHigherPriorityTaskWoken )
等待任务通知
configUSE_TASK_NOTIFICATIONS必须未定义或定义为1才能使此功能可用。
任务可以使用xTaskNotifyWait()来[可选地]阻塞以等待通知挂起,或者使用ulTaskNotifyTake()来[可选地]阻塞以等待其通知值具有非零值。处于“阻塞”状态时,该任务不会消耗任何CPU时间。
参数:
l ulBitsToClearOnEntry注意:等待前的清除,在检查任务是否有待处理的通知之前,将在调用任务的通知值中清除ulBitsToClearOnEntry值中设置的位,如果没有待处理的通知,则将阻塞该任务。将ulBitsToClearOnEntry设置为ULONG_MAX(如果包括limits.h)或0xffffffffUL(如果不包括limits.h)将具有将任务的通知值重置为0的作用。将ulBitsToClearOnEntry设置为0将使任务的通知值保持不变。
l ulBitsToClearOnExit:退出等待的清除,如果在调用任务退出xTaskNotifyWait()函数之前有待处理或已收到通知,则使用pulNotificationValue参数传递任务的通知值(请参阅xTaskNotify()API函数)。然后,将在任务的通知值中清除在ulBitsToClearOnExit中设置的所有位(请注意,在清除任何位之前已设置* pulNotificationValue)。将ulBitsToClearOnExit设置为ULONG_MAX(如果包括limits.h)或0xffffffffUL(如果不包括limits.h)将在功能退出之前将任务的通知值重置为0。将ulBitsToClearOnExit设置为0将在函数退出时使任务的通知值保持不变(在这种情况下,在pulNotificationValue中传递的值将与任务的通知值匹配)。
l pulNotificationValue:用于将任务的通知值传递出函数。注意,由于ulBitsToClearOnExit非零而导致清除任何位,不会影响传递的值。
l xTicksToWait:如果在调用xTaskNotifyWait()时通知尚未挂起,则任务在“已阻止”状态下等待接收通知的最长时间。处于“阻塞”状态时,该任务不会消耗任何处理时间。这是在内核滴答中指定的,宏pdMS_TO_TICSK(value_in_ms)可用于将以毫秒为单位指定的时间转换为以滴答为单位指定的时间。
返回
如果收到通知(包括调用xTaskNotifyWait时已待处理的通知),则返回pdPASS。否则,返回pdFAIL。
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry,uint32_t ulBitsToClearOnExit,uint32_t * pulNotificationValue,TickType_t xTicksToWait )
简化的通知
适用于模拟任务对任务的二值信号量和计数型信号量功能
参数:接收的任务句柄
返回:始终返回pdPASS
xTaskNotifyGive( xTaskToNotify )
函数原型
可见,其功能是给eAction参数的值进行加一操作
#define xTaskNotifyGive( xTaskToNotify ) xTaskNotify( ( xTaskToNotify ), 0, eIncrement )
简化的接收
适用于模拟任务对任务的二值信号量和计数型信号量功能
参数:
xClearCountOnExit:如果xClearCountOnExit为pdFALSE,则函数退出时任务的通知值将减小。这样,通知值就像计数信号量一样。如果xClearCountOnExit不是pdFALSE,则函数退出时,任务的通知值将清除为零。这样,通知值的作用就像一个二进制信号量。
xTicksToWait:如果在调用ulTaskNotifyTake()时计数尚未大于零,则任务应在“阻塞”状态下等待的最大时间,以使该任务的通知值大于零。处于“阻塞”状态时,该任务不会消耗任何处理时间。这是在内核滴答中指定的,宏pdMS_TO_TICSK(value_in_ms)可用于将以毫秒为单位指定的时间转换为以滴答为单位指定的时间。
返回
任务的通知计数在清零或递减之前(请参阅xClearCountOnExit参数)
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit,TickType_t xTicksToWait )
其功能是给eAction参数的值进行减一或清零操作
小试牛刀(任务同步效果)
1 #include <stdio.h> 2 #include "freertos/FreeRTOS.h"//freertos相关 3 #include "freertos/task.h" 4 #include "freertos/semphr.h" 5 //任务句柄 6 TaskHandle_t TaskH_0=NULL; 7 8 //任务0处理函数 9 void Task_Run_0(){ 10 uint32_t Noti_vlaue=0; 11 while(1){ 12 /* 13 参数1:进入时,传递的参数取反后按位与来设定任务通知初值(ULONG_MAX表示清零,0表示值不变,其他值按规则) 14 参数2:退出时,传递的参数取反后按位与来设定任务通知初值(ULONG_MAX表示清零,0表示值不变,其他值按规则) 15 参数3:通知值获取 16 参数4:等待时间 17 */ 18 xTaskNotifyWait(ULONG_MAX,ULONG_MAX,&Noti_vlaue,portMAX_DELAY); 19 printf("【task 0】接收到通知,其值为:%d\r\n",Noti_vlaue); 20 } 21 } 22 //主函数,优先级为1 23 void app_main() 24 { 25 printf("\r\n--------------DONGIXAODONG FreeRTOS-----------------\r\n"); 26 27 //启动任务0,简化 28 //函数,名字,字节大小,参数,优先级[0,16](16最优先),任务句柄 29 BaseType_t t0res=xTaskCreate(Task_Run_0,"DONG Task_Run_0",1024*2,NULL,7,&TaskH_0); 30 if(t0res==pdPASS){ 31 printf("任务0启动成功....\r\n"); 32 } 33 while(1){ 34 vTaskDelay(3000 / portTICK_PERIOD_MS);//延时3S 35 printf("【main】即将发送一次通知\r\n"); 36 /* 37 参数1:任务句柄 38 参数2:通知值 39 参数3: 40 eNoAction = 0,无动作,通知任务而不更新其通知值 41 eSetBits, 任务的通知值与ulValue按位或 42 eIncrement, 任务的通知值增加1 43 eSetValueWithOverwrite, 复写方式更新通知值,不管任务是否读取该值,都将更新通知值 44 eSetValueWithoutOverwrite 果任务已经读取了之前的值,则设置任务的通知值 45 */ 46 xTaskNotify(TaskH_0,1,eNoAction); 47 } 48 }
小试牛刀(任务同步与值传递效果)
1 #include <stdio.h> 2 #include "freertos/FreeRTOS.h"//freertos相关 3 #include "freertos/task.h" 4 #include "freertos/semphr.h" 5 //任务句柄 6 TaskHandle_t TaskH_0=NULL; 7 8 //任务0处理函数 9 void Task_Run_0(){ 10 uint32_t Noti_vlaue=0; 11 while(1){ 12 /* 13 参数1:进入时,传递的参数取反后按位与来设定任务通知初值(ULONG_MAX表示清零,0表示值不变,其他值按规则) 14 参数2:退出时,传递的参数取反后按位与来设定任务通知初值(ULONG_MAX表示清零,0表示值不变,其他值按规则) 15 参数3:通知值获取 16 参数4:等待时间 17 */ 18 xTaskNotifyWait(ULONG_MAX,ULONG_MAX,&Noti_vlaue,portMAX_DELAY); 19 printf("【task 0】接收到通知,其值为:%d\r\n",Noti_vlaue); 20 } 21 } 22 //主函数,优先级为1 23 void app_main() 24 { 25 printf("\r\n--------------DONGIXAODONG FreeRTOS-----------------\r\n"); 26 27 //启动任务0,简化 28 //函数,名字,字节大小,参数,优先级[0,16](16最优先),任务句柄 29 BaseType_t t0res=xTaskCreate(Task_Run_0,"DONG Task_Run_0",1024*2,NULL,7,&TaskH_0); 30 if(t0res==pdPASS){ 31 printf("任务0启动成功....\r\n"); 32 } 33 uint32_t num=0; 34 while(1){ 35 vTaskDelay(3000 / portTICK_PERIOD_MS);//延时3S 36 printf("【main】即将发送一次通知\r\n"); 37 num++; 38 /* 39 参数1:任务句柄 40 参数2:通知值 41 参数3: 42 eNoAction = 0,无动作,通知任务而不更新其通知值 43 eSetBits, 任务的通知值与ulValue按位或 44 eIncrement, 任务的通知值增加1 45 eSetValueWithOverwrite, 复写方式更新通知值,不管任务是否读取该值,都将更新通知值 46 eSetValueWithoutOverwrite 如果任务已经读取了之前的值,则设置任务的通知值 47 */ 48 xTaskNotify(TaskH_0,num,eSetValueWithoutOverwrite); 49 } 50 }
小试牛刀(任务同步与自动加一效果)
1 #include <stdio.h> 2 #include "freertos/FreeRTOS.h"//freertos相关 3 #include "freertos/task.h" 4 #include "freertos/semphr.h" 5 //任务句柄 6 TaskHandle_t TaskH_0=NULL; 7 8 //任务0处理函数 9 void Task_Run_0(){ 10 uint32_t Noti_vlaue=0; 11 while(1){ 12 /* 13 参数1:进入时,传递的参数取反后按位与来设定任务通知初值(ULONG_MAX表示清零,0表示值不变,其他值按规则) 14 参数2:退出时,传递的参数取反后按位与来设定任务通知初值(ULONG_MAX表示清零,0表示值不变,其他值按规则) 15 参数3:通知值获取 16 参数4:等待时间 17 */ 18 xTaskNotifyWait(0,0,&Noti_vlaue,portMAX_DELAY); 19 printf("【task 0】接收到通知,其值为:%d\r\n",Noti_vlaue); 20 } 21 } 22 //主函数,优先级为1 23 void app_main() 24 { 25 printf("\r\n--------------DONGIXAODONG FreeRTOS-----------------\r\n"); 26 27 //启动任务0,简化 28 //函数,名字,字节大小,参数,优先级[0,16](16最优先),任务句柄 29 BaseType_t t0res=xTaskCreate(Task_Run_0,"DONG Task_Run_0",1024*2,NULL,7,&TaskH_0); 30 if(t0res==pdPASS){ 31 printf("任务0启动成功....\r\n"); 32 } 33 while(1){ 34 vTaskDelay(3000 / portTICK_PERIOD_MS);//延时3S 35 printf("【main】DONG 即将发送一次通知\r\n"); 36 /* 37 参数1:任务句柄 38 参数2:通知值 39 参数3: 40 eNoAction = 0,无动作,通知任务而不更新其通知值 41 eSetBits, 任务的通知值与ulValue按位或 42 eIncrement, 任务的通知值增加1 43 eSetValueWithOverwrite, 复写方式更新通知值,不管任务是否读取该值,都将更新通知值 44 eSetValueWithoutOverwrite 如果任务已经读取了之前的值,则设置任务的通知值 45 */ 46 xTaskNotify(TaskH_0,0,eIncrement); 47 } 48 }
参考:
https://zhidao.baidu.com/question/7412988.html
ESP32文档:https://docs.espressif.com/projects/esp-idf/en/v4.0/api-reference/system/freertos.html
正点原子