FreeRTOS任务通知源码分析

本文深入探讨FreeRTOS任务通知机制,包括其功能、优势及应用场景。任务通知可用于任务间同步,模拟信号量、事件标志组和消息队列。文章详细解析了任务通知的发送与接收函数,以及在中断与任务级的使用方法。通过实例代码,展示了任务通知在二值信号量、计数型信号量、消息和事件标志组的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里是对学习任务通知的一些东西做的总结

任务通知能干什么

  1. 模拟事件标志组
  2. 模拟二值信号量和计数型信号量,只不过做计数型信号量的时候不适合做共享资源的使用
  3. 模拟消息队列发送消息

当然这里只能替代这些功能的一部分,因为
1.只能有一个任务接收任务通知,所以只能实现一个任务之间的任务同步,一个不能实现多个任务之间的任务同步,这里补充一下,就是等待任务通知的那个任务是任务自身,由其他任务发送它的任务通知,类似于UCOSIII的内嵌信号量的用法
2.发送任务通知的那个任务不会出现发送任务通知失败而进入阻塞状态,但是接受任务通知那个任务可以因为没有收到任务
当然他的优势就是减少内存的开销,同时它的处理速度加快,提高了任务的实时性

任务通知的用法即源码分析
1.任务级发送任务通知函数

