9.1本章介绍与范围

已经看到,使用FreeRTOS的应用程序被构造为一组独立的任务,并且这些任务很可能必须彼此通信,以便它们可以共同提供有用的系统功能。

通过中介对象进行通信

本书已经描述了任务之间可以相互通信的各种方式。 到目前为止描述的方法需要创建通信对象。 通信对象的示例包括队列,事件组和各种不同类型的信号量。

使用通信对象时,事件和数据不会直接发送到接收任务或接收ISR,而是会发送到通信对象。 同样,任务和ISR从通信对象接收事件和数据,而不是直接从发送事件或数据的任务或ISR接收事件和数据。 这在图76中进行了描述。

任务通知-直接进行任务通信

“任务通知”允许任务与其他任务进行交互,并与ISR同步,而无需单独的通信对象。 通过使用任务通知,任务或ISR可以将事件直接发送到接收任务。 这在图77中进行了描述。

任务通知功能是可选的。 要包括任务通知功能,请在FreeRTOSConfig.h中将configUSE_TASK_NOTIFICATIONS设置为1。

当configUSE_TASK_NOTIFICATIONS设置为1时,每个任务都有一个“通知状态”(可以是“挂起”或“未挂起”)和一个“通知值”(一个32位无符号整数)。 当一个任务收到通知,其通知状态设置为挂起。 当任务读取其通知值时,其通知状态将设置为“未挂起”。

任务可以在“阻止”状态下等待,并具有可选的超时时间,以使其通知状态变为挂起状态。

范围

本章旨在使读者更好地理解:

  • 任务的通知状态和通知值。
  • 如何以及何时可以使用任务通知代替通信对象(例如信号量)。
  • 使用任务通知代替通信对象的优点。

9.2任务通知; 好处和局限性

任务通知的性能优势

使用任务通知将事件或数据发送到任务比使用队列,信号量或事件组执行等效操作要快得多。

任务通知的RAM足迹优势

同样,与使用队列,信号量或事件组执行等效操作相比,使用任务通知将事件或数据发送到任务所需的RAM要少得多。 这是因为必须先创建每个通信对象(队列,信号量或事件组),然后才能使用它,而启用任务通知功能具有固定的开销,即每个任务只有8个字节的RAM。

任务通知的局限性

与通信对象相比,任务通知速度更快并且使用的RAM更少,但是任务通知不能在所有情况下都使用。 本节介绍了无法使用任务通知的方案:

  • 将事件或数据发送到ISR
    通信对象可用于从ISR向任务以及从任务向ISR发送事件和数据。
    任务通知可用于将事件和数据从ISR发送到任务,但不能用于将事件或数据从任务发送到ISR。

  • 启用多个接收任务
    任何知道其句柄(可能是队列句柄,信号量句柄或事件组句柄)的任务或ISR都可以访问该通信对象。 任何数量的任务和ISR都可以处理发送到任何给定通信对象的事件或数据。
    任务通知直接发送到接收任务,因此只能由发送通知的任务处理。 但是,这在实际情况中很少受到限制,因为尽管有多个任务和ISR发送到相同的通信对象是很常见的,但很少有多个任务和ISR从同一个通信对象接收到。

  • 缓冲多个数据项
    队列是一次可以容纳多个数据项的通信对象。 已发送到队列但尚未从队列接收的数据被缓冲在队列对象中。
    任务通知通过更新接收任务的通知值将数据发送到任务。 任务的通知值一次只能保存一个值。

  • 广播多个任务
    事件组是一个通信对象,可用于一次将事件发送到多个任务。
    任务通知直接发送到接收任务,因此只能由接收任务处理。

  • 在阻止状态下等待发送完成
    如果通信对象暂时处于无法再写入任何数据或事件的状态(例如,当队列已满时,无法再向该队列发送任何数据),则尝试写入该对象的任务可以 (可选)进入“阻止”状态,以等待其写入操作完成。
    如果任务试图将任务通知发送到已经有待处理的通知的任务,则发送任务不可能在“阻止”状态下等待接收任务重置其通知状态。 可以看出,在使用任务通知的实际情况下,这很少是一种限制。

