FreeRTOS消息队列、信号量、队列集、事件标志组与任务通知

一、消息队列

1.1使用场景

队列是一种任务到任务、任务到中断、中断到任务数据交流的一种机制。在队列中可以存储数量有限、大小固定的多个数据,队列中的每一个数据叫做队列项目,队列能够存储队列项目的最大数量称为队列的长度,在创建队列的时候,就需要指定所创建队列的长度及队列项目的大小。因为队列是用来在任务与任务或任务与中断之间传递消息的一种机制,因此队列也叫消息队列。

对于共同获取一个队列的不同任务,系统会根据任务优先级进行获取顺序的分配。 

 应用队列实现数据交流的优点:

  • 使用全局变量难以处理同时写入造成的数据安全性问题。而队列带有中断保护,可以保证数据安全性。

1.2特点

  1. 数据存储:队列通常采用FIFO(先进先出)的存储缓冲机制,当有新的数据被写入队列中时,永远都是写入到队列的尾部,而从队列中读取数据时,永远都是读取队列的头部数据。但同时FreeRTOS 的队列也支持将数据写入到队列的头部,并且还可以指定是否覆盖先前已经在队列头部的数据。
  2. 多任务访问:队列不属于某个特定的任务,可以在任何的任务或中断中往队列中写入消息,或者从队列 中读取消息。
  3. 队列读取阻塞:在任务从队列读取消息时,可以指定一个阻塞超时时间。如果任务在读取队列时,队列为空,这时任务将被根据指定的阻塞超时时间添加到阻塞态任务列表中进行阻塞,以等待队列中有可用的消息。当有其他任务或中断将消息写入队列中,因等待队列而阻塞任务将会被添加到就绪态任务列表中,并读取队列中可用的消息。如果任务因等待队列而阻塞的时间超过指定的阻塞超时时间,那么任务也将自动被转移到就绪态任务列表中,但不再读取队列中的数据。
  4. 队列写入阻塞:与队列读取一样,在任务往队列写入消息时,也可以指定一个阻塞超时时间。如果任务在写入队列时,队列已经满了,这时任务将被根据指定的阻塞超时时间添加到阻塞态任务列表中进行阻塞,以等待队列有空闲的位置可以写入消息。指定的阻塞超时时间为任务阻塞的最大时间,如果在阻塞超时时间到达之前,队列有空闲的位置,那么队列写入阻塞任务将会解除阻塞,并往队列中写入消息,如果达到指定的阻塞超时时间,队列依旧没有空闲的位置写入消息,那么队列写入阻塞任务将会自动转移到就绪态任务列表中,但不会往队列中写入消息。

1.3相关API函数

1.3.1创建消息队列API函数

与任务创建类似,根据内存空间的分配不同分为动态创建与静态创建。

动态创建

#define xQueueCreate( uxQueueLength,     uxItemSize )            \ 
xQueueGenericCreate( ( uxQueueLength ),        \ 
                    ( uxItemSize ),         \ 
                    ( queueQUEUE_TYPE_BASE ))

 入口参数:

  1. uxQueueLength:队列长度
  2. uxItemSize:队列项目的大小

返回值:

  •  NULL:队列创建失败
  • 其他值:队列创建成功,返回队列的起始地址

静态创建: 

#define xQueueCreateStatic( uxQueueLength,          \ 
                            uxItemSize,           \ 
                            pucQueueStorage,         \ 
                            pxQueueBuffer)          \ 
      xQueueGenericCreateStatic( ( uxQueueLength ),       \ 
                                 ( uxItemSize ),        \ 
                                 ( pucQueueStorage ),      \ 
                                 ( pxQueueBuffer ),       \ 
                                 ( queueQUEUE_TYPE_BASE ))

 入口参数:

  1. uxQueueLength:队列长度
  2. uxItemSize:队列项目的大小
  3. pucQueueStorage:队列存储区域的起始地址
  4. pxQueueBuffer:静态队列结构体

返回值:

  •  NULL:队列创建失败
  • 其他值:队列创建成功,返回队列的起始地址

1.3.2向队列写入消息API函数

任务级往队列的尾部写入消息函数

