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 );
}

效果:

相关推荐
爱丶不疚几秒前
BrowserWindow:你的Electron 应用可以不用手写红绿灯
前端·electron
吴声子夜歌1 分钟前
Java面试——Flink原理及应用(二)
java·面试·flink
用户594404103567 分钟前
【完整fx】Vue3 + TS + Leafletjs 打造企业级原神大地图
前端
深念Y10 分钟前
数据库层设计的取舍:ORM 便利性与手写 SQL 的安全性权衡
java·数据库·sql·golang·框架·语言·ome
黑泽明*10 分钟前
云计算与服务器基础入门指南
服务器·云计算·perl
小江的记录本12 分钟前
【ORM 框架】MyBatis-Plus 核心特性、条件构造器、分页插件、乐观锁插件(附《思维导图》、《问题排查与实践清单》和《面试高频考点汇总》)
java·windows·spring boot·python·spring·面试·mybatis
clorinda13 分钟前
SQL 快速入门:题目单知识点精炼总结
java·数据库·sql
小HANN22 分钟前
保姆级实战:CentOS7 搭建 LAMP 环境部署 WordPress 个人博客
linux·运维·服务器·经验分享
AI人工智能+电脑小能手23 分钟前
大白话说Java设计模式-40-备忘录模式(业务实战篇)
java·设计模式·事务回滚·备忘录模式·状态保存·spring transactional·购物车快照
计算机魔术师23 分钟前
AI开源社区迎来最大并购案:Hugging Face以129亿美元估值入局英伟达
前端