9.3使用任务通知

任务通知API选项

任务通知是一项非常强大的功能,通常可以用来代替二进制信号量,计数信号量,事件组,有时甚至是队列。 通过使用xTaskNotify()API函数发送任务通知,并使用xTaskNotifyWait()API函数接收任务通知,可以实现广泛的使用场景。

但是,在大多数情况下,不需要xTaskNotify()和xTaskNotifyWait()API函数提供的完全灵活性,并且更简单的函数就足够了。 因此,提供xTaskNotifyGive()API函数作为xTaskNotify()的一种更简单但不太灵活的替代方法,并且提供ulTaskNotifyTake()API函数作为xTaskNotifyWait()的一种更简单但不太灵活的替代方法。

xTaskNotifyGive()API函数

xTaskNotifyGive()直接向任务发送通知,并增加(添加一个)接收任务的通知值。 调用xTaskNotifyGive()会将接收任务的通知状态设置为“挂起”(如果尚未挂起)。

提供了xTaskNotifyGive()1 API函数,以使任务通知的重量更轻,并且可以更快地替代二进制或计数信号量。

Parameter Name/ Returned Value Description
xTaskToNotify 将通知发送到的任务的句柄-有关获取任务句柄的信息,请参阅xTaskCreate()API函数的pxCreatedTask参数。
Returned value xTaskNotifyGive()是调用xTaskNotify()的宏。 设置宏传递给xTaskNotify()的参数,以使pdPASS是唯一可能的返回值。 本书稍后将介绍xTaskNotify()。

vTaskNotifyGiveFromISR()API函数

vTaskNotifyGiveFromISR()是xTaskNotifyGive()的一个版本,可以在中断服务程序中使用。

Parameter Name/ Returned Value Description
xTaskToNotify 将通知发送到的任务的句柄-有关获取任务句柄的信息,请参阅xTaskCreate()API函数的pxCreatedTask参数。
pxHigherPriorityTaskWoken 如果要向其发送通知的任务正处于“阻止”状态以接收通知,则发送通知将使任务退出“阻止”状态。如果调用vTaskNotifyGiveFromISR()导致任务退出“已阻止”状态,并且未阻止的任务的优先级高于当前正在执行的任务(被中断的任务)的优先级,则内部vTaskNotifyGiveFromISR()会将* pxHigherPriorityTaskWoken设置为 pdTRUE。如果vTaskNotifyGiveFromISR()将此值设置为pdTRUE,则应在退出中断之前执行上下文切换。 这将确保中断直接返回到最高优先级的就绪状态任务。与所有中断安全API函数一样,在使用pxHigherPriorityTaskWoken参数之前,必须将其设置为pdFALSE。

ulTaskNotifyTake()API函数

ulTaskNotifyTake()允许任务在“阻止”状态下等待其通知值大于零,并且可以在执行任务返回之前递减(从中减去1)或清除任务的通知值。

提供了ulTaskNotifyTake()API函数,以使任务通知的重量更轻,并且可以更快地替代二进制或计数信号量。

Parameter Name/ Returned Value Description
xClearCountOnExit 如果xClearCountOnExit设置为pdTRUE,则调用任务的通知值将在对ulTaskNotifyTake()的调用返回之前清除为零。如果xClearCountOnExit设置为pdFALSE,并且调用任务的通知值大于零,则在调用ulTaskNotifyTake()返回之前,将减小调用任务的通知值。
xTicksToWait 调用任务应等待其通知值大于零的最大时间。块时间以滴答周期指定,因此它表示的绝对时间取决于滴答频率。 宏pdMS_TO_TICKS()可用于将以毫秒为单位的时间转换为以滴答数为单位的时间。将xTicksToWait设置为portMAX_DELAY将导致任务无限期地等待(没有超时),前提是提供在FreeRTOSConfig.h中将INCLUDE_vTaskSuspend设置为1。
Returned value 返回值是调用任务的通知值,该值在被清除为零或递减之前(由xClearCountOnExit参数的值指定)。如果指定了阻止时间(xTicksToWait不为零),并且返回值不为零,则可能会将调用任务置于“阻止”状态,以等待其通知值大于零,并等待其通知 阻止时间到期前,值已更新。如果指定了阻止时间(xTicksToWait不为零),并且返回值为零,则将调用任务置于“阻止”状态,以等待其通知值大于零,但是指定的阻止时间在 那事发生了。