#define xQueueSend(   xQueue,            \ 
           pvItemToQueue,          \ 
           xTicksToWait)          \ 
      xQueueGenericSend( ( xQueue ),           \ 
           ( pvItemToQueue ),         \ 
           ( xTicksToWait ),         \ 
           queueSEND_TO_BACK)
#define xQueueSendToBack( xQueue,            \ 
           pvItemToQueue,          \ 
           xTicksToWait)          \ 
      xQueueGenericSend( ( xQueue ),           \ 
           ( pvItemToQueue ),         \ 
           ( xTicksToWait ),         \ 
           queueSEND_TO_BACK)

 入口参数:

  1. xQueue:待写入的队列
  2. pvItemToQueue:待写入消息
  3. xTicksToWait:阻塞超时时间(portMAX_DELAY则为永久等待)

 返回值:

  • pdTRUE:队列写入成功
  • errQUEUE_FULL:队列写入失败

 中断级往队列的尾部写入消息函数

#define xQueueSendFromISR(   xQueue,          \ 
                             pvItemToQueue,        \ 
                             pxHigherPriorityTaskWoken)     \ 
      xQueueGenericSendFromISR( ( xQueue ),         \ 
                                 ( pvItemToQueue ),       \ 
                                 ( pxHigherPriorityTaskWoken ),    \ 
                                     queueSEND_TO_BACK) 
 
#define xQueueSendToBackFromISR( xQueue,          \ 
                                 pvItemToQueue,        \ 
                                 pxHigherPriorityTaskWoken)     \ 
      xQueueGenericSendFromISR( ( xQueue ),         \ 
                                 ( pvItemToQueue ),       \ 
                                 ( pxHigherPriorityTaskWoken ),    \ 
                                     queueSEND_TO_BACK)

入口参数 pxHigherPriorityTaskWoken表示是否需要任务切换。

任务级往队列的头部写入消息函数:

#define xQueueSendToFront( xQueue,            \ 
                           pvItemToQueue,          \ 
                          xTicksToWait)          \ 
      xQueueGenericSend( ( xQueue ),           \ 
                           ( pvItemToQueue ),         \ 
                           ( xTicksToWait ),         \ 
                           queueSEND_TO_FRONT)

 中断级往队列的头部写入消息函数:

#define xQueueSendToFrontFromISR( xQueue,          \ 
                                 pvItemToQueue,        \ 
                                 pxHigherPriorityTaskWoken)     \ 
      xQueueGenericSendFromISR( ( xQueue ),         \ 
                                 ( pvItemToQueue ),       \ 
                                ( pxHigherPriorityTaskWoken ),    \ 
                                     queueSEND_TO_FRONT)

 任务级覆写队列消息(只用于队列长度为1的情况):

#define xQueueOverwrite( xQueue,            \ 
                        pvItemToQueue)          \ 
      xQueueGenericSend( ( xQueue ),           \ 
                       ( pvItemToQueue ),         \ 
                           0,\ 
                        queueOVERWRITE)

 中断级覆写队列消息(只用于队列长度为1的情况):

#define xQueueOverwriteFromISR(  xQueue,          \ 
                                 pvItemToQueue,        \ 
                                 pxHigherPriorityTaskWoken)     \ 
      xQueueGenericSendFromISR( ( xQueue ),         \ 
                                 ( pvItemToQueue ),       \ 
                                 ( pxHigherPriorityTaskWoken ),    \ 
                                 queueOVERWRITE)

1.3.3从队列读取消息API函数

任务级从队列头部读取消息并删除函数

BaseType_t xQueueReceive( QueueHandle_t xQueue, 
                           void * const pvBuffer, 
                           TickType_t  xTicksToWait); 

 入口参数:

  1. xQueue:待读取的队列
  2. pvBuffer:信息读取缓冲区
  3. xTicksToWait:阻塞超时时间

中断级从队列头部读取消息并删除函数

BaseType_t xQueueReceiveFromISR( 
                QueueHandle_t  xQueue, 
                void * const  pvBuffer, 
                BaseType_t * const pxHigherPriorityTaskWoken);

 入口参数 pxHigherPriorityTaskWoken表示是否需要任务切换。

任务级从队列头部读取消息函数:

BaseType_t xQueuePeek( QueueHandle_t xQueue, 
                        void * const pvBuffer, 
                        TickType_t  xTicksToWait);

