1.任务通知什么是任务通知任务通知就是直接的通信不需要中间量通信对象比如队列信号量事件组...可以让任务与任务中断服务程序进行同步注意中断服务程序可以直接发给任务但任务不可以直接发给中断服务程序。configUSE_TASK_NOTIFICATIONS被设置1时每一个任务至少有一个“通知状态”可以是“待定”或“未定”以及一个32位无符号整数的“通知值”。当一个任务接收到通知时其通知状态被设置为待定当一个任务读取通知值时其通知状态被设置为未定。2.任务通知的使用任务通知具有非常强大的功能通常可以用来替代二进制信号量、计数信号量、事件组有时甚至是代替队列。通过使用xTaskNotify() API 函数发送任务通知以及使用xTaskNotifyWait() API 函数接收任务通知可以适应广泛的使用场景。然而在大多数情况下不需要xTaskNotify()和xTaskNotifyWait() API 函数提供的全部灵活性功能更简单的函数就足够了。因此提供了xTaskNotifyGive() API 函数作为xTaskNotify()函数的更简单但灵活性较小的替代函数并提供了ulTaskNotifyTake() API 函数作为xTaskNotifyWait()函数的更简单但灵活性较小的替代函数。任务通知系统不仅仅限于单个通知事件。configTASK_NOTIFICATION_ARRAY_ENTRIES的参数默认设置为1。如果将其设置为大于1的值则会在每个任务内部创建一个通知数组。这允许通过索引来管理通知。每个任务通知的API函数都有一个带索引的版本。使用非索引版本将访问notification[0]数组中的第一个。每个API函数的indexed版本通过后缀Indexed进行标识因此xTaskNotify()函数名变为xTaskNotifyIndexed。为了简单起见教程中仅使用任务通知函数的非索引版本。3.函数/* 由 main() 创建的两个任务的原型。 */ static void prvTask1( void *pvParameters ); static void prvTask2( void *pvParameters ); /* 由 main() 创建的任务的句柄。 */ static TaskHandle_t xTask1 NULL, xTask2 NULL; /* 创建两个任务这两个任务相互发送通知然后启动RTOS调度器。*/ void main( void ) { xTaskCreate( prvTask1, Task1, 200, NULL, tskIDLE_PRIORITY, xTask1 ); xTaskCreate( prvTask2, Task2, 200, NULL, tskIDLE_PRIORITY, xTask2 ); vTaskStartScheduler(); } /*-----------------------------------------------------------*/ /* prvTask1() 使用 indexed 版本的 API。*/ static void prvTask1( void *pvParameters ) { for( ;; ) { /* 向 prvTask2() 发送通知使其从阻塞状态变为就绪状态。 */ xTaskNotifyGiveIndexed( xTask2, 0 ); /* 阻塞等待 prvTask2() 向此任务发送通知。*/ ulTaskNotifyTakeIndexed( 0, pdTRUE, portMAX_DELAY ); } } /*-----------------------------------------------------------*/ /* prvTask2() 使用 API 的原始版本不带 Indexed。*/ static void prvTask2( void *pvParameters ) { for( ;; ) { /* 阻塞等待 prvTask1() 向此任务发送通知。 */ ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); /* 向 prvTask1() 发送一个通知将其从阻塞状态中转出。*/ xTaskNotifyGive( xTask1 ); } }4.实验1CubeMX的配置代码main.c /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ extern void ulExampleInterruptHandler(void); /* USER CODE END PV */ /* USER CODE BEGIN 4 */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { UNUSED (GPIO_Pin); if(HAL_GPIO_ReadPin (KEY4_GPIO_Port,KEY4_Pin)GPIO_PIN_SET) { ulExampleInterruptHandler(); } } /* USER CODE END 4 */user_app.h #ifndef __USER_APP_H__ #define __USER_APP_H__ #include usart.h #include stdio.h #include FreeRTOS.h #include task.h #include main.h #include cmsis_os2.h #include string.h #include Timers.h #include semphr.h #include stdlib.h #include event_groups.h void vHandlerTask(void* pvParameters); void vPeriodicTask(void * pvParameters); void ulExampleInterruptHandler(void); void vprintfStringAndNumber(const char *pcString,uint32_t ulValue); void vprintfString(const char *pcString); #endifuser_app.c #include user_app.h #include queue.h extern osThreadId_t Task1Handle; static const TickType_t xInterruptFrequencypdMS_TO_TICKS (500); void vprintfStringAndNumber(const char *pcString,uint32_t ulValue) { //临近保护 taskENTER_CRITICAL(); { printf(%s%d\n\r,pcString,ulValue); } taskEXIT_CRITICAL(); } void vprintfString(const char *pcString) { taskENTER_CRITICAL(); { printf(%s,pcString); } taskEXIT_CRITICAL(); } int fputc(int ch, FILE *f) { HAL_UART_Transmit (huart1 ,(uint8_t*)ch,1,0xffff); return ch; } void vHandlerTask(void* pvParameters) { const TickType_t xMaxExpectedBlockTimexInterruptFrequency pdMS_TO_TICKS (10); uint32_t ulEventsToProcess; for(;;) { //收 ulEventsToProcess ulTaskNotifyTake (pdTRUE,xMaxExpectedBlockTime ); if(ulEventsToProcess !0) { while(ulEventsToProcess !0) { vprintfString (Handler task - processing event.\n\r); ulEventsToProcess--; } } else { /* 如果函数执行到这一部分则表示在预期时间内没有接收到中断并且在真实的 应用中可能需要执行一些错误恢复操作。 */ } } } void vPeriodicTask(void * pvParameters) { const TickType_t Delay500mspdMS_TO_TICKS (500UL); for(;;) { vTaskDelay (xInterruptFrequency ); vprintfString (Periodic task - About to generate an interrupt\n\r); __HAL_GPIO_EXTI_GENERATE_SWIT (KEY4_Pin); //软触发 vprintfString (Periodic task _ Interruptgenerated.\n\r\n\r\n\r); } } void ulExampleInterruptHandler(void) { BaseType_t xHigherPriorityTaskWoken; xHigherPriorityTaskWoken pdFALSE; //给 vTaskNotifyGiveFromISR (Task1Handle , //正在发送通知的任务的句柄这个句柄是在任务创建时保存的。 xHigherPriorityTaskWoken //使用的方法与其他的相似 ); vTaskNotifyGiveFromISR (Task1Handle ,xHigherPriorityTaskWoken ); vTaskNotifyGiveFromISR (Task1Handle ,xHigherPriorityTaskWoken ); portYIELD_FROM_ISR (xHigherPriorityTaskWoken ); }效果