例子24.使用任务通知代替信号量,方法1

示例16使用二进制信号量从中断服务例程中取消阻止任务-有效地将任务与中断同步。 此示例复制了示例16的功能,但使用直接任务通知来代替二进制信号量。

清单148显示了与中断同步的任务的实现。 例16中使用的对xSemaphoreTake()的调用已由对ulTaskNotifyTake()的调用所取代。

ulTaskNotifyTake()xClearCountOnExit参数设置为pdTRUE,这导致接收任务的通知值在ulTaskNotifyTake()返回之前被清除为零。 因此,有必要处理在每次调用ulTaskNotifyTake()之间已经可用的所有事件。 在示例16中,由于使用了二进制信号量,因此必须从硬件确定挂起事件的数量,这并不总是可行的。 在示例24中,未决事件的数量是从ulTaskNotifyTake()返回的。

用于生成软件中断的定期任务会在生成中断之前以及在生成中断之后再次打印一条消息。 这样可以在产生的输出中观察执行顺序。

清单149显示了中断处理程序。 除了将通知直接发送到延迟处理的任务之外,这几乎没有其他作用。

执行示例24时产生的输出如图78所示。正如预期的那样,它与执行示例16时产生的输出相同。 一旦产生中断,vHandlerTask()就会进入运行状态,因此任务的输出会拆分定期任务产生的输出。 图79提供了进一步的说明。

例子25.使用任务通知代替信号量,方法2

在示例24中,ulTaskNotifyTake()xClearOnExit参数设置为pdTRUE。 示例25稍微修改了示例24,以演示ulTaskNotifyTake()xClearOnExit参数改为设置为pdFALSE时的行为。

当xClearOnExit为pdFALSE时,调用ulTaskNotifyTake()只会将调用任务的通知值减1(减少1),而不是将其清除为零。 因此,通知计数是已发生的事件数与已处理的事件数之间的差。 这样可以通过两种方式简化vHandlerTask()的结构:

  1. 等待处理的事件数保留在通知值中,因此不需要将其保留在局部变量中。
  2. 仅需要在每次调用ulTaskNotifyTake()之间处理一个事件。

清单150中显示了示例25中使用的vHandlerTask()的实现。

出于演示目的,还对中断服务例程进行了修改,以使每个中断发送多个任务通知,并以此模拟在高频下发生的多个中断。 清单151中显示了示例25中使用的中断服务例程的实现。

执行示例25时产生的输出如图80所示。可以看出,每次生成中断时,vHandlerTask()都会处理所有三个事件。

xTaskNotify()和xTaskNotifyFromISR()API函数

xTaskNotify()是xTaskNotifyGive()的功能更强大的版本,可用于通过以下任何一种方式来更新接收任务的通知值:

  • 递增(添加一个)接收任务的通知值,在这种情况下,xTaskNotify()等同于xTaskNotifyGive()。
  • 在接收任务的通知值中设置一位或多位。 这样一来,任务的通知值就可以用作事件组的轻量级对象,并且可以更快地替代事件组。
  • 在接收任务的通知值中写入一个全新的数字,但前提是接收任务自上次更新以来已读取其通知值。 这样,任务的通知值就可以提供与长度为1的队列所提供的功能类似的功能。
  • 即使接收任务自上次更新以来尚未读取其通知值,也要在接收任务的通知值中写入一个全新的数字。 这样,任务的通知值可以提供与xQueueOverwrite()API函数提供的功能相似的功能。 由此产生的行为有时称为“邮箱”。

xTaskNotify()比xTaskNotifyGive()更灵活,功能更强大,并且由于具有额外的灵活性和功能,因此使用起来也有些复杂。

xTaskNotifyFromISR()是xTaskNotify()的一个版本,可以在中断服务例程中使用,因此具有附加的pxHigherPriorityTaskWoken参数。