中断级从队列头部读取消息函数:

BaseType_t xQueuePeekFromISR( QueueHandle_t xQueue, 
                                void * const pvBuffer);

二、信号量

2.1使用场景

信号量是一种解决同步问题的机制,可以实现对共享资源的有序访问。其中,“同步”指的 是任务间的同步,即信号量可以使得一个任务等待另一个任务完成某件事情后,才继续执行; 而“有序访问”指的是对被多任务或中断访问的共享资源(如全局变量)的管理,当一个任务在访问(读取或写入)一个共享资源时,信号量可以防止其他任务或中断在这期间访问(读取 或写入)这个共享资源。

2.2二值信号量

2.2.1简介

二值信号量实际上就是一个队列长度为1的队列,在这种情况下,队列就只有空和满两种情况。二 值信号量通常用于互斥访问或任务同步。

对于二值信号量:

  • 释放:将标志置满(1)
  • 获取:将标志取空(0)

 和队列一样,在获取二值信号量的时候,允许设置一个阻塞超时时间,阻塞超时时间是当任务获取二值信号量时,由于二值信号量处于没有资源的状态,而导致任务进入阻塞状态的最大系统时钟节拍数。如果多个任务同时因获取同一个处于没有资源状态的二值信号量而被阻塞,那么在二值信号量有资源的时候,这些阻塞任务中优先级高的任务将优先获得二值信号量的资源并解除阻塞。

2.2.2API函数

使用动态方式创建二值信号量函数

#define xSemaphoreCreateBinary()           \ 
            xQueueGenericCreate( ( UBaseType_t ) 1,        \ 
                    semSEMAPHORE_QUEUE_ITEM_LENGTH,    \ 
                            queueQUEUE_TYPE_BINARY_SEMAPHORE)

 使用静态方式创建二值信号量函数

#define xSemaphoreCreateBinaryStatic(pxStaticSemaphore)      \ 
    xQueueGenericCreateStatic( ( UBaseType_t ) 1,       \ 
                            semSEMAPHORE_QUEUE_ITEM_LENGTH,   \
                                    NULL,       \   
                                pxStaticSemaphore,   \
                               queueQUEUE_TYPE_BINARY_SEMAPHORE) 

任务级获取信号量函数

#define xSemaphoreTake(   xSemaphore,          \ 
                            xBlockTime)          \ 
      xQueueSemaphoreTake( ( xSemaphore ),         \ 
                            ( xBlockTime )) 

 中断级获取信号量函数

#define xSemaphoreTakeFromISR( xSemaphore,          \ 
                                pxHigherPriorityTaskWoken)      \ 
      xQueueReceiveFromISR( ( QueueHandle_t ) ( xSemaphore ),    \ 
                                NULL,           \ 
                                ( pxHigherPriorityTaskWoken )) 

 任务级释放信号量函数

#define xSemaphoreGive(  xSemaphore)           \ 
      xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ),     \ 
                                   NULL,            \ 
                               semGIVE_BLOCK_TIME,         \ 
                               queueSEND_TO_BACK)

 中断级释放信号量函数

#define xSemaphoreGiveFromISR( xSemaphore,          \ 
                                pxHigherPriorityTaskWoken)      \ 
      xQueueGiveFromISR(  ( QueueHandle_t ) ( xSemaphore ),    \ 
                            ( pxHigherPriorityTaskWoken ))

 删除信号量函数

#define vSemaphoreDelete(xSemaphore)           \ 
            vQueueDelete ( QueueHandle_t )  ( xSemaphore )) 

2.3计数型信号量

2.3.1简介

计数型信号量相当于队列长度大于 0 的队列,因此计数型信号量能够容纳多个资源,这是在计数型信号量被创建的时候确定的。