函数 xTaskNotify( xTaskToNotify, ulValue, eAction )作用: 可以发送消息、事件标志位、信号量
函数原型,即上面这个函数是一个宏定义,它替代的函数是这个xTaskGenericNotify()真正起作用的是这个xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL )
参数参数介绍
xTaskToNotify任务句柄是指接收任务通知的那个任务句柄
ulValue任务通知值(根据不同的类型的任务通知发送不同的值)
eAction发送什么类型的任务通知(消息 事件标志位 信号量 这三种)
xTaskGenericNotify( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL )
BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue )
	{
	TCB_t * pxTCB;
	BaseType_t xReturn = pdPASS;
	uint8_t ucOriginalNotifyState;
	
		pxTCB = ( TCB_t * ) xTaskToNotify;  /* 接收通知那个任务的任务句柄 */
		taskENTER_CRITICAL();  /* 临界段代码保护*/
		{
			if( pulPreviousNotificationValue != NULL )  /* 指针指向不为空 */
			{
				*pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
			}
             /* 保存之前任务通知的状态,为了后面是否解除任务阻塞做铺垫*/
			ucOriginalNotifyState = pxTCB->ucNotifyState;
  pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;  /*接收那个任务的任务通知状态变成接收态 */
			switch( eAction )   /* 给任务发送通知的形式 */
			{
				case eSetBits	:   /* 对任务通知值相应的位置一类似一发送一个标志位事件 */
					pxTCB->ulNotifiedValue |= ulValue;
					break;

				case eIncrement	: /* 对任务通知值自增类似一发送一个计数型或者二值型的信号量 */
					( pxTCB->ulNotifiedValue )++;
					break;
           
				case eSetValueWithOverwrite	: /* 对任务通知值直接赋值类似一发送消息事件,不管上一个任务还没有处理掉这个消息直接发送新的消息 */
					pxTCB->ulNotifiedValue = ulValue;
					break;

				case eSetValueWithoutOverwrite : 
					if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
					{
						pxTCB->ulNotifiedValue = ulValue;
					}
					else
					{
						/* 如果被通知任务还没取走上一个通知,本次发送通知,
						   任务又接收到了一个通知,则这次通知值丢弃,
						   在这种情况下,函数调用失败并返回 pdFALSE。 */
						xReturn = pdFAIL;
					}
					break;

				case eNoAction: /* 对任务通知值不做任何操作 */
					/* The task is being notified without its notify value being
					updated. */
					break;
			}

			traceTASK_NOTIFY();

	/* 原来任务通知的状态如果是等待任务通知处于了阻塞态,那么就要解除它,因为有任务给他发送了通知 */
			if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
			{
		( void ) uxListRemove( &( pxTCB->xStateListItem ) );   /* 从任务阻塞列表中删除该任务 */
		prvAddTaskToReadyList( pxTCB );                         /* 将任务添加到任务就绪列表 */

				 /* 如果接受任务通知的任务优先级大于当前运行的任务,那么就要任务切换 */
				if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
				{
					/* The notified task has a priority above the currently
					executing task so a yield is required. */
					taskYIELD_IF_USING_PREEMPTION();
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		taskEXIT_CRITICAL();  /* 退出临界段代码保护*/

		return xReturn;
	}

函数总结:

  1. 获取任务控制块首地址,并保存任务通知的状态与一个变量里面,并修改任务通知状态为接收态
  2. 根据不同的需求该变任务通知的值
    用再信号量 则任务通知值自增
    用再事件标志组 则任务通知值的相应位置一
    用在消息队列 直接复制,在复写的情况下,如果没有复写即任务还没有处理掉这个消息就是任务的状态还是接收态 就放弃这次赋值
  3. 如果任务之前的状态是等待态,就要将任务解除阻塞态,如果解除任务阻塞的任务比当前运行任务优先级高就做任务切换
函数 xTaskNotifyGive( xTaskToNotify )作用: 专门发送信号量的
函数原型,即上面这个函数是一个宏定义,它替代的函数是这个xTaskGenericNotify()真正起作用的是这个xTaskGenericNotify( ( xTaskToNotify ), ( 0 ), eIncrement, NULL )
参数参数介绍
xTaskToNotify任务句柄是指接收任务通知的那个任务句柄

用法和上面那个函数一样,因为它替换的是同一个函数

2.中断级发送任务通知函数

函数 vTaskNotifyGiveFromISR( xTaskToNotify, *pxHigherPriorityTaskWoken)作用:专门发送信号量
参数参数介绍
xTaskToNotify任务句柄是指接收任务通知的那个任务句柄
*pxHigherPriorityTaskWoken是一个变量的指针,它的是pdTRUE表示要任务切换,pdFALSE不用任务切换
TCB_t * pxTCB;
	uint8_t ucOriginalNotifyState;
	UBaseType_t uxSavedInterruptStatus;
		portASSERT_IF_INTERRUPT_PRIORITY_INVALID();
		pxTCB = ( TCB_t * ) xTaskToNotify;//获取任务控制块地址
		uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();//中断级临界段代码保护
		{
			ucOriginalNotifyState = pxTCB->ucNotifyState; //获取之前的任务通知的状态
			pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;//将任务状态变成接收态
			( pxTCB->ulNotifiedValue )++;//任务通知值自增

			/* 之前的任务通知状态是等待态,可能要解除任务阻塞态 */
			if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
			{
				if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) //任务调度器没有挂起
				{
( void ) uxListRemove( &( pxTCB->xStateListItem ) );//从阻塞列表删除该任务,并将任务添加到任务就绪列表
		 prvAddTaskToReadyList( pxTCB );
				}
				else //任务调度器挂起,先将任务添加到等待就绪列表
				{
					vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
				}
                //如果解除阻塞的任务比当前运行的任务优先级还要高那么就要进行任务切换
				if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
				{
					/* The notified task has a priority above the currently
					executing task so a yield is required. */
					if( pxHigherPriorityTaskWoken != NULL )
					{
						*pxHigherPriorityTaskWoken = pdTRUE;
					}
					else
					{
						xYieldPending = pdTRUE;
					}
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
		}
		portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );//退出中断级临界段代码保护
	}
函数 xTaskNotifyFromISR( xTaskToNotify, ulValue, eAction, pxHigherPriorityTaskWoken )作用:专门信号量、消息、事件标志位
函数原型,即上面这个函数是一个宏定义,它替代的函数是这个xTaskGenericNotifyFromISR()真正起作用的是这个xTaskGenericNotifyFromISR( ( xTaskToNotify ), ( ulValue ), ( eAction ), NULL, ( pxHigherPriorityTaskWoken ) )
参数参数介绍
xTaskToNotify任务句柄是指接收任务通知的那个任务句柄
ulValue任务通知值(根据不同的类型的任务通知发送不同的值)
eAction发送什么类型的任务通知(消息 事件标志位 信号量 这三种)
*pxHigherPriorityTaskWoken是一个变量的指针,它的是pdTRUE表示要任务切换,pdFALSE不用任务切换
	BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken )
	{
	TCB_t * pxTCB;
	uint8_t ucOriginalNotifyState;
	BaseType_t xReturn = pdPASS;
	UBaseType_t uxSavedInterruptStatus;
		portASSERT_IF_INTERRUPT_PRIORITY_INVALID();

		pxTCB = ( TCB_t * ) xTaskToNotify;   /* 获取发送任务通知的任务控制块地址*/

		uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); /* 中断级临界段代码保护*/ 
		{
			if( pulPreviousNotificationValue != NULL ) /* 指针指向不为空 */ 
			{
	*pulPreviousNotificationValue = pxTCB->ulNotifiedValue; /* 将任务通知值赋给*pulPreviousNotificationValue */ 
			}

			ucOriginalNotifyState = pxTCB->ucNotifyState;     /* 之前的任务状态做保存*/
			pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;/*  现在的任务状态变成接收态*/

			/* 根据不同的动作(事件标志组  消息  信号量) 做不同的事情*/
			switch( eAction )
			{
				case eSetBits	:
					pxTCB->ulNotifiedValue |= ulValue;
					break;

				case eIncrement	:
					( pxTCB->ulNotifiedValue )++;
					break;

				case eSetValueWithOverwrite	:
					pxTCB->ulNotifiedValue = ulValue;
					break;

				case eSetValueWithoutOverwrite :
					if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
					{
						pxTCB->ulNotifiedValue = ulValue;
					}
					else
					{
						/* The value could not be written to the task. */
						xReturn = pdFAIL;
					}
					break;

				case eNoAction :
					/* The task is being notified without its notify value being
					updated. */
					break;
			}

if( ucOriginalNotifyState == taskWAITING_NOTIFICATION ) /* 之前的任务状态是等待态,则需要解除任务阻塞*/ 
			{
                /* 任务调度器是否挂起*/
				if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE ) /* 任务调度器没有挂起*/
				{
					( void ) uxListRemove( &( pxTCB->xStateListItem ) ); /* 从阻塞列表移出该任务,并将任务添加到任务就绪列表 */
					prvAddTaskToReadyList( pxTCB );
				}
				else /* 任务调度器挂起 */
				{
vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );/* 则先将任务添加到任务等待就绪列表*/
				}

/* 如果任务优先级比当前运行的任务优先级高,就要进行任务切换,因为有任务解除了阻塞态*/
				if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
				{

					if( pxHigherPriorityTaskWoken != NULL )
					{
						*pxHigherPriorityTaskWoken = pdTRUE;
					}
					else
					{
						xYieldPending = pdTRUE; 
					}
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
		}
		portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); /* 退出中断级临界段代码保护*/

		return xReturn;
	}

