当前位置: 首页 > news >正文

细说STM32单片机FreeRTOS任务通知及其应用实例

目录

一、任务通知的原理和功能

1、 进程间使用任务通知直接通信的基本原理

2、任务通知的优点

3、任务通知的局限性

二、任务通知的相关函数

1、相关函数概述

2、函数详解

(1)函数xTaskNotify()

(2)函数xTaskNotifyAndQuery()

(3)函数xTaskNotifyGive()

(4)函数xTaskNotifyWait()

(5)函数ulTaskNotifyTake()

(6)函数xTaskNotifyStateClear()

三、示例:使用任务通知传递数据

1、示例功能与CubeMX项目设置

(1)RCC、SYS、Code Gennerator、USART3、TIM6

(2)ADC3_IN6

(3)TIM3

(4) RTOS

(5)NVIC 

2、程序功能实现

(1)主程序

(2)FreeRTOS对象初始化

(3)任务通知的接收

(4)在ADC3的中断里发送通知

3、运行调试


        任务通知(task notification)是FreeRTOS中的另外一种进程间通信技术。使用任务通知不需要创建任何中间对象,可以直接从任务向任务,或从ISR向任务发送通知,传递一个通知值(notification value)。任务通知可以模拟二值信号量、计数信号量,或长度为1的消息队列,使用任务通知,通常效率更高、消耗内存更少。

一、任务通知的原理和功能

        如队列、信号量、事件组等这样的进程间通信技术都需要创建一个中间对象,进程之间通过这些中间对象进行通信或同步。

        在FreeRTOS中还有一种无须创建中间对象的进程间直接通信方法,那就是任务通知方法。要使用任务通知方法,需要将参数configUSE_TASK_NOTIFICATIONS设置为1。这个参数默认值为1,且可以在CubeMX中设置。

        当将参数configUSE_TASK_NOTIFICATIONS设置为1时,任务的任务控制块中会增加一个uint32_t类型的通知值变量,并且任务接收通知的状态有挂起(pending)和非挂起(not-pending)两种状态。

1、 进程间使用任务通知直接通信的基本原理

 

  • 一个任务或ISR向另外一个指定的任务发送通知,则将发送通知的进程称为发送者(sender),将接收通知的进程称为接收者(receiver)。
  • 发送者可以是任务或ISR,接收者只能是任务,不能是ISR。
  • 发送者发送通知时,可以带一个通知值,或者是使接收者的通知值发生改变的计算方法,例如,使通知值加1。发送者只管发送通知,不会进入阻塞状态,是否接收和处理通知由接收者决定。
  • 接收者有未处理的通知时,处于挂起状态。接收者可以进入阻塞状态等待通知,收到通知后退出阻塞状态,再做处理。

2、任务通知优点

        由任务通知的存储特点和工作原理可知,任务通知有如下优点:

  • 性能更高。使用任务通知在进程间传递数据时,比使用队列或信号量等方法的速度快得多。
  • 内存开销小。使用任务通知时内存开销小,因为只需在任务控制块中增加几个变量。而使用队列、信号量等,则需要先创建这些对象。

3、任务通知局限性

        当然,任务通知也有一些局限性,具体如下:

  • 使用任务通知时,不能向ISR发送通知,只能是任务或ISR向任务发送通知。
  • 任务通知指定了接收者,多个发送者可以向同一个接收者发送不同的通知,但是发送者不能将一个通知发送给不同的接收者,也就是不能进行消息广播。
  • 任务通知一次只能发送或接收一个uint32_t类型的数据,不能像消息队列那样发送多个缓存数据,因为任务控制块的数据缓存里只有一个uint32_t类型的通知值。

        使用任务通知可以代替二值信号量、计数信号量、事件组,可以代替只有一个uint32_t类型存储单元的队列。任务通知使用比较灵活,而且工作效率高。

二、任务通知的相关函数

1相关函数概述

        要使用任务通知功能,需要将参configUSE_TASK_NOTIFICATIONS设置为1,这个参数默认值为1,可在CubeMX中设置。

        使用任务通知无须创建中间对象,任务操作的相关函数主要是发送者发送通知,接收者等待和接收通知。任务通知的相关函数都在文件task.h中定义。

