FreeRTOS任务通知

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函数都有一个带索引的版本。使用非索引版本将访问notification0(数组中的第一个)。每个API函数的indexed版本通过后缀Indexed进行标识,因此xTaskNotify()函数名变为xTaskNotifyIndexed。为了简单起见,教程中仅使用任务通知函数的非索引版本。

3.函数

cs 复制代码
/* 由 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.实验1

CubeMX的配置:

代码:

cs 复制代码
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 */
cs 复制代码
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); 
#endif 
cs 复制代码
user_app.c


#include "user_app.h"
#include "queue.h"

extern osThreadId_t Task1Handle;
static const TickType_t xInterruptFrequency=pdMS_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 xMaxExpectedBlockTime=xInterruptFrequency +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 Delay500ms=pdMS_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 );
}

效果:

相关推荐
过往的时光1 小时前
Spring Boot、Spring Cloud 与 Spring Cloud Alibaba 版本对照终极指南
java·spring boot·spring cloud
柒@宝儿姐1 小时前
若依 B 端从浏览器访问升级为 Windows 安装包交付流程
前端·javascript·vue.js·windows
snow@li1 小时前
SpringBoot:Payload统一响应包装/全景深入梳理
java·spring boot·后端
中国搜索直付通1 小时前
游戏车机端支付通道,会是下一个被低估的合规战场吗?
java·大数据·开发语言·人工智能·游戏
开开心心_Every1 小时前
电脑文件搜索软件支持内容和拼音搜索
linux·服务器·人工智能·r语言·pdf·音视频·symfony
AKA__Zas1 小时前
芝士算法(位运算)
java·开发语言·算法·leetcode·学习方法
她说可以呀1 小时前
Spring-ai 2.0 MCP
java·人工智能·spring
宵时待雨1 小时前
linux笔记归纳13:Socket编程UDP
linux·服务器·笔记·udp
bksczm1 小时前
Linux之应用层层协议认知(TCP协议编程模块化demo) —— 兼论守护进程机制
linux·运维·服务器