函数总结:

  1. 获取任务控制块首地址,并保存任务通知的状态与一个变量里面,并修改任务通知状态为接收态
  2. 根据不同的需求该变任务通知的值
    用再信号量 则任务通知值自增
    用再事件标志组 则任务通知值的相应位置一
    用在消息队列 直接复制,在复写的情况下,如果没有复写即任务还没有处理掉这个消息就是任务的状态还是接收态 就放弃这次赋值
  3. 如果任务之前的状态是等待态,就要将任务解除阻塞态,,如果解除任务阻塞的任务比当前运行任务优先级高就做任务切换;在任务调度器没有挂起的情况下,那么在任务调度器挂起条件下就将任务插入到等待就绪列表,等任务调度器解挂在处理它

3.等待任务通知函数,没有中断级的,

uint32_t ulTaskNotifyTake( xClearCountOnExit, xTicksToWait )这是一个专门等待信号量的的函数
参数参数介绍
xClearCountOnExit收到任务通知之后处理完是否将任务通知值清空 pdTRUE=清空 用于二值信号量 pdFALSE=不清空,用于计数型信号量
xTicksToWait阻塞时间,如果没有收到任务通知需要的阻塞时间
	uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait ) /* 这是一个专门等待信号量的的函数 */
	{
	uint32_t ulReturn;

		taskENTER_CRITICAL();
		{
			/* 任务通知的值为0 */
			if( pxCurrentTCB->ulNotifiedValue == 0UL )
			{
				
				pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION; /* 任务通知的状态变成等待态 */

				if( xTicksToWait > ( TickType_t ) 0 )  /* 等待任务通知的时间不为0,则表示任务会进行任务阻塞 */
				{
		prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); /* 加入延时列表,如果是无限等待则加入挂起列表 */


					/* .进行任务切换 */
					portYIELD_WITHIN_API();
				}
				else /* 等待任务通知的时间为0,则表示任务不会进行任务阻塞 */
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		taskEXIT_CRITICAL();

		 /*1. 等待任务通知的时间为0,任务没有进行任务阻塞 
		   2. 任务通知值不为0,即信号量数还有
		   3. 之前任务处于阻塞态,但是现在接受到任务通知,解除了任务阻塞运行到这里*/
		taskENTER_CRITICAL();
		{
			traceTASK_NOTIFY_TAKE();
			ulReturn = pxCurrentTCB->ulNotifiedValue; /* 将当前任务的任务通知值给 ulReturn*/

			if( ulReturn != 0UL ) /* 将当前任务的任务通知值不为0 */
			{
	if( xClearCountOnExit != pdFALSE ) /* 将当前任务的任务通知值清空 xClearCountOnExit==pdTRUE 用于二值型号量*/
				{
					pxCurrentTCB->ulNotifiedValue = 0UL;
				}
				else  /* 将当前任务的任务通知值自减  用于计数型型号量*/
				{
					pxCurrentTCB->ulNotifiedValue = ulReturn - 1;
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}

			pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION; /* 任务状态变成不等待任务通知状态 */
		}
		taskEXIT_CRITICAL();

		return ulReturn;
	}

函数总结:

1.如果任务通知值为空,则任务阻塞时间不为空,需要任务阻塞就要将任务添加到延时列表或者挂起列表即阻塞列表然后任务切换,等待任务通知的到来
2. 进入到函数下半部分 可能是3种情况 case1:接收到任务通知 case2:是阻塞时间到了还没有接收到任务通知 case3:任务通知值不为空
不同情况的处理 case1 如果是等待计数型信号量, 任务通知值自减,如果是等待二值信号量,任务通知值直接清空 ,任务通知状态变成初始态 并返回任务通知接收成功 pdTRUE
case2 任务通知值为0 任务通知状态变成初始态 并返回任务通知接收失败 pdFALSE
case3 与case1 情况一样

xTaskNotifyWait( ulBitsToClearOnEntry, ulBitsToClearOnExit, *pulNotificationValue, xTicksToWait )可以等待信号量、消息、事件标志组的的函数
参数参数介绍
ulBitsToClearOnEntry在没有收到任务通知的情况下将任务通知值清空 0x00=不清空 ULONG_MAX=0xffffffff 表示清空
ulBitsToClearOnExit收到任务通知之后处理完是否将任务通知值清空 0x00=不清空 ULONG_MAX=0xffffffff 表示清空
*pulNotificationValue接收到的任务通知值存到这个指针变量里面
xTicksToWait阻塞时间,如果没有收到任务通知需要的阻塞时间
	BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait )
	{
	BaseType_t xReturn;

		taskENTER_CRITICAL();
		{
			/* Only block if a notification is not already pending. 任务状态不是接收态 */
			if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )
			{
				
				/* Clear bits in the task's notification value as bits may get
				set	by the notifying task or interrupt.  This can be used to
				clear the value to zero. 在等待任务通知之前将任务通知值清空*/
				pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry;

				/* Mark this task as waiting for a notification.任务状态变成等待态 */
				pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;

				if( xTicksToWait > ( TickType_t ) 0 ) //阻塞时间不为0
				{
prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE ); //将任务从就绪列表中移出,加入延时列表或者阻塞列表 
					/* 任务切换 */
					portYIELD_WITHIN_API();
				}
				else
				{
					mtCOVERAGE_TEST_MARKER();
				}
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		taskEXIT_CRITICAL();
		
		 /*1.任务状态不是接收到任务通知 但是等待任务通知的时间为0,任务没有进行任务阻塞 
		   2. 之前任务处于阻塞态,但是现在接受到任务通知,解除了任务阻塞运行到这里*/
		
		
		taskENTER_CRITICAL();
		{
			traceTASK_NOTIFY_WAIT();

			if( pulNotificationValue != NULL )  //指针指向不为空
			{
				/* Output the current notification value, which may or may not
				have changed. 将当前任务通知值给*pulNotificationValue*/
				*pulNotificationValue = pxCurrentTCB->ulNotifiedValue;
			}
			  /* 1. 任务等待通知没有设置阻塞时间
			     2. 任务等待通知设置了阻塞时间,但是阻塞时间到了还是没有接收到任务通知
			     上述两种情况 任务通知的状态都是等待态*/
			if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION )
			{
				/* A notification was not received. 没有接收到任务通知,返回接收失败*/
				xReturn = pdFALSE;
			}
			else  //任务接收到了任务通知
			{
				/*在退出函数之前将任务通知值清空,并返回接收成功 */
				pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit;
				xReturn = pdTRUE;
			}
            //指针任务状态变成初始态
			pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
		}
		taskEXIT_CRITICAL();

		return xReturn;
	}