分组

函数

功能

发送通知

xTaskNotify()

向一个任务发送通知,带有通知值,还有值的传递方式设置。适用于利用通知值直接传递数据的应用场景

xTaskNotifyFromISR()

xTaskNotify()的ISR版本

xTaskNotifyAndQuery()

与xTaskNotify()的功能相似,但是可以返回接收者之前的通知值

xTaskNotifyAndQueryFromISR()

xTaskNotifyAndQuery()的ISR版本

xTaskNotifyGive()

向一个任务发送通知,不带通知值,只是使接收者的通知值加1。适用于将任务通知当作二值信号量或计数信号量使用的应用场景

vTaskNotifyGiveFromISR()

xTaskNotifyGive()的ISR版本

接收通知

xTaskNotifyWait()

等待并获取任务通知值的通用函数,可以设置进入和退出等待时的任务通知值,例如,进入时将通知值清零,或退出时将通知值清零

ulTaskNotifyTake()

等待并获取任务通知值,可在退出等待时将通知值减1
或清零。适用于将任务通知用作二值信号量或计数信号量的场合

其他

xTaskNotifyStateClear()

清除任务的等待状态,任务的通知值不变

        可以在任务或ISR里发送通知,所以发送通知的函数有任务和ISR两种版本,只有任务能接收通知,所以接收通知的函数没有ISR版本。发送和接收通知的函数可以分为以下两组。

  • 通用版本的函数xTaskNotify()和xTaskNotifyWait(),可以发送任意的通知值,适合在进程间通过通知值直接传递数据。
  • 将任务通知用作二值信号量或计数信号量的函数xTaskNotifyGive()和ulTaskNotifyTake(),发送时,使接收者的通知值加1,接收时,使通知值减1或清零。

2函数详解

(1)函数xTaskNotify()

        函数xTaskNotify()是发送通知的通用函数,它是一个宏函数,定义如下:

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

        它实际上是执行了函数xTaskGenericNotify(),这个函数的原型定义如下:

BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue ) PRIVILEGED_FUNCTION;

        其中,几个参数的意义如下:

  • 参数xTaskToNotify是接收者任务的句柄。
  • 参数ulValue是发送的通知值。
  • 参数eAction是通知值的作用方式,是枚举类型eNotifyAction,其定义如下。各枚举值与参数ulValue的结合,决定了如何改变接收者的通知值。
  • 参数pulPreviousNotificationValue,返回接收者的通知值被改变之前的值。
/* Actions that can be performed when vTaskNotify() is called. */
typedef enum
{eNoAction = 0,              /* Notify the task without updating its notify value. */eSetBits,                   /* Set bits in the task's notification value. */eIncrement,                 /* Increment the task's notification value. */eSetValueWithOverwrite,     /* Set the task's notification value to a specific value even if the previous value has not yet been read by the task. */eSetValueWithoutOverwrite   /* Set the task's notification value if the previous value     has been read by the task. */
} eNotifyAction;

        xTaskNotify()在调用函数xTaskGenericNotify()时,没有传递最后一个参数,所以不能返回接收者更新之前的通知值。函数xTaskNotify()的返回值是更新之后接收者的通知值。

        函数xTaskNotify()在发送通知时,根据参数ulValue和eAction的取值,有不同的改变接收者通知值的方式,也适用于不同的应用场景。例如,eAction等于eSetBits时,ulValue与接收者当前通知值进行按位或运算,这适用于将任务通知作为事件组使用的场景;eAction等于eIncrement时,接收者的通知值在当前基础上加1,与ulValue无关,这适用于将任务通知作为二值信号量或计数信号量使用的场景。

        函数xTaskNotifyFromISR()是xTaskNotify()的ISR版本,也是一个宏函数,其原型定义如下:

BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
#define xTaskNotifyFromISR( xTaskToNotify, ulValue, eAction, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL, ( pxHigherPriorityTaskWoken ) )
#define xTaskNotifyAndQueryFromISR( xTaskToNotify, ulValue, eAction, pulPreviousNotificationValue, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotificationValue ), ( pxHigherPriorityTaskWoken ) )

        它实际上是调用了函数xTaskGenericNotifyFromISR(),这个函数的原型定义如下:

        前4个参数与函数xTaskGenericNotify()中的参数相同,最后一个参数pxHigherPriorityTaskWoken是一个BaseType_t类型的指针,实际上是一个返回数据,表示退出中断ISR之前,是否需要申请进行上下文切换。调用函数portYIELD_FROM_ISR()进行上下文切换申请,调用该函数的示意代码如下: 

BaseType_t highTaskWoken=pdFALSE;
xTaskNotifyFromISR(xTaskToNotify,ulValue,eAction,&highTaskWoken);
portYIELD_FROM_ISR(highTaskWoken);

(2)函数xTaskNotifyAndQuery()

        函数xTaskNotifyAndQuery()与xTaskNotify()的功能相同,但是能返回接收者通前的值。函数xTaskNotifyAndQuery()的原型如下:

BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;
#define xTaskNotifyFromISR( xTaskToNotify, ulValue, eAction, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL, ( pxHigherPriorityTaskWoken ) )
#define xTaskNotifyAndQueryFromISR( xTaskToNotify, ulValue, eAction, pulPreviousNotificationValue, pxHigherPriorityTaskWoken ) xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), ( pulPreviousNotificationValue ), ( pxHigherPriorityTaskWoken ) )

(3)函数xTaskNotifyGive()

        函数xTaskNotifyGive()是xTaskNotify()的一种功能简化版本,它的功能是发送通知,使接收者的通知值加1。其原型定义如下:

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

        函数 xTaskNotifyGive()也调用了函数 xTaskGenericNotify(),但是默认传递了参数 ulValue为0,eAction为eIncrement,pulPreviousNotificationValue为NULL。所以,函数xTaskNotifyGive()的功能就是使接收者的通知值加1,这使其适用于将任务通知当作二值信号量或计数信号量使用的场合。

        函数vTaskNotifyGiveFromISR()是xTaskNotifyGive()的ISR版本,其原型定义如下。其中的参数pxHigherPriorityTaskWoken与函数xTaskNotifyFromISR()中同名参数的意义和使用方法相同。

* \defgroup xTaskNotifyWait xTaskNotifyWait
* \ingroup TaskNotifications
*/
void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken ) PRIVILEGED_FUNCTION;

(4)函数xTaskNotifyWait()

        接收者使用函数xTaskNotifyWait()等待任务通知并获取通知值,其原型定义如下:

* \defgroup xTaskNotifyWait xTaskNotifyWait
* \ingroup TaskNotifications
*/
BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;

        其中,几个参数的意义如下。

  • 参数u1BitsToClearOnEntry是在函数进入时需要清零的通知值的位掩码。需要清零的位在掩码中用1表示,否则,用0表示。计算方法是ulBitsToClearOnEntry按位取反后与当前的通知值进行按位与运算,用计算的结果更新通知值。例如,如果ulBitsToClearOnEntry设置为0,就是不更改当前的通知值;如果ulBitsToClearOnEntry设置为0xFFFFFFFF,就是将所有位清零,也就是使通知值清零。注意,通过ulBitsToClearOnEntry更改通知值,只在函数xTaskNotifyWait()进入且没有接收到任务通知时,才会执行,执行后进入阻塞状态,等待任务通知。如果函数在进入时已经有挂起待处理的任务通知,则不会更新当前的通知值。
  • 参数ulBitsToClearOnExit是函数在退出时需要清零的通知值的位掩码。如果设置为0,就是不更改通知值;如果设置为0xFFFFFFFF,就是将通知值设置为0。注意,这个操作在函数从等待超时状态退出,也就是没有接收到任务通知时是不执行的。
  • 参数pulNotificationValue是一个uint32_t类型的指针,用于返回接收的通知值。
  • 参数XTicksToWait是函数在阻塞状态等待的节拍数。如果设置为常数portMAX_DELAY,就是一直等待;如果设置为0,则表示不等待。函数的返回值是pdTRUE或pdFALSE,pdTRUE表示接收了任务通知,包括函数一进入就读取已挂起的任务通知。

        执行函数xTaskNotifyWait()时,如果任务是未挂起状态,也就是没有待处理的任务通知,任务就进入阻塞状态,等待接收通知;如果任务是挂起状态,也就是有未处理的任务通知,就立刻读取通知值,然后返回。在阻塞等待状态下,任务接收到新的任务通知,或等待超时就退出阻塞状态。

        函数xTaskNotifyWait()是等待任务通知的通用函数。用户可以通过参数ulBitsToClearOnEntry设置通知值的初值,如设置为0。在退出时,用户可以通过参数ulBitsToClearOnExit对通知值做一些处理,如清零。