如果尚未接收,则调用xTaskNotify()会将接收任务的通知状态始终设置为“待处理”。

Parameter Name/ Returned Value Description
xTaskToNotify 将通知发送到的任务的句柄-有关获取任务句柄的信息,请参阅xTaskCreate()API函数的pxCreatedTask参数。
ulValue ulValue的使用方式取决于eNotifyAction值。 请参阅表52。
eNotifyAction 一个枚举类型,指定如何更新接收任务的通知值。 请参阅表52。
Returned value xTaskNotify()将返回pdPASS,但表52中指出的一种情况除外。
eNoAction 接收任务的通知状态被设置为“未处理”,但通知值未更新。 不使用xTaskNotify()ulValue参数。eNoAction操作允许将任务通知用作二进制信号量的更快,更轻量的替代方案。
eSetBits 接收任务的通知值与xTaskNotify()ulValue参数中传递的值按位进行“或”运算。 例如,如果ulValue设置为0x01,则将在接收任务的通知值中设置位0。 作为另一个示例,如果ulValue为0x06(二进制0110),则将在接收任务的通知值中设置位1和位2。eSetBits操作允许将任务通知用作事件组的更快,更轻量的替代方案。
eIncrement 接收任务的通知值增加。 不使用xTaskNotify()ulValue参数。eIncrement操作允许将任务通知用作二进制或计数信号量的更快,更轻量的替代方法,并且等效于更简单的xTaskNotifyGive()API函数。
eSetValueWithoutOverwrite 如果接收任务在调用xTaskNotify()之前有待处理的通知,则不执行任何操作,xTaskNotify()将返回pdFAIL。如果在调用xTaskNotify()之前接收任务没有待处理的通知,则将接收任务的通知值设置为xTaskNotify()ulValue参数中传递的值。接收任务的通知值设置为xTaskNotify()ulValue参数中传递的值,无论接收任务在调用xTaskNotify()之前是否有待处理的通知。

xTaskNotifyWait()API函数

xTaskNotifyWait()是ulTaskNotifyTake()的功能更强大的版本。 它允许任务以可选的超时等待,如果调用任务的通知状态尚未挂起,则该状态将变为挂起。 xTaskNotifyWait()提供了用于在调用函数进入和退出函数时清除调用任务通知值中的位的选项。

Parameter Name/ Returned Value Description
ulBitsToClearOnEntry 如果调用任务在调用xTaskNotifyWait()之前没有待处理的通知,则在进入函数时,将在任务的通知值中清除ulBitsToClearOnEntry中设置的任何位。例如,如果ulBitsToClearOnEntry为0x01,则将清除任务通知值的位0。 作为另一个示例,将ulBitsToClearOnEntry设置为0xffffffff(ULONG_MAX)将清除任务通知值中的所有位,从而有效地将值清除为0。
ulBitsToClearOnExit 如果正在调用的任务由于收到通知而退出xTaskNotifyWait(),或者因为在调用xTaskNotifyWait()时已经有待处理的通知,则ulBitsToClearOnExit中设置的任何位都将在任务的通知值中清除,然后任务退出。 xTaskNotifyWait()函数。在将任务的通知值保存在* pulNotificationValue中之后,将清除这些位(请参阅下面的pulNotificationValue描述)。例如,如果ulBitsToClearOnExit为0x03,则在函数退出之前,将清除任务通知值的位0和位1。将ulBitsToClearOnExit设置为0xffffffff(ULONG_MAX)将清除任务通知值中的所有位,从而有效地将值清除为0。
pulNotificationValue 用于传递任务的通知值。 复制到* pulNotificationValue的值是由于ulBitsToClearOnExit设置而清除任何位之前的任务的通知值。pulNotificationValue是一个可选参数,如果不需要,可以将其设置为NULL。
xTicksToWait 调用任务应保持在“阻止”状态以等待其通知状态变为挂起状态的最长时间。块时间以滴答周期指定,因此它表示的绝对时间取决于滴答频率。 宏pdMS_TO_TICKS()可用于将以毫秒为单位的时间转换为以滴答数为单位的时间。将xTicksToWait设置为portMAX_DELAY将导致任务无限期地等待(没有超时),前提是提供在FreeRTOSConfig.h中将INCLUDE_vTaskSuspend设置为1。
Returned value 有两个可能的返回值:1. pdTRUE这表明xTaskNotifyWait()返回是由于收到通知,或者是因为调用xTaskNotifyWait()时调用任务已经有待处理的通知。如果指定了阻止时间(xTicksToWait不为零),则可能会将调用任务置于“阻止”状态,以等待其通知状态变为挂起状态,但在阻止时间之前将其通知状态设置为“挂起” 已到期。2. pdFALSE这表明xTaskNotifyWait()返回了,而调用任务没有收到任务通知。如果xTicksToWait不为零,则调用任务将一直处于“阻塞”状态,以等待其通知状态变为挂起状态,但是指定的阻塞时间在此之前已过期。