函数总结:

1.如果没有接收到任务通知,即任务通知状态不是接收态,则如需要任务阻塞就要将任务添加到延时列表或者挂起列表即阻塞列表然后任务切换
2. 进入到函数下半部分 可能是3种情况 case1:接收到任务通知 case2:是阻塞时间到了还没有接收到任务通知 case3:任务没有收到任务通知但是又没有任务阻塞
不同情况的处理 case1 pulNotificationValue这个指针保存了任务通知值,任务通知状态变成初始态 并返回任务通知接收成功 pdTRUE
case2 pulNotificationValue这个指针值为0 任务通知状态变成初始态 并返回任务通知接收失败 pdFALSE
case3 与case2 一样的结果

例子

#include "main.h"	
#include "string.h"
#include "delay.h"
#include "usart.h"

/*系统时钟配置在system_stm32f4xx.c 文件中的 SystemInit() 函数中实现,复位后直接在启动文件中运行*/
//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);

//任务优先级
#define SEND_NOTIFY_TASK_PRIO		2
//任务堆栈大小	
#define SEND_NOTIFY_STK_SIZE 		120  
//任务句柄
TaskHandle_t Send_Notify_Task_Handler;
//任务函数
void Send_Notify_task(void *pvParameters);


//任务优先级
#define NOTIFY_PROCESS_BINARYSEM_TASK_PRIO		3
//任务堆栈大小	
#define NOTIFY_PROCESS_BINARYSEM_STK_SIZE 		80  
//任务句柄
TaskHandle_t Notify_BinarySem_Task_Handler;
//任务函数
void Notify_BinarySem_task(void *pvParameters);