计数型信号量通常用于以下两个场合:

  • 事件计数:在这种场合下,每次事件发生后,在事件处理函数中释放计数型信号量(计数型信号量的 资源数加1),其他等待事件发生的任务获取计数型信号量(计数型信号量的资源数减1),这么一来等待事件发生的任务就可以在成功获取到计数型信号量之后执行相应的操作。在这种场合 下,计数型信号量的资源数一般在创建时设置为0
  • 资源管理:在这种场合下,计数型信号量的资源数代表着共享资源的可用数量。一个任务想要访问共享资源,就必须先获取这个共享资源的计数型信号量,之后在成功获取了计数型信号量之后,才可以对这个共享资源进行访问操作,当然,在使用完共享资源后也要释放这个共享资源的计数型信号量。在这种场合下,计数型信号量的资源数一般在创建时设置为受其管理的共享资源的最大可用数量

2.3.2API函数

使用动态方式创建计数型信号量函数

#define xSemaphoreCreateCounting(  uxMaxCount,        \ 
                                    uxInitialCount )     \ 
xQueueCreateCountingSemaphore( ( uxMaxCount ),       \ 
                               ( uxInitialCount ))

 入口参数:

  1. uxMaxCount:最大计数值
  2. uxInitialCount:初始计数值

 使用静态方式创建计数型信号量函数

#define xSemaphoreCreateCountingStatic(  uxMaxCount,      \ 
                                         uxInitialCount,     \ 
                                        pxSemaphoreBuffer)   \ 
xQueueCreateCountingSemaphoreStatic( ( uxMaxCount ),     \ 
                                      ( uxInitialCount ),    \ 
                                     ( pxSemaphoreBuffer ))

计数型信号量的获取、释放与删除使用的API函数与二值信号量一致。

2.4互斥信号量

2.4.1优先级翻转

优先级翻转问题指的是,当一个高优先级任务因获取一个被低优先级任务获取而处于没有资源状态的二值信号量时,这个高优先级的任务将被阻塞,直到低优先级的任务释放二值信号量,而在这之前,如果有一个优先级介于这个高优先级任务和低优先级任务之间的任务就绪,那么这个中等优先级的任务就会抢占低优先级任务的运行,这么一来,这三个任务中优先级最高的任务反而要最后才运行

2.4.2简介

互斥信号量其实就是一个拥有优先级继承的二值信号量

优先级继承:当一个互斥信号量正在被一个低优先级的任务持有时,如果此时有个高优先级的任务也尝试获取这个互斥信号量,那么这个高优先级的任务就会被阻塞。不过这个高优先级的任务会将低优先级任务的优先级提升到与自己相同的优先级,这个过程就是优先级继承。优先级继承尽可能的减少了高优先级任务处于阻塞态的时间,并且将“优先级翻转”的影响降到最低。

 与二值信号量相比,互斥信号量更适合用于互斥访问。

互斥信号量不能用于中断服务函数中:

  • 互斥信号量有任务优先级继承的机制,但是中断不是任务,没有任务优先级,所以互斥 信号量只能用于任务中,不能用于中断服务函数。
  • 中断服务函数中不能因为要等待互斥信号量而设置阻塞时间进入阻塞态。

2.4.3API函数

使用动态方式创建互斥信号量函数

#define xSemaphoreCreateMutex()  xQueueCreateMutex(queueQUEUE_TYPE_MUTEX) 

 使用静态方式创建互斥信号量函数

#define xSemaphoreCreateMutexStatic( pxMutexBuffer)       \ 
      xQueueCreateMutexStatic(  queueQUEUE_TYPE_MUTEX,     \ 
                                  ( pxMutexBuffer ) ) 

互斥信号量的获取、释放与删除使用的API函数与二值信号量一致。

三、队列集

3.1简介

在使用队列进行任务之间的“沟通交流”时,一个队列只允许任务间传递的消息为同一种 数据类型,如果需要在任务间传递不同数据类型的消息时,那么就可以使用队列集。FreeRTOS 提供的队列集可以对多个队列或队列和信号量进行“监听”,只要被监听的队列中有一个队列有有效的消息, 那么队列集的读取任务都可以读取到消息,如果读取任务因读取队列集而被阻塞,那么队列集将解除读取任务的阻塞。使用队列集的好处在于,队列集可以是的任务可以读取多个队列中的消息,而无需遍历所有待读取的队列,以确定具体读取哪一个队列。

使用队列集可以解决任务需要从多个队列都获取消息的问题。在不使用队列集的情况下,因为获取函数有先后顺序,可能造成等待第一个队列阻塞而导致后面队列中已有消息但因任务阻塞而无法获取的情况。使用队列集则在队列集中任意队列有消息时结束阻塞,提高消息获取效率。