外围设备驱动程序中使用的任务通知:UART示例

外围设备驱动程序库提供了在硬件接口上执行常见操作的功能。 通常为其提供此类库的外围设备的示例包括通用异步收发器(UART),串行外围设备接口(SPI)端口,模数转换器(ADC)和以太网端口。 此类库通常提供的功能示例包括初始化外围设备,将数据发送到外围设备以及从外围设备接收数据的功能。

外设上的某些操作需要相对较长的时间才能完成。 此类操作的示例包括高精度ADC转换以及在UART上传输大数据包。 在这些情况下,可以实现驱动程序库功能来轮询(反复读取)外围设备的状态寄存器,以确定操作何时完成。 但是,以这种方式进行轮询几乎总是很浪费,因为它占用了100%的处理器时间,而没有进行任何有效的处理。 在多任务系统中,浪费特别昂贵,在该系统中,轮询外围设备的任务可能会阻止执行确实要执行生产性处理的优先级较低的任务。

为避免可能浪费处理时间,应使用高效的RTOS传感器设备驱动程序进行中断驱动,并为启动冗长的操作的任务提供在“阻塞”状态下等待操作完成的选项。 这样,可以在执行长时间操作的任务处于“已阻止”状态时执行优先级较低的任务,除非有效率地使用它,否则任何任务都不会占用处理时间。

RTOS传感器驱动程序库的常见做法是使用二进制信号量将任务置于“已阻止”状态。 清单154中所示的伪代码演示了该技术,该伪代码提供了RTOS传感器库函数的概述,该函数在UART端口上传输数据。 在清单154中:

  • xUART是描述UART外设并保存状态信息的结构。 结构的xTxSemaphore成员是SemaphoreHandle_t类型的变量。 假定信号量已经创建。
  • xUART_Send()函数不包含任何互斥逻辑。 如果有多个任务要使用xUART_Send()函数,则应用程序编写器将必须管理应用程序自身内部的互斥。 例如,在调用xUART_Send()之前,可能需要一个任务来获取互斥量。
  • xSemaphoreTake()API函数用于在启动UART传输后将调用任务置于“阻塞”状态。
  • 传输完成后,xSemaphoreGiveFromISR()API函数用于将任务从Blocked状态中删除,这是UART外设的传输结束中断服务例程执行时。

清单154中展示的技术是完全可行的,甚至是惯例,但它也有一些缺点:

  • 该库使用多个信号量,从而增加了其RAM占用空间。
  • 在创建信号量之前,不能使用它们,因此使用信号量的库只有在明确初始化后才能使用。
  • 信号量是通用对象,适用于广泛的用例。 它们包括允许任何数量的任务在“阻塞”状态下等待信号变为可用的逻辑,以及选择(以确定性方式)在信号确实变为可用时从“阻塞”状态中删除哪个任务的逻辑。 在清单154所示的情况下,执行逻辑需要花费有限的时间,并且不需要处理开销,在清单154中,在任何给定时间都不能有多个任务在等待信号量。

清单155展示了如何通过使用任务通知代替二进制信号量来避免这些弊端。

注意:如果库使用任务通知,则库的文档必须明确声明调用库函数可以更改调用任务的通知状态和通知值。