//任务优先级
#define NOTIFY_PROCESS_COUNTSEM_TASK_PRIO		4
//任务堆栈大小	
#define NOTIFY_PROCESS_COUNTSEM_STK_SIZE 		80  
//任务句柄
TaskHandle_t Notify_CountSem_Task_Handler;
//任务函数
void Notify_CountSem_task(void *pvParameters);

//任务优先级
#define NOTIFY_PROCESS_MESSAGEQUEUE_TASK_PRIO		5
//任务堆栈大小	
#define NOTIFY_PROCESS_MESSAGEQUEUE_STK_SIZE 		80  
//任务句柄
TaskHandle_t Notify_MessageQueue_Task_Handler;
//任务函数
void Notify_MessageQueue_task(void *pvParameters);

//任务优先级
#define NOTIFY_PROCESS_USARTREC_TASK_PRIO		6
//任务堆栈大小	
#define NOTIFY_PROCESS_USARTREC_STK_SIZE 		80  
//任务句柄
TaskHandle_t Notify_UsartReceive_Task_Handler;
//任务函数
void Notify_UsartReceive_task(void *pvParameters);

//任务优先级
#define NOTIFY_PROCESS_EVENTGROUP_TASK_PRIO		7
//任务堆栈大小	
#define NOTIFY_PROCESS_EVENTGROUP_STK_SIZE 		80  
//任务句柄
TaskHandle_t Notify_EventGroup_Task_Handler;
//任务函数
void Notify_EventGroup_task(void *pvParameters);


typedef void (*function)(void);
void CallBack_Message(void)
{
   static u8 num;
   num++;
   printf("num=%d\n",num);
}


#define SETBIT0  (1<<0)
#define SETBIT1  (1<<1)
#define SETBIT2  (1<<2)

/* 任务通知的使用
   1. 为了任务之间的同步,或者中断与任务之间的同步
   2. 一个任务与多个任务进行同步 即多个任务的完成(就是标志组值置一在一个任务的完成),才会出触发一个新的任务运行
*/

#define NOTIFY_SEMAPHORE_TEST    0
#define NOTIFY_MESSAGEQUEUE_TEST 0
#define NOTIFY_EVENTGROUP_TEST   1


int main(void)
{
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
	delay_init(168);		//初始化延时函数
	uart_init(9600);     	//初始化串口	
	RS485Init(115200);
    Key_Configuration();
	LED_GPIO_Config();
	
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄              
    vTaskStartScheduler();          //开启任务调度
}