使用队列集功能,需要将配置项configUSE_QUEUE_SETS配置为1。

3.2API函数

创建队列集函数

QueueSetHandle_t xQueueCreateSet(const UBaseType_t uxEventQueueLength); 

入口参数:

  1.  uxEventQueueLength:队列集可容纳的队列数量

返回值:

  •  NULL:队列集创建失败
  • 其他值:队列集创建成功,返回队列集

 队列添加到队列集中函数

BaseType_t xQueueAddToSet( QueueSetMemberHandle_t xQueueOrSemaphore, 
                           QueueSetHandle_t  xQueueSet); 

注意,队列在被添加到队列集之前,队列中不能有有效信息。

入口参数:

  1.  xQueueOrSemaphore:待添加的队列/信号量
  2. xQueueSet:队列集

返回值:

  •  pdPASS:队列集添加队列成功
  • pdFAIL:队列集添加队列失败

 从队列集中移除队列函数:

BaseType_t xQueueRemoveFromSet( QueueSetMemberHandle_t xQueueOrSemaphore, 
                                QueueSetHandle_t  xQueueSet);

注意,队列在从队列集移除之前,队列中不能有有效信息。

入口参数:

  1.  xQueueOrSemaphore:待移除的队列/信号量
  2. xQueueSet:队列集

返回值:

  •  pdPASS:队列集移除队列成功
  • pdFAIL:队列集移除队列失败

 获取队列集中有有效消息的队列函数

QueueSetMemberHandle_t xQueueSelectFromSet(  QueueSetHandle_t xQueueSet, 
                                              TickType_t const xTicksToWait); 

入口参数:

  1.  xQueueSet:队列集
  2. xTicksToWait:阻塞超时时间

返回值:

  • NULL:获取消息失败
  • 其他值:获取到消息的队列

在中断中获取队列集中有有效消息的队列函数

QueueSetMemberHandle_t xQueueSelectFromSetFromISR(  QueueSetHandle_t xQueueSet ); 

四、事件标志组

4.1简介

事件标志:事件标志是一个用于指示事件是否发生的布尔值,一个事件标志只有 0 或 1 两种状态。

事件组:多个事件标志储存在一个变量类型为EventBits_t变量中,这个变量就是事件组。

EventBits_t 是一个 32 位无符号的数据类型,其中低24位[23:0]用于存储事件标志,而高8位[31:24]用作存储事件标志组的一些控制信息。也就是说一个事件组最多可以存储24个事件标志

 事件标志组适用于等待一个或多个事件标志位针对所有符合条件的任务进行唤醒。对标志位的等待由用户设置,可用于多任务同步或者系统状态监控等复杂场景。同时事件标志组支持在等待过程中清除已满足的标志。

4.2API函数

使用动态方式创建事件标志组函数

EventGroupHandle_t xEventGroupCreate(void); 

返回值:

  •  NULL:事件标志组创建失败
  • 其他值:事件标志组创建成功,返回其句柄

 使用静态方式创建事件标志组函数

EventGroupHandle_t xEventGroupCreateStatic( StaticEventGroup_t * pxEventGroupBuffer); 

 删除事件标志组函数

void vEventGroupDelete(EventGroupHandle_t xEventGroup); 

 等待事件标志位函数:

EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, 
                                 const EventBits_t uxBitsToWaitFor, 
                                 const BaseType_t xClearOnExit, 
                                 const BaseType_t xWaitForAllBits, 
                                 TickType_t   xTicksToWait) 

 入口参数:

  1. xEvenrGroup:等待的事件标志组
  2. uxBitsToWaitFor:等待的事件标志位,可以用逻辑或等待多个事件标志位
  3. xClearOnExi:成功等待到事件标志位后,是否清除事件组中对应的事件标志位(pdTRUE为清除,pdFALSE为不清除)
  4. xWaitForAllBits:是否等待uxBitsToWaitFor 中的所有事件标志位(pdTRUE为等待的位全部为1时唤醒,pdFALSE为等待的位一位为1时唤醒)
  5. xTicksToWait:等待的阻塞时间