(5)函数ulTaskNotifyTake()

        函数ulTaskNotifyTake()是另一个等待任务通知的函数,适用于将任务通知当作二值信号量或计数信号量使用的场合。这个函数的原型定义如下:

* \defgroup ulTaskNotifyTake ulTaskNotifyTake
* \ingroup TaskNotifications
*/
uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ) PRIVILEGED_FUNCTION;
  • 参数xClearCountOnExit的取值为pdTRUE或pdFALSE。当取值为pdTRUE时,函数在接收通知后退出时会将通知值清零,这种情况下,任务通知被当作二值信号量使用;当取值为pdFALSE时,函数在接收通知后退出时会将通知值减1,这种情况下,任务通知被当作计数信号量使用。
  • 参数xTicksToWait是在阻塞状态等待任务通知的节拍数。如果设置为常数portMAX_DELAY,则表示一直等待;如果设置为0,则表示不等待。
  • 函数的返回值是减1或清零之前的通知值。

        函数ulTaskNotifyTake()一般与函数xTaskNotifyGive()搭配使用,将任务通知当作二值信号量或计数信号量使用。xTaskNotifyGive()发送通知使接收者的通知值加1,uITaskNotifyTake()接收通知后,使通知值减1或复位为0。

        将通知值当作二值信号量或计数信号量使用的操作如图所示,图中的变量Value表示通知值。将任务通知当作计数信号量使用时,操作特点如下。

  • 接收者的通知值初始为0。
  • 使用ulTaskNotifyGive()发送通知时,即使接收者没有接收和处理,通知值也会每次加1,例如,多次发送后,Value变为5。
  • 执行函数ulTaskNotifyTake()时,如果通知值大于1,即使处于未挂起状态,函数也会立刻使通知值减1后返回,不会等待新的任务通知。如果当前通知值为0,接收者才会进入阻塞状态,等待新的任务通知。

 

(6)函数xTaskNotifyStateClear()

        函数xTaskNotifyStateClear()的功能是清除接收者的任务通知等待状态,使其变为未挂起状态,但是不会将接收者的通知值清零。其原型定义如下:

BaseType_t xTaskNotifystateclear(TaskHandle_t xTask);

        其中,参数xTask是需要操作的任务句柄,如果参数xTask设置为NULL,则表示清除当前任务的通知状态。

三、示例:使用任务通知传递数据

1示例功能与CubeMX项目设置

        本例设计一个示例使用中断方式进行ADC转换,然后,通过任务通知,将ADC转换结果作为通知值发送给另一个任务加以显示。

        ADC3_IN6在定时器TIM3的触发下进行ADC转换,TIM3的定时周期为500ms。在ADC3的ISR里,通过函数xTaskNotifyFromISR()将ADC转换结果数据发送给任务Task_Show。

        任务Task_Show总是使用函数xTaskNotifyWait()等待任务通知,读取通知值后,在串口助手上显示。

        继续使用旺宝红龙开发板STM32F407ZGT6 KIT V1.0。一些设置可以参考本文作者写的其他文章:

        细说STM32单片机FreeRTOS用事件组同步任务的方法及其应用实例-CSDN博客  https://wenchm.blog.csdn.net/article/details/147951964?spm=1011.2415.3001.5331

(1)RCC、SYS、Code Gennerator、USART3、TIM6

        该部分的设置可以参考本文作者发布的其他文章。

(2)ADC3_IN6

 

(3)TIM3

(4) RTOS

        在FreeRTOS中使用任务通知功能,需要将参数configUSE_TASK_NOTIFICATIONS设置为1。用户在CubeMX中可以设置这个参数,且默认为Enabled。设置任务Task_Show。

 

(5)NVIC 