//开始任务任务函数
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
	
	
    //创建处理二值信号量接收任务
    xTaskCreate((TaskFunction_t )Notify_BinarySem_task,     	
                (const char*    )"Notify_BinarySem_task",   	
                (uint16_t       )NOTIFY_PROCESS_BINARYSEM_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )NOTIFY_PROCESS_BINARYSEM_TASK_PRIO,	
                (TaskHandle_t*  )&Notify_BinarySem_Task_Handler);  
				
    //创建处理计数型信号量接收任务
    xTaskCreate((TaskFunction_t )Notify_CountSem_task,     	
                (const char*    )"Notify_CountSem_task",   	
                (uint16_t       )NOTIFY_PROCESS_COUNTSEM_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )NOTIFY_PROCESS_COUNTSEM_TASK_PRIO,	
                (TaskHandle_t*  )&Notify_CountSem_Task_Handler);  				
				
    //创建处理消息队列接收任务
    xTaskCreate((TaskFunction_t )Notify_MessageQueue_task,     	
                (const char*    )"Notify_MessageQueue_task",   	
                (uint16_t       )NOTIFY_PROCESS_MESSAGEQUEUE_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )NOTIFY_PROCESS_MESSAGEQUEUE_TASK_PRIO,	
                (TaskHandle_t*  )&Notify_MessageQueue_Task_Handler);
	
    //创建处理消息队列串口接收任务
    xTaskCreate((TaskFunction_t )Notify_UsartReceive_task,     	
                (const char*    )"Notify_UsartReceive_task",   	
                (uint16_t       )NOTIFY_PROCESS_USARTREC_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )NOTIFY_PROCESS_USARTREC_TASK_PRIO,	
                (TaskHandle_t*  )&Notify_UsartReceive_Task_Handler);
	
    //创建处理事件标志组任务
    xTaskCreate((TaskFunction_t )Notify_EventGroup_task,     	
                (const char*    )"Notify_EventGroup_task",   	
                (uint16_t       )NOTIFY_PROCESS_EVENTGROUP_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )NOTIFY_PROCESS_EVENTGROUP_TASK_PRIO,	
                (TaskHandle_t*  )&Notify_EventGroup_Task_Handler);
				
				
    //创建发送任务通知任务
    xTaskCreate((TaskFunction_t )Send_Notify_task,     	
                (const char*    )"Send_Notify_task",   	
                (uint16_t       )SEND_NOTIFY_STK_SIZE, 
                (void*          )NULL,				
                (UBaseType_t    )SEND_NOTIFY_TASK_PRIO,	
                (TaskHandle_t*  )&Send_Notify_Task_Handler);  
		
	
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

//LED0任务函数 
void Send_Notify_task(void *pvParameters)
{
    UBaseType_t stack_space;
	u8 key;
	function MessageQueue_Callback;
    MessageQueue_Callback=CallBack_Message;	
    while(1)
    {
	  key=KEY_Scan(0);

#if NOTIFY_SEMAPHORE_TEST	
		switch(key)
		{
			case 1:      				
		    xTaskNotifyGive(Notify_BinarySem_Task_Handler);  //向Notify_BinarySem_Task_Handler 这个任务发送信号量
			break;
			case 2: 
		    xTaskNotifyGive(Notify_CountSem_Task_Handler);   //向Notify_CountSem_Task_Handler 这个任务发送信号量
			break;			
		}		
#endif
		
#if NOTIFY_MESSAGEQUEUE_TEST		
		switch(key)
		{
			case 1: 
		    xTaskNotify(Notify_MessageQueue_Task_Handler,key,eSetValueWithOverwrite);  //向 Notify_MessageQueue_Task_Handler 这个任务发送消息值
			break;
			case 2: 
		    xTaskNotify(Notify_MessageQueue_Task_Handler,key,eSetValueWithOverwrite);   //向 Notify_MessageQueue_Task_Handler 这个任务发送消息值
			break;
			case 3: 
		    xTaskNotify(Notify_MessageQueue_Task_Handler,(uint32_t)MessageQueue_Callback,eSetValueWithOverwrite);   //向 Notify_MessageQueue_Task_Handler 这个任务发送函数指针的地址
			break;				
		}
		
#endif		

#if NOTIFY_EVENTGROUP_TEST		
		switch(key)
		{
			case 1: 
		    xTaskNotify(Notify_EventGroup_Task_Handler,SETBIT0,eSetBits);  //向 Notify_EventGroup_Task_Handler 这个任务发送标志组置位值
			break;
			case 2: 
		    xTaskNotify(Notify_EventGroup_Task_Handler,SETBIT1,eSetBits);   //向 Notify_EventGroup_Task_Handler 这个任务发送标志组置位值	
			break;
			case 3: 
		    xTaskNotify(Notify_EventGroup_Task_Handler,SETBIT2,eSetBits);   //向 Notify_EventGroup_Task_Handler 这个任务发送标志组置位值			
			break;				
		}
		
#endif			
		
		
//	stack_space=uxTaskGetStackHighWaterMark(Send_Notify_Task_Handler);
//	printf("stack_space=%d \r\n",(int)stack_space);
	vTaskDelay(10);
    }
}   
//创建处理二值信号量接收任务
void Notify_BinarySem_task(void *pvParameters)
{
	UBaseType_t stack_space;
	uint32_t Sem_Value;
   while(1)
   {
       Sem_Value= ulTaskNotifyTake(pdTRUE,portMAX_DELAY);  /* 这是一个专门等待信号量的的函数 */
	   //注意这里的返回值是 二值信号量清0之前的值
		printf("Sem_Value=%d \r\n",Sem_Value-1);
//	stack_space=uxTaskGetStackHighWaterMark(Notify_BinarySem_Task_Handler);
//	printf("stack_space=%d \r\n",(int)stack_space);
		vTaskDelay(100);
   }

}

