FreeRTOS学习——任务通知

一、什么是任务通知

FreeRTOS 从版本 V8.2.0 开始提供任务通知这个功能,每个任务都有一个 32 位的通知值。按照 FreeRTOS 官方的说法,使用消息通知比通过二进制信号量方式解除阻塞任务快 45%, 并且更加省内存(无需创建队 列)。

在大多数情况下,任务通知可以替代二值信号量、计数信号量、事件标志组,可以替代长度为 1 的队列(可 以保存一个 32 位整数或指针值),并且任务通知速度更快、使用的RAM更少!

二、任务通知的更新方式

FreeRTOS 提供以下几种方式发送通知给任务 :

发送消息给任务,如果有通知未读, 不覆盖通知值

发送消息给任务,直接覆盖通知值

发送消息给任务,设置通知值的一个或者多个位

发送消息给任务,递增通知值

通过对以上方式的合理使用,可以在一定场合下替代原本的队列、信号量、事件标志组等。

三、任务通知的优势和劣势

3.1、任务通知的优势

  1. 使用任务通知向任务发送事件或数据,比使用队列、事件标志组或信号量快得多。

  2. 使用其他方法时都要先创建对应的结构体,使用任务通知时无需额外创建结构体。

3.2、任务通知的劣势

  1. 只有任务可以等待通知,中断服务函数中不可以,因为中断没有 TCB 。

  2. 通知只能一对一,因为通知必须指定任务。

  3. 等待通知的任务可以被阻塞, 但是发送消息的任务,任何情况下都不会被阻塞等待。

  4. 任务通知是通过更新任务通知值来发送数据的,任务结构体中只有一个任务通知值,只能保持一个数据。

四、相关函数

4.1、发送通知

cpp 复制代码
BaseType_t xTaskNotify( 
    TaskHandle_t     xTaskToNotify,
    uint32_t         ulValue,
    eNotifyAction    eAction 
);

参数:

xTaskToNotify:需要接收通知的任务句柄;

ulValue:用于更新接收任务通知值, 具体如何更新由形参 eAction 决定;

eAction:一个枚举,代表如何使用任务通知的值;

返回值:

如果被通知任务还没取走上一个通知,又接收了一个通知,则这次通知值未能更新并返回 pdFALSE, 而其他情况均返回pdPASS。

cpp 复制代码
BaseType_t xTaskNotifyAndQuery( 
    TaskHandle_t     xTaskToNotify,
    uint32_t         ulValue,
    eNotifyAction    eAction,
    uint32_t *       pulPreviousNotifyValue 
);

参数:

xTaskToNotify:需要接收通知的任务句柄;

ulValue:用于更新接收任务通知值, 具体如何更新由形参 eAction 决定;

eAction:一个枚举,代表如何使用任务通知的值;

pulPreviousNotifyValue:对象任务的上一个任务通知值,如果为 NULL, 则不需要回传, 这个时候就等价于函数 xTaskNotify()。

返回值:

如果被通知任务还没取走上一个通知,又接收了一个通知,则这次通知值未能更新并返回 pdFALSE, 而其他 情况均返回pdPASS。

cpp 复制代码
BaseType_t xTaskNotifyGive( TaskHandle_t xTaskToNotify );

参数:

xTaskToNotify:接收通知的任务句柄, 并让其自身的任务通知值加 1。

返回值:

总是返回 pdPASS。

4.2、等待通知

注意:等待通知API函数只能用在任务,不可应用于中断中!

cpp 复制代码
uint32_t ulTaskNotifyTake( 
        BaseType_t     xClearCountOnExit,
        TickType_t     xTicksToWait 
);

参数:

xClearCountOnExit:指定在成功接收通知后,将通知值清零或减 1,pdTRUE:把通知值清零(二值信号量);pdFALSE:把通知值减一(计数型信号量);

xTicksToWait:阻塞等待任务通知值的最大时间;

返回值:

0:接收失败

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