在清单155中:

  • xUART结构的xTxSemaphore成员已由xTaskToNotify成员替换。 xTaskToNotify是TaskHandle_t类型的变量,用于保存等待UART操作完成的任务的句柄。
  • xTaskGetCurrentTaskHandle()FreeRTOS API函数用于获取处于“运行”状态的任务的句柄。
  • 该库不会创建任何FreeRTOS对象,因此不会产生RAM开销,也不需要显式初始化。
  • 任务通知直接发送到正在等待UART操作完成的任务,因此不会执行不必要的逻辑。

xUART结构的xTaskToNotify成员可以从任务和中断服务例程中访问,因此需要考虑处理器如何更新其值:

  • 如果xTaskToNotify由单个内存写入操作更新,则可以在关键部分之外进行更新,如清单155所示。如果xTaskToNotify是32位变量(TaskHandle_t是32位类型),情况就是这样。 ),运行FreeRTOS的处理器是32位处理器。
  • 如果需要多个内存写入操作来更新xTaskToNotify,则xTaskToNotify只能从关键部分进行更新,否则,中断服务程序可能会在xTaskToNotify处于不一致状态时对其进行访问。 如果xTaskToNotify是一个32位变量,并且运行FreeRTOS的处理器是一个16位处理器,就会是这种情况,因为它将需要两个16位内存写操作来更新所有32位。

在FreeRTOS实现内部,TaskHandle_t是一个指针,因此sizeof(TaskHandle_t)始终等于sizeof(void *)。

任务通知还可以替换接收函数中的信号量,如伪代码清单156所示,伪代码清单156提供了RTOS感知库函数的概述,该函数在UART端口上接收数据。 参考清单156:

  • xUART_Receive()函数不包含任何互斥逻辑。 如果有多个任务要使用xUART_Receive()函数,则应用程序编写器将必须管理应用程序内部的互斥。 例如,在调用xUART_Receive()之前,可能需要一个任务来获取互斥量。
  • UART的接收中断服务程序将UART接收的字符放入RAM缓冲区。 xUART_Receive()函数从RAM缓冲区返回字符。
  • xUART_Receive()uxWantedBytes参数用于指定要接收的字符数。 如果RAM缓冲区中尚未包含所请求的数字字符,则调用任务将置于“阻塞”状态,以等待通知缓冲区中的字符数已增加。 while()循环用于重复此序列,直到接收缓冲区包含请求的字符数,或者发生超时。
  • 调用任务可能会多次进入“阻止”状态。 因此,调整块时间时要考虑到调用xUART_Receive()以来已经过去的时间。 这些调整可确保在xUART_Receive()中花费的总时间不超过xUART结构的xRxTimeout成员指定的块时间。 可以使用FreeRTOS vTaskSetTimeOutState()和xTaskCheckForTimeOut()帮助函数来调整块时间。

外围设备驱动程序中使用的任务通知:ADC示例

上一节演示了如何使用vTaskNotifyGiveFromISR()将任务通知从中断发送到任务。 vTaskNotifyGiveFromISR()是一个易于使用的函数,但功能有限。 它只能将任务通知作为无价值的事件发送,而不能发送数据。 本节演示如何使用xTaskNotifyFromISR()通过任务通知事件发送数据。 清单157中所示的伪代码演示了该技术,该伪代码提供了模数转换器(ADC)的RTOS感知中断服务例程的概述。 在清单157中:

  • 假定ADC转换至少每50毫秒开始一次。
  • ADC_ConversionEndISR()是ADC转换结束中断的中断服务程序,该中断服务在每次有新的ADC值可用时执行。
  • 由vADCTask()实现的任务处理ADC生成的每个值。 假定创建任务时任务的句柄存储在xADCTaskToNotify中。
  • ADC_ConversionEndISR()使用xTaskNotifyFromISR()(将eAction参数设置为eSetValueWithoutOverwrite)将任务通知发送到vADCTask()任务,并将ADC转换的结果写入任务的通知值。
  • vADCTask()任务使用xTaskNotifyWait()来等待被通知有新的ADC值可用,并从其通知值中检索ADC转换的结果。