返回值:

  •  等待的事件标志位值:等待事件标志位成功,返回等待到的事件标志位
  • 其他值:等待事件标志位失败,返回事件组中的事件标志位

 任务级设置事件标志位函数:

EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, 
                                const EventBits_t uxBitsToSet) 

入口参数:

  1.  xEventGroup:待操作的事件标志组
  2. uxBitsToSet:待设置的事件标志位

返回值为事件组的事件标志位值。

中断级设置事件标志位函数:

BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, 
                                        const EventBits_t uxBitsToSet, 
                                        BaseType_t *  pxHigherPriorityTaskWoken) 

 

 任务级清除事件标志位函数:

EventBits_t xEventGroupClearBits( EventGroupHandle_t xEventGroup, 
                                    const EventBits_t uxBitsToClear) 

入口参数:

  1.  xEventGroup:待操作的事件标志组
  2. uxBitsToSet:待清零的事件标志位

返回值为清零事件标志位之前事件组中事件标志位的值。

中断级清除事件标志位函数:

BaseType_t xEventGroupClearBitsFromISR( EventGroupHandle_t EventGroup, 
                                        const EventBits_t uxBitsToClear) 

任务级获取事件组中各事件标志位的值函数:

EventBits_t xEventGroupGetBits(xEventGroup); 

中断级获取事件组中各事件标志位的值函数:

EventBits_t xEventGroupGetBitsFromISR(EventGroupHandle_t xEventGroup); 

事件标志组同步函数

EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup, 
                            const EventBits_t uxBitsToSet, 
                            const EventBits_t uxBitsToWaitFor, 
                            TickType_t   xTicksToWait) 

 该函数一般用于多任务同步,每个任务都必须等待其他任务达到同步点然后才能继续执行。

入口参数:

  1. xEventGroup:等待事件标志所在事件组
  2. uxBitsToSet:达到同步点后,要设置的事件标志
  3. uxBitsToWaitFor:等待的事件标志
  4. xTicksToWait:等待的阻塞时间

返回值:

  • 等待的事件标志位值:等待事件标志位成功,返回等待到的事件标志位
  • 其他值:等待事件标志位失败,返回事件组中的事件标志位

五、任务通知

5.1简介

在FreeRTOS 中,每一个任务都有两个用于任务通知功能的数组,分别为任务通知数组任务通知状态数组。其中任务通知数组中的每一个元素都是一个32位无符号类型的通知值;而 任务通知状态数组中的元素则表示与之对应的任务通知的状态。

任务通知数组:32位无符号通知值用于任务到任务或中断到任务发送通知的“媒介”。 当通知值为0时,表示没有任务通知;当通知值不为0时,表示有任务通知,并且通知值就是通知的内容。

任务通知状态数组:任务通知状态数组中的元素,用于标记任务通知数组中通知的状态,任务通知有三种状态,分别为未等待通知状态、等待通知状态和等待接收通知状态。

  • 未等待通知状态:复位状态
  • 等待通知状态:任务在没有通知的时候接收通知时&在任务阻塞等待任务通知的时候
  • 等待接收通知状态:有其他任务向任务发送通知,但任务还未接收这一通知的这段期间内

 任务通知功能所使用到的任务通知数组和任务通知状态数组为任务控制块中的成员变量, 因此任务通知的传输是直接传出到任务中的,不同通过任务的通讯对象(队列、事件标志组和信号量就属于通讯对象)这个间接的方式。

 任务通知的优点

  • 相比与使用通讯对象的间接通讯要快速
  • 无需创建通讯对象,节省大量内存

任务通知的缺点

  • 无法发送事件或数据到中断
  • 无法同时发送给多个任务
  • 无法缓冲多个数据项
  • 无法阻塞等待

5.2API函数

①任务级发送任务通知函数

xTaskNotify()往指定任务发送任务通知,通知方式可以自由指定,并且不获取发送任务通知 前任务通知的通知值
xTaskNotifyAndQuery()往指定任务发送任务通知,通知方式可以自由指定,并且获取发送任务通知前 任务通知的通知值
xTaskNotifyGive()往指定任务发送任务通知,通知方式为将通知值加1,并且不获取发送任务通 知前任务通知的通知值

 xTaskNotify()