cpp 复制代码
BaseType_t xTaskNotifyWait( 
    uint32_t      ulBitsToClearOnEntry,
    uint32_t      ulBitsToClearOnExit,
    uint32_t *    pulNotificationValue,
    TickType_t    xTicksToWait 
);

ulBitsToClearOnEntry:函数执行前清零任务通知值那些位 。

ulBitsToClearOnExit:表示在函数退出前,清零任务通知值那些位(最大值:0xFFFFFFFF),在清 0 前,接收到的任务通知值会先被 保存到形参*pulNotificationValue 中。

pulNotificationValue:用于保存接收到的任务通知值。 如果不需要使用,则设置为 NULL 即可 。 xTicksToWait:等待消息通知的最大等待时间。

五、实操

5.1、模拟二值信号量

按下 KEY1 则释放信号量,按下 KEY2 获取信号量。

cpp 复制代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

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

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

/* USER CODE END Variables */
osThreadId TaskKEY1Handle;
osThreadId TaskKEY2Handle;

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

void StartTaskKEY1(void const * argument);
void StartTaskKEY2(void const * argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/* GetIdleTaskMemory prototype (linked to static allocation support) */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );

/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];

void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
  *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
  *ppxIdleTaskStackBuffer = &xIdleStack[0];
  *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
  /* place for user code */
}
/* USER CODE END GET_IDLE_TASK_MEMORY */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* definition and creation of TaskKEY1 */
  osThreadDef(TaskKEY1, StartTaskKEY1, osPriorityNormal, 0, 128);
  TaskKEY1Handle = osThreadCreate(osThread(TaskKEY1), NULL);

  /* definition and creation of TaskKEY2 */
  osThreadDef(TaskKEY2, StartTaskKEY2, osPriorityNormal, 0, 128);
  TaskKEY2Handle = osThreadCreate(osThread(TaskKEY2), NULL);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

}

/* USER CODE BEGIN Header_StartTaskKEY1 */
/**
  * @brief  Function implementing the TaskKEY1 thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartTaskKEY1 */
void StartTaskKEY1(void const * argument)
{
  /* USER CODE BEGIN StartTaskKEY1 */
	BaseType_t mark = 0;
  /* Infinite loop */
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_0) == GPIO_PIN_RESET)
		{
			osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_0) == GPIO_PIN_RESET)
			{
				 mark = xTaskNotifyGive( TaskKEY2Handle );
				if(mark == pdPASS)
					printf("任务通知模拟二值信号量发送成功!\r\n");
				else
					printf("任务通知模拟二值信号量发送失败!\r\n");
			}
			while(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_0) == GPIO_PIN_RESET);
		}
    osDelay(10);
  }
  /* USER CODE END StartTaskKEY1 */
}

/* USER CODE BEGIN Header_StartTaskKEY2 */
/**
* @brief Function implementing the TaskKEY2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTaskKEY2 */
void StartTaskKEY2(void const * argument)
{
  /* USER CODE BEGIN StartTaskKEY2 */
	uint32_t flag = 0;
  /* Infinite loop */
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_1) == GPIO_PIN_RESET)
		{
			osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_1) == GPIO_PIN_RESET)
			{
				flag = ulTaskNotifyTake(pdTRUE ,0);
				if(flag != 0)
					printf("接收成功!任务的通知值为:%d\r\n",flag);
				else
					printf("接收失败!\r\n");
			}
			while(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_1) == GPIO_PIN_RESET);
		}
    osDelay(10);
  }
  /* USER CODE END StartTaskKEY2 */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */

5.2、模拟计数型信号量

按下 KEY1 则释放信号量,按下 KEY2 获取信号量。

cpp 复制代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

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

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

/* USER CODE END Variables */
osThreadId TaskKEY1Handle;
osThreadId TaskKEY2Handle;

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

void StartTaskKEY1(void const * argument);
void StartTaskKEY2(void const * argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/* GetIdleTaskMemory prototype (linked to static allocation support) */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );

/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];