在应用程序中直接使用的任务通知

本节通过演示任务通知在包括以下功能的假设应用程序中的使用来增强任务通知的功能:

  1. 应用程序通过慢速的Internet连接进行通信,以将数据发送到远程数据服务器,并向远程数据服务器请求数据。 从这里开始,远程数据服务器称为云服务器。
  2. 从云服务器请求数据后,请求任务必须在“阻止”状态下等待接收请求的数据。
  3. 将数据发送到云服务器后,发送任务必须在“阻止”状态下等待确认云服务器正确接收了数据。

软件设计的原理图如图81所示。在图81中:

  • 处理与云服务器的多个Internet连接的复杂性封装在一个FreeRTOS任务中。 该任务在FreeRTOS应用程序中充当代理服务器,并称为服务器任务。
  • 应用程序任务通过调用CloudRead()从云服务器读取数据。 CloudRead()不直接与云服务器通信,而是将读取的请求发送到队列中的服务器任务,并从服务器任务接收请求的数据作为任务通知。
  • 应用程序任务通过调用CloudWrite()将日期写入云服务器。 CloudWrite()不直接与云服务器通信,而是将写入请求发送到队列中的服务器任务,并从服务器任务接收写入操作的结果作为任务通知。

清单158显示了由CloudRead()和CloudWrite()函数发送到服务器任务的结构。


清单159中显示了CloudRead()的伪代码。该函数将其请求发送到服务器任务,然后调用xTaskNotifyWait()以处于Blocked状态,直到被通知请求的数据可用为止。

清单160中显示了伪代码,该伪代码显示了服务器任务如何管理读取请求。从云服务器接收到数据后,服务器任务通过调用xTaskNotify()解除对应用程序任务的阻止,并将接收到的数据发送给应用程序任务。 ),并将eAction参数设置为eSetValueWithOverwrite。

清单160显示了一个简化的场景,因为它假定GetCloudData()不必等待从云服务器获取值。

清单161显示了CloudWrite()的伪代码。为了演示起见,
CloudWrite()返回按位状态代码,其中状态代码中的每个位都分配有唯一含义。 清单161顶部的#define语句显示了四个示例状态位。

任务清除四个状态位,将其请求发送到服务器任务,然后调用xTaskNotifyWait()以处于“阻止”状态等待状态通知。


清单162显示了演示服务器任务如何管理写请求的伪代码。将数据发送到云服务器后,服务器任务将解除对应用程序任务的阻止,并通过调用xTaskNotify将按位状态代码发送给应用程序任务 (),并将eAction参数设置为eSetBits。 只有CLOUD_WRITE_STATUS_BIT_MASK常量定义的位可以更改接收任务的通知值,因此接收任务可以将其通知值中的其他位用于其他目的。

清单162显示了一种简化的方案,因为它假定SetCloudData()不必等待从远程云服务器获取确认。


  1. xTaskNotifyGive()实际上是作为宏而不是函数实现的。 为了简单起见,在本书中将其称为函数