void Notify_CountSem_task(void *pvParameters)
{
	UBaseType_t stack_space;
	uint32_t CountSem_Value;
   while(1)
   {
		CountSem_Value= ulTaskNotifyTake(pdFALSE,portMAX_DELAY);
		//注意这里的返回值是 计数型信号量减一之前的值
		printf("CountSem_Value=%d \r\n",CountSem_Value-1);
//		stack_space=uxTaskGetStackHighWaterMark(Notify_CountSem_Task_Handler);
//		printf("stack_space=%d \r\n",(int)stack_space);
		vTaskDelay(1000);
   }

}

void Notify_MessageQueue_task(void *pvParameters)
{

  UBaseType_t stack_space;
  uint32_t NotificationValue;
  function MessageQueue_Callback;	
   while(1)
   {
		xTaskNotifyWait(ULONG_MAX,ULONG_MAX,&NotificationValue,portMAX_DELAY);//等待信号量 消息 事件标志位

		if(NotificationValue>0xffff)
		{
			//		printf("CallBack_Message=%d \r\n",CallBack_Message);
			printf("NotificationValue=%d \r\n",NotificationValue);
			MessageQueue_Callback=(void *)NotificationValue;
			MessageQueue_Callback();
		}
		else
		printf("NotificationValue=%d \r\n",NotificationValue);   
		//		stack_space=uxTaskGetStackHighWaterMark(Notify_MessageQueue_Task_Handler);
		//		printf("stack_space=%d \r\n",(int)stack_space);
		vTaskDelay(100);
   }

}

void Notify_UsartReceive_task(void *pvParameters)
{
  UBaseType_t stack_space;
  uint32_t NotificationValue;
  u8 *array;
   while(1)
   {
		xTaskNotifyWait(ULONG_MAX,ULONG_MAX,&NotificationValue,portMAX_DELAY);
		printf("NotificationValue=%d \r\n",NotificationValue);
		array=(u8 *)NotificationValue;
		printf("array=%s\n",array);  

//		stack_space=uxTaskGetStackHighWaterMark(Notify_UsartReceive_Task_Handler);
//		printf("stack_space=%d \r\n",(int)stack_space);
		vTaskDelay(100);
   }

}

void Notify_EventGroup_task(void *pvParameters)
{
  uint32_t NotificationValue;
  static u8 EventValue=0;
  static u8 EventBaseValue=SETBIT0|SETBIT1|SETBIT2;
   while(1)
   {
	xTaskNotifyWait(ULONG_MAX,ULONG_MAX,&NotificationValue,portMAX_DELAY);
	printf("NotificationValue=%d \r\n",NotificationValue);
	   
    if(NotificationValue&SETBIT0)	   
    EventValue |= NotificationValue;
    else if(NotificationValue&SETBIT1)	   
    EventValue |= NotificationValue;	
    else if(NotificationValue&SETBIT2)	   
    EventValue |= NotificationValue;	
	printf("EventValue=%d \r\n",EventValue); 	
	
	if( EventValue==EventBaseValue )
    {
    EventValue=0;		
	printf("Notify_EventGroup_task 事件标志组与操作\n");
	}
	vTaskDelay(100);
   }



  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值