FREERTOS_任务通知——使用

目录

一、特点

[二、使用流程(无 "创建" 步骤,直接用任务句柄)](#二、使用流程(无 “创建” 步骤,直接用任务句柄))

[1. 前置准备(已经有一个可以run的任务,下面这些得有)](#1. 前置准备(已经有一个可以run的任务,下面这些得有))

[2. 创建发送 / 接收任务](#2. 创建发送 / 接收任务)

[三、基本使用(核心 API 与操作)](#三、基本使用(核心 API 与操作))

[1. 发送通知(发送任务调用)](#1. 发送通知(发送任务调用))

[2. 接收通知(接收任务调用)](#2. 接收通知(接收任务调用))

四、接收和发送加一个简单的校验,这里以LED为例:

1、main外的:

2、我有创建的两个任务:

任务1、

任务2、这个函数读取不同的按键来发不同的任务通知


一、特点

  • 无需创建独立句柄:通过任务句柄直接发送 / 接收通知,省内存;
  • 32 位通知内容:可存储命令、参数、状态等(灵活传递少量数据);
  • 支持多模式:覆盖、叠加、置位等,适配不同场景;
  • 替代简单队列 / 信号量:适合 "任务→任务" 的一对一 / 一对多通信。

二、使用流程(无 "创建" 步骤,直接用任务句柄)

1. 前置准备(已经有一个可以run的任务,下面这些得有)

包含头文件

复制代码
#include "FreeRTOS.h"
#include "task.h" // 任务通知API在task.h中声明

定义接收任务的句柄

复制代码
TaskHandle_t xRecvTaskHandle = NULL; // 接收通知的任务句柄
2. 创建发送 / 接收任务

通过xTaskCreate()创建两个任务(发送方和接收方),并保存接收任务的句柄:

复制代码
// 创建接收任务(保存句柄)
xTaskCreate(RecvTask, "RecvTask", 128, NULL, 1, &xRecvTaskHandle);
// 创建发送任务
xTaskCreate(SendTask, "SendTask", 128, NULL, 2, NULL);

三、基本使用(核心 API 与操作)

1. 发送通知(发送任务调用)

**在任务中:**用xTaskNotify()发送 32 位通知内容,关键是指定 "接收任务句柄" 和 "通知模式":

复制代码
uint32_t ulNotifyValue = 0x12345678; // 32位通知内容(可存命令+参数)

// 发送通知(核心函数)
xTaskNotify(
  xRecvTaskHandle,        // 接收通知的任务句柄(必须有效)
  ulNotifyValue,          // 要发送的32位内容
  eSetValueWithOverwrite  // 通知模式(常用3种,见下表)
);

常用的通知模式:

模式 作用 适用场景
eSetValueWithOverwrite 新通知覆盖旧通知(仅保留最新值) 传递实时参数(如闪烁频率)
eSetValueWithoutOverwrite 旧通知未处理则不覆盖(防止丢失) 传递事件(如按键触发)
eSetBits 按位叠加(仅置 1 对应位,不清除其他位) 多事件标记(如多个按键)
2. 接收通知(接收任务调用)

**在任务中:**用xTaskNotifyWait()等待并接收通知,可设置 "阻塞超时" 和 "位操作":

参数定义放任务起始:

复制代码
uint32_t ulRecvValue; // 存储接收的32位通知内容
BaseType_t xResult;   // 接收结果(pdPASS=成功)

接收的代码:

复制代码
// 接收通知(核心函数)
xResult = xTaskNotifyWait(
  0xFFFFFFFFU,        // 接收后要清除的位(0xFFFFFFFF=清除所有位)
  0xFFFFFFFFU,        // 接收时要保留的位(0xFFFFFFFF=保留所有位)
  &ulRecvValue,       // 存储接收内容的指针
  portMAX_DELAY       // 阻塞超时时间(0=非阻塞,portMAX_DELAY=永久等待)
);

// 处理通知
if(xResult == pdPASS) {
  // 解析ulRecvValue(如命令+参数分离)
  uint16_t cmd = (ulRecvValue >> 16) & 0xFFFF; // 高16位为命令
  uint16_t param = ulRecvValue & 0xFFFF;       // 低16位为参数
}

四、接收和发送加一个简单的校验,这里以LED为例:

通过位运算检查高 16 位的 "命令标识":

为什么用高 16 位做命令?

避免参数值和命令冲突(比如参数最大是 65535,不会影响高 16 位);

为什么用固定命令值?

唯一标识通知的用途(比如后续扩展CMD_SET_COLOR控制 LED 颜色,也用高 16 位区分)。

1、main外的:
复制代码
// 任务通知内容定义(用32位值传递:高16位标识命令,低16位传递参数)
#define CMD_SET_DELAY       0x00010000U // 命令:设置LED延时
#define GET_DELAY_PARAM(x)  (x & 0xFFFFU) // 提取低16位的延时参数
2、我有创建的两个任务:
复制代码
//外:
osThreadId_t LED_TaskHandle;
const osThreadAttr_t LED_Task_attributes = {
  .name = "LED_Task",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityBelowNormal7,
};

osThreadId_t KEY_TaskHandle;
const osThreadAttr_t KEY_Task_attributes = {
  .name = "KEY_Task",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};
void Start_LED_Task(void *argument);
void Start_KEY_Task(void *argument);


//内:
LED_TaskHandle = osThreadNew(Start_LED_Task, NULL, &LED_Task_attributes);
KEY_TaskHandle = osThreadNew(Start_KEY_Task, NULL, &KEY_Task_attributes);
任务1、
复制代码
void Start_LED_Task(void *argument)
{
  uint32_t ulNotificationValue; // 接收的通知内容
  uint16_t current_delay = 500U; // 默认500ms闪烁
  BaseType_t xResult;

  // 初始状态:确保LED是熄灭的(可选,根据硬件调整)
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
  for(;;)
  { //HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_10);
    /* 核心修改:用 xTaskNotifyWait 替代 xTaskNotifyWaitIndexed(基础API) */
    xResult = xTaskNotifyWait(
      0xFFFFFFFFU,        // 接收后清除所有位(清空通知)
      0xFFFFFFFFU,        // 保留所有位(完整接收32位内容)
      &ulNotificationValue, // 存储通知内容
      0  //portMAX_DELAY       // 永久等待通知
    );

    /* 收到通知后解析处理 */
    if(xResult == pdPASS)
    {
      // 判断是否是"设置延时"命令
      if((ulNotificationValue & 0xFFFF0000U) == CMD_SET_DELAY)
      {
        current_delay = GET_DELAY_PARAM(ulNotificationValue); // 更新延时
      }
    }

    HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
    vTaskDelay(current_delay); // ѓʱ500ms
  }
}
任务2、这个函数读取不同的按键来发不同的任务通知
复制代码
    case 1:
		// 构造通知:命令 + 延时参数
        ulNotificationValue = CMD_SET_DELAY | 200U;
        // 核心修改:用 xTaskNotify 替代 xTaskNotifyGiveIndexed(基础API,无索引)
        //             接收通知的任务句柄、通知内容、覆盖模式:新通知替换旧通知
        xTaskNotify(LED_TaskHandle, ulNotificationValue,eSetValueWithOverwrite);        
        ); 
    break;

    case 2:
		ulNotificationValue = CMD_SET_DELAY | 800U;
        xTaskNotify(LED_TaskHandle, ulNotificationValue, eSetValueWithOverwrite);
    break;
相关推荐
CC.GG15 小时前
【C++】STL----封装红黑树实现map和set
android·java·c++
xinyu_Jina15 小时前
Calculator Game:WebAssembly在计算密集型组合优化中的性能优势
前端·ui·性能优化
loosenivy15 小时前
IP风险画像识别和IP风险预警接口
java·ip查询·ip风险画像识别·ip预警查询·ip画像
JustHappy15 小时前
「2025年终个人总结」🤬🤬回答我!你个菜鸟程序员这一年发生了啥?
前端
BD_Marathon15 小时前
Vue3_计算属性
javascript·vue.js·ecmascript
wniuniu_16 小时前
ceph运维
运维·javascript·ceph
啃火龙果的兔子16 小时前
可以指定端口启动本地前端的npm包
前端·npm·node.js
汤姆yu16 小时前
基于springboot的林业资源管理系统
java·spring boot·后端
软件管理系统16 小时前
基于Spring Boot的医疗服务系统的设计与实现
java·spring boot·后端