void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
  *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
  *ppxIdleTaskStackBuffer = &xIdleStack[0];
  *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
  /* place for user code */
}
/* USER CODE END GET_IDLE_TASK_MEMORY */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* definition and creation of TaskKEY1 */
  osThreadDef(TaskKEY1, StartTaskKEY1, osPriorityNormal, 0, 128);
  TaskKEY1Handle = osThreadCreate(osThread(TaskKEY1), NULL);

  /* definition and creation of TaskKEY2 */
  osThreadDef(TaskKEY2, StartTaskKEY2, osPriorityNormal, 0, 128);
  TaskKEY2Handle = osThreadCreate(osThread(TaskKEY2), NULL);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

}

/* USER CODE BEGIN Header_StartTaskKEY1 */
/**
  * @brief  Function implementing the TaskKEY1 thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartTaskKEY1 */
void StartTaskKEY1(void const * argument)
{
  /* USER CODE BEGIN StartTaskKEY1 */
	BaseType_t mark = 0;
  /* Infinite loop */
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_0) == GPIO_PIN_RESET)
		{
			osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_0) == GPIO_PIN_RESET)
			{
				 mark = xTaskNotifyGive( TaskKEY2Handle );
				if(mark == pdPASS)
					printf("任务通知模拟计数型信号量发送成功!\r\n");
				else
					printf("任务通知模拟计数型信号量发送失败!\r\n");
			}
			while(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_0) == GPIO_PIN_RESET);
		}
    osDelay(10);
  }
  /* USER CODE END StartTaskKEY1 */
}

/* USER CODE BEGIN Header_StartTaskKEY2 */
/**
* @brief Function implementing the TaskKEY2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTaskKEY2 */
void StartTaskKEY2(void const * argument)
{
  /* USER CODE BEGIN StartTaskKEY2 */
	uint32_t flag = 0;
  /* Infinite loop */
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_1) == GPIO_PIN_RESET)
		{
			osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_1) == GPIO_PIN_RESET)
			{
				flag = ulTaskNotifyTake(pdFALSE ,0);
				if(flag != 0)
					printf("接收成功!任务的通知值为:%d\r\n",flag);
				else
					printf("接收失败!\r\n");
			}
			while(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_1) == GPIO_PIN_RESET);
		}
    osDelay(10);
  }
  /* USER CODE END StartTaskKEY2 */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */

5.3、模拟事件标志组

两个任务( task1 和 task2),task1 检测按键,如果检测到 KEY1 和 KEY2 都按过, 则执行 task2 。

cpp 复制代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

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

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

/* USER CODE END Variables */
osThreadId Task1Handle;
osThreadId Task2Handle;

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

void StartTask1(void const * argument);
void StartTask2(void const * argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/* GetIdleTaskMemory prototype (linked to static allocation support) */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );

/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];

void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
  *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
  *ppxIdleTaskStackBuffer = &xIdleStack[0];
  *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
  /* place for user code */
}
/* USER CODE END GET_IDLE_TASK_MEMORY */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* definition and creation of Task1 */
  osThreadDef(Task1, StartTask1, osPriorityNormal, 0, 128);
  Task1Handle = osThreadCreate(osThread(Task1), NULL);

  /* definition and creation of Task2 */
  osThreadDef(Task2, StartTask2, osPriorityNormal, 0, 128);
  Task2Handle = osThreadCreate(osThread(Task2), NULL);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

}

/* USER CODE BEGIN Header_StartTask1 */
/**
  * @brief  Function implementing the Task1 thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartTask1 */
void StartTask1(void const * argument)
{
  /* USER CODE BEGIN StartTask1 */
  /* Infinite loop */
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_0) == GPIO_PIN_RESET)
		{
			osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_0) == GPIO_PIN_RESET)
			{
				printf("bit23位置1\r\n");
				xTaskNotifyAndQuery(Task2Handle ,0x800000 ,eSetBits ,NULL);
			}
			while(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_0) == GPIO_PIN_RESET);
		}
		
		if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_1) == GPIO_PIN_RESET)
		{
			osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_1) == GPIO_PIN_RESET)
			{
				printf("bit1与bit0位置1\r\n");
				xTaskNotifyAndQuery(Task2Handle ,0x3 ,eSetBits ,NULL);		/*0011*/
			}
			while(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_1) == GPIO_PIN_RESET);
		}
    osDelay(10);
  }
  /* USER CODE END StartTask1 */
}