2程序功能实现

(1)主程序

        在CubeMX里重新生成代码,在CubeIDE里打开项目后,添加用户功能代码后,主程序代码如下:

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "cmsis_os.h"
#include "adc.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void MX_FREERTOS_Init(void);/*** @brief  The application entry point.* @retval int*/
int main(void)
{/* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* Configure the system clock */SystemClock_Config();/* Initialize all configured peripherals */MX_GPIO_Init();MX_USART3_UART_Init();MX_ADC3_Init();MX_TIM3_Init();/* USER CODE BEGIN 2 */// Start Menuuint8_t startstr[] = "Demo8_1:Task Notification.\r\n";HAL_UART_Transmit(&huart3,startstr,sizeof(startstr),0xFFFF);uint8_t startstr1[] = "Transfer ADC value by Notification.\r\n";HAL_UART_Transmit(&huart3,startstr1,sizeof(startstr1),0xFFFF);HAL_ADC_Start_IT(&hadc3);		//以中断方式启动ADCHAL_TIM_Base_Start(&htim3);	//启动Timer/* USER CODE END 2 *//* Init scheduler */osKernelInitialize();/* Call init function for freertos objects (in cmsis_os2.c) */MX_FREERTOS_Init();/* Start scheduler */osKernelStart();/* We should never get here as control is now taken by the scheduler *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}//以下内容省略

        在外设初始化部分,MX_ADC3_Init()用于ADC3的初始化,MX_TIM3_Init()用于定时器TIM3的初始化,它们的代码都是自动生成的。

        ADC3在TIM3触发下周期性地进行ADC转换,需要执行HAL_ADC_Start_IT(&hadc3)启动ADC3的中断工作方式,执行HAL_TIM_Base_Start(&htim3)启动定时器TIM3。这样,ADC3就能每500ms进行一次ADC转换。

(2)FreeRTOS对象初始化

        使用任务通知时,无须创建任何中间对象,所以函数MX_FREERTOS_Init()只需创建任务。文件freertos.c中的初始化代码如下,这些代码是自动生成的:

         自动生成includes:

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

         手动添加私有includes:

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "usart.h"
#include "adc.h"
//#include "event_groups.h"		//事件组相关头文件
//#include "keyled.h"
/* USER CODE END Includes */

        自动生成任务定义代码:

/* Definitions for Task_Show */
osThreadId_t Task_ShowHandle;
const osThreadAttr_t Task_Show_attributes = {.name = "Task_Show",.stack_size = 256 * 4,.priority = (osPriority_t) osPriorityNormal,
};

        自动声明私有函数声明和RTOS初始化: 

/* Private function prototypes -----------------------------------------------*/void AppTask_Show(void *argument);
void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) *//*** @brief  FreeRTOS initialization* @param  None* @retval None*/
void MX_FREERTOS_Init(void) 
{/* Create the thread(s) *//* creation of Task_Show */Task_ShowHandle = osThreadNew(AppTask_Show, NULL, &Task_Show_attributes);
}

(3)任务通知的接收

         ADC3中断里发送的任务通知是发送给任务Task_Show的,这个任务负责接收通知,读取通知值之后,进行处理并显示。文件freertos.c中,手动添加任务Task_Show的任务函数和相关代码如下:

/* USER CODE BEGIN Header_AppTask_Show */
/*** @brief  Function implementing the Task_Show thread.* @param  argument: Not used* @retval None*/
/* USER CODE END Header_AppTask_Show */
void AppTask_Show(void *argument)
{/* USER CODE BEGIN AppTask_Show *//* Infinite loop */uint32_t  notifyValue=0;for(;;){uint32_t ulBitsToClearOnEntry=0x00;				//进入时不清除数据uint32_t ulBitsToClearOnExit=0xFFFFFFFF;	    //退出时清零数据BaseType_t result=xTaskNotifyWait(ulBitsToClearOnEntry, ulBitsToClearOnExit,&notifyValue, portMAX_DELAY);		//接收任务通知if (result==pdTRUE){uint32_t tmpValue = notifyValue;			//ADC原始数值printf("Notify Value = %ld\r\n",tmpValue );uint32_t Volt = 3300*tmpValue;				//单位:mVVolt = Volt>>12;							//除以2^12printf("Engineering Value = %ld\r\n",Volt );}}/* USER CODE END AppTask_Show */
}

        上述程序通过调用函数xTaskNotifyWait()接收通知。根据程序中设置的输入参数可知:它进入时,不清除原来的通知值;退出时,清除通知值;读取的通知值保存在变量notifyValue里;进入阻塞状态后,无限等待通知。任务读取任务通知后,返回的通知值notifyValue就是ADC转换原始结果。

(4)在ADC3的中断里发送通知

        ADC3采用TIM3外部触发方式进行ADC转换,在ADC3的中断里读取转换结果数据。ADC3的中断ISR框架已经在文件stm32f4xx_it.c中自动创建,只需重新实现ADC转换完成事件中断的回调函数HAL_ADC_ConvCpltCallback()。为了便于使用任务Task_Show的句柄Task_ShowHandle,直接在文件freertos.c的一个代码沙箱段内实现这个回调函数,如下所示: 

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{if (hadc->Instance != ADC3)return;uint32_t adc_value=HAL_ADC_GetValue(hadc);  	//Get ADC Valueif (Task_ShowHandle != NULL){BaseType_t taskWoken=pdFALSE;xTaskNotifyFromISR(Task_ShowHandle, adc_value,eSetValueWithOverwrite, &taskWoken);//Transmit ADCportYIELD_FROM_ISR(taskWoken);  			//Required, context switch.}
}int __io_putchar(int ch)
{HAL_UART_Transmit(&huart3,(uint8_t*)&ch,1,0xFFFF);return ch;
}
/* USER CODE END Application */

        这个回调函数的代码很简单,就是读取ADC转换结果数据,然后调用函数xTaskNotifyFromISR(),将转换结果以任务通知的方式发给任务Task_Show。ADC转换结果是uint32_t型数据,正好作为任务通知的通知值。在执行函数xTaskNotifyFromISR()之后,后面的申请进行上下文切换的语句portYIELD_FROM_ISR(taskWoken)是必须执行的。

3、运行调试

        构建项目后,将其下载到开发板上并运行测试,可以看到,串口助手上周期性地刷新显示ADC原始值和电压值。使用二值信号量实现了与本示例相同的功能对照,对比两个项目的代码,可以明显看出,使用任务通知要简单一些。

相关文章:

  • unity 第一人称控制器
  • C语言之 比特(bit)、字节(Byte)、字(Word)、整数(Int)
  • 学习黑客PowerShell的历史、架构与工作原理深度解析
  • ## Docker 中 Elasticsearch 启动失败:日志文件权限问题排查与解决
  • 什么是仓储管理,仓储管理怎么做
  • 【Android构建系统】Soong构建系统,通过.bp + .go定制编译
  • 【成品设计】基于STM32的的宠物看护系统
  • MySQL - 如何突破单库性能瓶颈
  • Qt读取Excel文件的技术实现与最佳实践
  • MySQL替换瀚高数据库报错: TO_DAYS()不存在(APP)
  • DNS服务搭建
  • 基于vue框架的东莞市二手相机交易管理系统5yz0u(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 家庭数字生态构建实战:基于飞牛fnOS的智能家居数据中台搭建全流程解析
  • 云原生环境下的事件驱动架构:理念、优势与落地实践
  • 架构演变 -单体到云原生
  • RK3568解码1080P视频时遇到系统崩溃内核挂掉的解决方案
  • 云原生攻防1(基础介绍)
  • 【Linux网络】传输层协议UDP
  • TCP和套接字SSL加密连接行为分析
  • 【Hadoop】--HA高可用搭建--3.2.2
  • 大语言模型在线辩论说服力比人类辩手高出64%
  • 读懂城市|成都高新区:打造“人尽其才”的“理想之城”
  • 芬兰西南部两架直升机相撞坠毁,第一批救援队已抵达现场
  • 天算星座二期首批卫星成功发射,将助力6G空天信息基础设施建设
  • 美国失去最后的AAA主权评级,继标普、惠誉后再遭穆迪降级
  • 技术派|威胁F-35、击落“死神”,胡塞武装防空战力如何?