#define xTaskNotify( xTaskToNotify, ulValue, eAction)            \
xTaskGenericNotify( (xTaskToNotify), (tskDEFAULT_INDEX_TO_NOTIFY),       \ 
                    (ulValue),(eAction), NULL) 

入口参数:

  1.  xTaskToNotify:接收任务通知的任务
  2. ulValue:通知值
  3. eAction:通知方式

 eNotifyAction定义如下:

typedef enum
{
    eNoAction=0, //无操作
    eSetBits, //更新指定bit
    eIncrement,//通知值加一
    eSetValueWithOverwrite,//覆写的方式更新通知值
    eSetValueWithoutOverwrite//不覆写通知值
}eNotifyAction;

 xTaskNotifyAndQuery()

#define xTaskNotifyAndQuery( xTaskToNotify, ulValue, eAction,pulPreviousNotifyValue)  \
        xTaskGenericNotify(   (xTaskToNotify), (tskDEFAULT_INDEX_TO_NOTIFY),(ulValue),  \                             
                                (eAction),  (pulPreviousNotifyValue))

 该函数与xTaskNotify()的入口参数类似。其中第四个入口参数pulPreviousNotifyValue是uint32_t类型的指针,用于获取发送通知前的通知值。

xTaskNotifyGive():

#define xTaskNotifyGive( xTaskToNotify)          \ 
    xTaskGenericNotify(  (xTaskToNotify), (tskDEFAULT_INDEX_TO_NOTIFY),      \ 
                           (0), eIncrement, NULL)

②中断级发送任务通知函数:

中断级与任务级类似,但每个函数都会另有一个pxHigherPriorityTaskWoken参数用于标记函数退出后是否需要进行任务切换。

③接收任务通知函数:

注意,任务通知无法在中断中接收。

ulTaskNotifyTake()获取任务通知,可以设置在退出此函数时将任务通知值清零或减一。当任务通知用作二值信号量或者计数信号量时,使用此函数来获取信号量。
xTaskNotifyWait()获取任务通知,比上一个函数更为复杂,可获取通知值和清除通知值的指定位

 ulTaskNotifyTake():

#define ulTaskNotifyTake(  xClearCountOnExit, xTicksToWait)         \ 
        ulTaskGenericNotifyTake( (tskDEFAULT_INDEX_TO_NOTIFY), (xClearCountOnExit),(xTicksToWait)) 

 入口参数:

  1. xClearCountOnExit:指定在成功接收通知后,将通知值清零或减1(pdTRUE为将通知值清零,pdFALSE为将通知值减一)
  2. xTicksToWait:阻塞等待任务通知值的最大时间

返回值:

  •  0:接受失败
  • 非0:接收成功,返回任务通知值的通知值

 xTaskNotifyWait():

#define xTaskNotifyWait( ulBitsToClearOnEntry,        \ 
                         ulBitsToClearOnExit,        \ 
                         pulNotificationValue,        \ 
                         xTicksToWait)          \ 
    xTaskGenericNotifyWait( tskDEFAULT_INDEX_TO_NOTIFY,       \ 
                           (ulBitsToClearOnEntry),        \ 
                           (ulBitsToClearOnExit),        \ 
                           (pulNotificationValue),        \ 
                           (xTicksToWait)) 

 入口参数:

  1. ulBitesToClearOnEntry:等待前指定清零的任务通知通知值比特位
  2. ulBitesToClearOnExit:成功等待后指定清零的任务通知通知值比特位
  3. pulNotificationValue:等待超时后任务通知的通知值
  4. xTicksToWait:阻塞等待任务通知值的最大时间 

六、对比

通讯方式数据数量数据类型通讯对象应用场景
队列间接通讯一个或多个可任意指定多对多基本数据交流
二值信号量间接通讯一个布尔一对一双任务同步
计数型信号量间接通讯多个计数值多对多事件计数和资源管理
互斥信号量间接通讯一个布尔一对一互斥访问
队列集间接通讯多个取决于队列集的成员多对多需要同时接收多个队列/信号量
事件标志组间接通讯24个标志位多对多多任务同步和系统状态监控
任务通知直接通讯一个或多个取决于通知方式一对一任务间高效节省内存通讯

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值