/* USER CODE BEGIN Header_StartTask2 */
/**
* @brief Function implementing the Task2 thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTask2 */
void StartTask2(void const * argument)
{
  /* USER CODE BEGIN StartTask2 */
	uint32_t events = 0,result_bit = 0;
  /* Infinite loop */
  for(;;)
  {
		xTaskNotifyWait(0 ,0xFFFFFFFF ,&events ,portMAX_DELAY);
		if(events & 0x800000)
			result_bit |= 0x800000;
		if(events & 0x3)
			result_bit |= 0x3;
		if(result_bit == (0x800000 | 0x3))
		{
			printf("请假成功,任务通知模拟事件标志组成功!\r\n");
			result_bit = 0;
		}
    osDelay(10);
  }
  /* USER CODE END StartTask2 */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */

5.4、模拟邮箱

邮箱是长度为1的队列

5.4.1、覆盖

cpp 复制代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

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

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

/* USER CODE END Variables */
osThreadId TaskSendHandle;
osThreadId TaskReceiveHandle;

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

void StartTaskSend(void const * argument);
void StartTaskReceive(void const * argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/* GetIdleTaskMemory prototype (linked to static allocation support) */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );

/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];

void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
  *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
  *ppxIdleTaskStackBuffer = &xIdleStack[0];
  *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
  /* place for user code */
}
/* USER CODE END GET_IDLE_TASK_MEMORY */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* definition and creation of TaskSend */
  osThreadDef(TaskSend, StartTaskSend, osPriorityNormal, 0, 128);
  TaskSendHandle = osThreadCreate(osThread(TaskSend), NULL);

  /* definition and creation of TaskReceive */
  osThreadDef(TaskReceive, StartTaskReceive, osPriorityNormal, 0, 128);
  TaskReceiveHandle = osThreadCreate(osThread(TaskReceive), NULL);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

}

/* USER CODE BEGIN Header_StartTaskSend */
/**
  * @brief  Function implementing the TaskSend thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartTaskSend */
void StartTaskSend(void const * argument)
{
  /* USER CODE BEGIN StartTaskSend */
	static uint32_t cnt = 0;
  /* Infinite loop */
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_0) == GPIO_PIN_RESET)
		{
			osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_0) == GPIO_PIN_RESET)
			{
				if(cnt == 0)
				{
					xTaskNotify(TaskReceiveHandle ,1 ,eSetValueWithOverwrite);    /*覆盖*/
					cnt++;
					printf("任务通知模拟邮箱(长度为1的队列)写入值:1\r\n");
				}
				else
				{
					xTaskNotify(TaskReceiveHandle ,5 ,eSetValueWithOverwrite);
					printf("任务通知模拟邮箱(长度为1的队列)写入值:5\r\n");
					cnt = 0;
				}
			}
			while(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_0) == GPIO_PIN_RESET);
		}
    osDelay(10);
  }
  /* USER CODE END StartTaskSend */
}

/* USER CODE BEGIN Header_StartTaskReceive */
/**
* @brief Function implementing the TaskReceive thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTaskReceive */
void StartTaskReceive(void const * argument)
{
  /* USER CODE BEGIN StartTaskReceive */
	uint32_t notify_queue = 0;
  /* Infinite loop */
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_1) == GPIO_PIN_RESET)
		{
			osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_1) == GPIO_PIN_RESET)
			{
				xTaskNotifyWait(0 ,0xFFFFFF ,&notify_queue ,portMAX_DELAY);
				printf("任务通知模拟邮箱接收值为:%d\r\n",notify_queue);
			}
			while(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_1) == GPIO_PIN_RESET);
		}
    osDelay(10);
  }
  /* USER CODE END StartTaskReceive */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */

结果:

5.4.2、不覆盖

cpp 复制代码
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2024 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

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

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