FreeRTOS-TaskNotify相关推荐

  1. esp freertos_如何开始使用FreeRTOS和ESP8266

    esp freertos by Denis Nuțiu 丹尼斯·努尤(Denis Nuțiu) 如何开始使用FreeRTOS和ESP8266 (How to get started with Free ...

  2. freeRTOSConfig.h文件对FreeRTOS进行系统配置

    FreeRTOS内核是高度可定制的,使用配置文件FreeRTOSConfig.h进行定制.每个FreeRTOS应用都必须包含这个头文件,用户根据实际应用来裁剪定制FreeRTOS内核.这个配置文件是针 ...

  3. freertos zynq 移植_Zynq-7000 FreeRTOS(一)系统移植配置

    软件版本:VIvado HLx 2018.2 从FreeRTOS的官网中下载源代码: https://www.freertos.org/a00104.html 图:FreeRTOS的官网 上图中,点击 ...

  4. FreeRTOS 临界段和开关中断

    以下转载自安富莱电子: http://forum.armfly.com/forum.php 临界段 代码的临界段也称为临界区,一旦这部分代码开始执行,则不允许任何中断打断.为确保临界段代码 的执行不被 ...

  5. FreeRTOS(四)——内存管理

    概述 标准的内存函数是malloc和free,但是对于嵌入式系统来说,可能会有以下问题: 这两个函数在小型嵌入式系统中可能不可用 这两个函数的具体实现可能会相对较大,会占用较多的代码空间 这两个函数通 ...

  6. freertos 创建互斥量_STM32CubeMX+FreeRTOS学习[6] 互斥量(Lu)

    FreeRTOS 学习之六:互斥量 前提:默认已经装好 MDK V5 和 STM32CubeMX ,并安装了 STM32F1xx 系列的支持包. 硬件平台: STM32F1xx 系列. 目的:学习互斥 ...

  7. FreeRTOS介绍

    1.为什么学习RTOS? 作为基于ARM7.Cortex-M3硬件开发的嵌入式工程师,我一直反对使用RTOS.不仅因为不恰当的使用RTOS会给项目带来额外的稳定性风险,更重要的是我认为绝大多数基于AR ...

  8. FreeRTOS学习笔记4-FreeRTOS配置管理

    FreeRTOS配置管理: 网上移植教程较多,也可以使用官方提供的各种Demo工程进行移植,不在详细介绍.本文主要介绍FreeRTOS移植成功后进行的配置方式.使其成为自己最匹配最精简,最适用的系统. ...

  9. cube sdio fatfs 初始化sd卡_Stm32CubeMx配置SDIO+FATFS+FREERTOS

    芯片型号:STM32F427VG 软件版本:Stm32CubeMx 5.6.0 库版本:STM32Cube FW_F4 V1.25.0 配置SDIO: 卡时钟(SDIO_CK ):每个时钟周期在命令和 ...

  10. java是否支持freertos_使用GCC配置FreeRTOS(ARM)

    我是RTOS和ARM Cortex MCU的新手 . 我需要使用带有STM32L053核板的FreeRTOS GCC mbed.org库 . 我已经使用GCC mbed qt-creator成功创建了 ...

最新文章

  1. jittor和pytorch生成网络对比之dragan
  2. Spring MVC实现上传文件报错解决方案
  3. 【Matlab 控制】利用 Simulink 对微分代数方程建模
  4. 记一则神秘JDK版本引发的hadoop集群慢性崩溃”血案“
  5. 231. 2的幂 golang
  6. .NET 项目开发总结
  7. 双缓冲(Double Buffer)原理和使用【转】
  8. java双向链表结构_【Java数据结构】2.3双向链表的迭代实现
  9. [Threejs]环境光与HDR贴图
  10. IT行业都能干什么事?为什么要学习IT技能呢?
  11. Qt显示wav波形图
  12. Effective Kotlin 中文版
  13. 通过对TCPWindowSize的调整对网络流量的性能优化
  14. 一个普通码农的Linux之路
  15. 一步步教你怎么用python写贪吃蛇游戏!
  16. 程序员如何变得更优秀?从业 10 年,我总结了 7 个建议
  17. kotlin “${ }”是什么意思?
  18. Java算法(八)详细解析:寻找完数
  19. Ipad 横屏、分屏页面布局错乱问题
  20. 【笔记】网易微专业-Web安全工程师-01.WEB基础知识

热门文章

  1. 电力系统微型计算机继电保护试题及答案,2011年4月全国自学考试电力系统微型计算机继电保护试题答案...
  2. 红帽子 linux 声卡驱动,RedHat Linux系统下安装ALSA驱动的方法
  3. python book pdf_The Django Book 第2版 中文PDF版[1.87MB]
  4. Android 中东阿拉伯语适配,看这一篇够了
  5. java hsqldb数据库,HSQLDB数据库的使用
  6. 通达信自动交易软件步骤分析
  7. 获取已发布微信小游戏源码
  8. 测试用例(功能用例)——资产申购、统计报表
  9. 【第一章:绪论】静态时序分析圣经翻译计划
  10. 4.6 数值分析: P阶收敛的迭代法