/* USER CODE END Variables */
osThreadId TaskSendHandle;
osThreadId TaskReceiveHandle;

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

void StartTaskSend(void const * argument);
void StartTaskReceive(void const * argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/* GetIdleTaskMemory prototype (linked to static allocation support) */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );

/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];

void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
  *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
  *ppxIdleTaskStackBuffer = &xIdleStack[0];
  *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
  /* place for user code */
}
/* USER CODE END GET_IDLE_TASK_MEMORY */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* definition and creation of TaskSend */
  osThreadDef(TaskSend, StartTaskSend, osPriorityNormal, 0, 128);
  TaskSendHandle = osThreadCreate(osThread(TaskSend), NULL);

  /* definition and creation of TaskReceive */
  osThreadDef(TaskReceive, StartTaskReceive, osPriorityNormal, 0, 128);
  TaskReceiveHandle = osThreadCreate(osThread(TaskReceive), NULL);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

}

/* USER CODE BEGIN Header_StartTaskSend */
/**
  * @brief  Function implementing the TaskSend thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartTaskSend */
void StartTaskSend(void const * argument)
{
  /* USER CODE BEGIN StartTaskSend */
	static uint32_t cnt = 0;
  /* Infinite loop */
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_0) == GPIO_PIN_RESET)
		{
			osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_0) == GPIO_PIN_RESET)
			{
				if(cnt == 0)
				{
					xTaskNotify(TaskReceiveHandle ,1 ,eSetValueWithoutOverwrite);		/*不覆盖*/
					cnt++;
					printf("任务通知模拟邮箱(长度为1的队列)写入值:1\r\n");
				}
				else
				{
					xTaskNotify(TaskReceiveHandle ,5 ,eSetValueWithoutOverwrite);
					printf("任务通知模拟邮箱(长度为1的队列)写入值:5\r\n");
					cnt = 0;
				}
			}
			while(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_0) == GPIO_PIN_RESET);
		}
    osDelay(10);
  }
  /* USER CODE END StartTaskSend */
}

/* USER CODE BEGIN Header_StartTaskReceive */
/**
* @brief Function implementing the TaskReceive thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_StartTaskReceive */
void StartTaskReceive(void const * argument)
{
  /* USER CODE BEGIN StartTaskReceive */
	uint32_t notify_queue = 0;
  /* Infinite loop */
  for(;;)
  {
		if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_1) == GPIO_PIN_RESET)
		{
			osDelay(20);
			if(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_1) == GPIO_PIN_RESET)
			{
				xTaskNotifyWait(0 ,0xFFFFFF ,&notify_queue ,portMAX_DELAY);
				printf("任务通知模拟邮箱接收值为:%d\r\n",notify_queue);
			}
			while(HAL_GPIO_ReadPin(GPIOA ,GPIO_PIN_1) == GPIO_PIN_RESET);
		}
    osDelay(10);
  }
  /* USER CODE END StartTaskReceive */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */

结果:

相关推荐
无敌最俊朗@1 小时前
stm32学习之路——八种GPIO口工作模式
c语言·stm32·单片机·学习
EterNity_TiMe_1 小时前
【论文复现】STM32设计的物联网智能鱼缸
stm32·单片机·嵌入式硬件·物联网·学习·性能优化
L_cl2 小时前
Python学习从0到1 day28 Python 高阶技巧 ⑤ 多线程
学习
前端SkyRain2 小时前
后端Node学习项目-用户管理-增删改查
后端·学习·node.js
提笔惊蚂蚁2 小时前
结构化(经典)软件开发方法: 需求分析阶段+设计阶段
后端·学习·需求分析
DDDiccc2 小时前
JAVA学习日记(十五) 数据结构
数据结构·学习
腾科张老师4 小时前
为什么要使用Ansible实现Linux管理自动化?
linux·网络·学习·自动化·ansible
tao_sc6 小时前
luckfox-pico-max学习记录
学习
zx_zx_1236 小时前
多态的学习
c++·学习
B1nna9 小时前
SpringMVC学习记录(三)之响应数据
java·学习·json·springmvc·jsp