FreeRTOS:任务状态和信息查询

news2024/11/25 15:35:43

目录

  • 一、任务相关 API函数预览
  • 二、任务相关API函数详解
    • 2.1uxTaskPriorityGet()
    • 2.2vTaskPrioritySet()
    • 2.3uxTaskGetSystemState() ※※※※※
    • 2.4vTaskGetInfo() ※※※※※
    • 2.5xTaskGetApplicationTaskTag()
    • 2.6xTaskGetCurrentTaskHandle()
    • 2.7xTaskGetHandle()
    • 2.8xTaskGetIdleTaskHandle()
    • 2.9uxTaskGetStackHighWaterMark()
    • 2.10eTaskGetState()
    • 2.11pcTaskGetName()
    • 2.12xTaskGetTickCount()
    • 2.13xTaskGetTickCountFromISR()
    • 2.14xTaskGetSchedulerState()
    • 2.15uxTaskGetNumberOfTask()
    • 2.16vTaskList()※※※※※
    • 2.17vTaskGetRunTimeStats()
    • 2.18vTaskSetApplicationTaskTag()
    • 2.19vTaskSetThreadLocalStoragePointer()
    • 2.20pvTaskGetThreadLocalStoragePointer()
  • 三、函数应用
    • 3.1任务壮态查询 API函数实验
      • 3.1.1实验要求
      • 3.1.2程序代码
    • 3.2任务运行时间信息统计实验
      • 3.2.1实验要求
      • 3.2.2程序代码

一、任务相关 API函数预览

FreeRTOS中提供了很多函数可以用来获取相应的任务信息,FreeRTOS中的任务信息查询函数列举如下:
在这里插入图片描述
这些 API函数在 FreeRTOS官网上都有,如图所示:
在这里插入图片描述

二、任务相关API函数详解

2.1uxTaskPriorityGet()

查询某个任务的优先级

/*****************************相关宏的配置*****************************/
#define INCLUDE_uxTaskPriorityGet 			 必须置为1
/*******************************函数原型*******************************/
函数原型:UBaseType_t uxTaskPriorityGet(TaskHandle_t xTask)
传 入 值:xTask 要查找的任务的任务句柄
返 回 值:获取到的对应的任务的优先级

2.2vTaskPrioritySet()

改变某个任务的优先级

/*****************************相关宏的配置*****************************/
#define INCLUDE_vTaskPrioritySet 			 必须置为1
/*******************************函数原型*******************************/
函数原型:void vTaskPrioritySet(TaskHandle_t xTask,UBaseType_t uxNewPriority)
传 入 值:xTask 要更改优先级的任务的任务句柄
		 uxNewPriority 任务要使用的新的优先级

2.3uxTaskGetSystemState() ※※※※※

获取系统中所有任务的任务状态,每个任务的状态信息保存在一个TaskStatus_t类型的结构体里,这个结构体包含了任务句柄、任务名称、堆栈、优先级等信息

/*****************************相关宏的配置*****************************/
#define configUSE_TRACE_FACILITY 			 必须置为1
/*******************************函数原型*******************************/
函数原型:UBaseType_t uxTaskGetSystemState(TaskStatus_t *const pxTaskStatusArray,
										  const UBaseType_t uxArraySize,
										  uint32_t *const pulTotalRunTime)
传 入 值:pxTaskStatusArray 指向TaskStatus_t结构体类型的数组首地址
		 uxArraySize 	   保存任务状态数组的大小
		 pulTotalRunTime   若开启了系统运行时间统计,则用来保存系统总的运行时间
返 回 值:统计到的任务状态的个数,也就是填写到数组pxTaskStatusArray中的个数
/*****TaskStatus_t结构体*****/
typedef struct xTASK_STATUS{
	TaskHandle_t	xHandle;	//任务句柄
	const char*		pcTaskName;	//任务名字
	UBaseType_t		xTaskNumber;	//任务编号
	eTaskState		eCurrentState;	//当前任务状态
	UBaseType_t		uxCurrentPriority;	//任务当前的优先级
	UBaseType_t		uxBasePriority;		//任务基础优先级
	uint32_t		ulRunTimeCounter;	//任务运行的总时间
	StackType_t*	pxStackBase;	//堆栈基地址
	uint16_t		usStackHighWaterMark;//任务创建依赖任务堆栈剩余的最小值
}TaskStatus_t;

下面简要分析一下该函数的源码

UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray, const UBaseType_t uxArraySize, uint32_t * const pulTotalRunTime )
	{
	UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES;

		vTaskSuspendAll();-----(1)
		{
			/* Is there a space in the array for each task in the system? */
			if( uxArraySize >= uxCurrentNumberOfTasks )-----(2)
			{
				/* Fill in an TaskStatus_t structure with information on each
				task in the Ready state. */
				do-----(3)
				{
					uxQueue--;
					uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &( pxReadyTasksLists[ uxQueue ] ), eReady );

				} while( uxQueue > ( UBaseType_t ) tskIDLE_PRIORITY ); /*lint !e961 MISRA exception as the casts are only redundant for some ports. */

				/* Fill in an TaskStatus_t structure with information on each
				task in the Blocked state. */
				uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxDelayedTaskList, eBlocked );-----(4)
				uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), ( List_t * ) pxOverflowDelayedTaskList, eBlocked );-----(5)

				#if( INCLUDE_vTaskDelete == 1 )-----(6)
				{
					/* Fill in an TaskStatus_t structure with information on
					each task that has been deleted but not yet cleaned up. */
					uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xTasksWaitingTermination, eDeleted );
				}
				#endif

				#if ( INCLUDE_vTaskSuspend == 1 )-----(7)
				{
					/* Fill in an TaskStatus_t structure with information on
					each task in the Suspended state. */
					uxTask += prvListTasksWithinSingleList( &( pxTaskStatusArray[ uxTask ] ), &xSuspendedTaskList, eSuspended );
				}
				#endif

				#if ( configGENERATE_RUN_TIME_STATS == 1)-----(8)
				{
					if( pulTotalRunTime != NULL )
					{
						#ifdef portALT_GET_RUN_TIME_COUNTER_VALUE
							portALT_GET_RUN_TIME_COUNTER_VALUE( ( *pulTotalRunTime ) );
						#else
							*pulTotalRunTime = portGET_RUN_TIME_COUNTER_VALUE();
						#endif
					}
				}
				#else
				{
					if( pulTotalRunTime != NULL )
					{
						*pulTotalRunTime = 0;
					}
				}
				#endif
			}
			else
			{
				mtCOVERAGE_TEST_MARKER();
			}
		}
		( void ) xTaskResumeAll();-----(9)

		return uxTask;
	}


(1)、挂起任务调度器,停止任务调度,以免任务打断,或任务状态信息改变。
(2)、判断定义的结构体数组大小是否比当前系统所有任务数量,即判断是否能够存储得下系统中所有任务的信息。
(3)、获取处于准备态任务的信息。uxQueue表示任务的优先级,按照高优先级到低优先级的顺序来获取任务信息。prvListTasksWithinSingleList()函数是用来获取单个任务的信息,在该任务中调用了vTaskGetInfo()函数,该函数返回值为同一优先级同一状态的任务数量。uxTask用以统计获得信息的任务个数。
(4)、获取处于阻塞态延时列表中任务的信息。
(5)、获取处于阻塞态延时溢出列表中任务信息,因为任务阻塞时可能会产生溢出,所以用这两个列表共同表示阻塞态任务。
(6)、获取未完全删除的任务信息。
(7)、获取处于挂起态任务的信息。
(8)、获取任务运行时间。本章节没有用到该信息
(9)、调度器解挂。

函数用法示例:

   TaskStatus_t* StatusArray;
	UBaseType_t ArraySize ;
	ArraySize = uxTaskGetNumberOfTasks();
	StatusArray = pvPortMalloc(ArraySize * sizeof(TaskStatus_t));//动态申请空间
	
	printf("------------Get System State------------\r\n");
	if (StatusArray != NULL)
	{
		ArraySize = uxTaskGetSystemState(StatusArray, ArraySize, &pulTotalRunTime);
		//printf("TaskName\t\tPriority\tTaskNumber\truntime\r\n");
		for (i=0; i<ArraySize; i++)
		{
			
		  printf("%d\t%s\t%#x\t%d\t%ld\t%ld\t%#x\t%ld\t\r\n",
			       StatusArray[i].eCurrentState,
						 StatusArray[i].pcTaskName,
						 StatusArray[i].pxStackBase,
						 StatusArray[i].usStackHighWaterMark,
			       StatusArray[i].uxBasePriority,
						 StatusArray[i].uxCurrentPriority,
			       StatusArray[i].xHandle,
			       StatusArray[i].xTaskNumber
			  );
		}			
	}	

2.4vTaskGetInfo() ※※※※※

获取某个指定的单个任务的任务信息

/*****************************相关宏的配置*****************************/
#define configUSE_TRACE_FACILITY 			 必须置为1
/*******************************函数原型*******************************/
函数原型:void vTaskGetInfo(TaskHandle_t	xTask,
						   TaskStatus_t* pxTaskStatus,
						   BaseType_t xGetFreeStackSpace,
						   eTaskState eState)
传 入 值:xTask 要查找的任务的任务句柄
		 pxTaskStatus 指向类型为TaskStatus_t结构体变量
		 xGetFreeStackSpace 堆栈剩余的历史最小值
		 eState 保存任务运行状态 

函数输入参数有四个,TaskHandle_t xTask为所要查询任务的任务句柄;TaskStatus_t *pxTaskStatus为任务状态结构体,用于存放任务的状态,该结构体需要用户自定义;BaseType_t xGetFreeStackSpace为是否计算任务剩余最小堆栈大小,传入参数pdTRUE表示计算,但需要耗费一些时间;eTaskState eState为是否获取任务状态,输入参数eInvalid时表示获取任务状态,但同样也会消耗一些时间,否则用户指定任务状态,不会消耗时间。下面深入分析一下该函数源码:

	void vTaskGetInfo( TaskHandle_t xTask, TaskStatus_t *pxTaskStatus, BaseType_t xGetFreeStackSpace, eTaskState eState )
	{
	TCB_t *pxTCB;

		/* xTask is NULL then get the state of the calling task. */
		pxTCB = prvGetTCBFromHandle( xTask );------(1)

		pxTaskStatus->xHandle = ( TaskHandle_t ) pxTCB;------(2)
		pxTaskStatus->pcTaskName = ( const char * ) &( pxTCB->pcTaskName [ 0 ] );------(3)
		pxTaskStatus->uxCurrentPriority = pxTCB->uxPriority;------(4)
		pxTaskStatus->pxStackBase = pxTCB->pxStack;------(5)
		pxTaskStatus->xTaskNumber = pxTCB->uxTCBNumber;------(6)

		#if ( INCLUDE_vTaskSuspend == 1 ) ------(7)
		{
			/* If the task is in the suspended list then there is a chance it is
			actually just blocked indefinitely - so really it should be reported as
			being in the Blocked state. */
			if( pxTaskStatus->eCurrentState == eSuspended )
			{
				vTaskSuspendAll();
				{
					if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
					{
						pxTaskStatus->eCurrentState = eBlocked;
					}
				}
				xTaskResumeAll();
			}
		}
		#endif /* INCLUDE_vTaskSuspend */

		#if ( configUSE_MUTEXES == 1 ) ------(8)
		{
			pxTaskStatus->uxBasePriority = pxTCB->uxBasePriority;
		}
		#else
		{
			pxTaskStatus->uxBasePriority = 0;
		}
		#endif

		#if ( configGENERATE_RUN_TIME_STATS == 1 ) ------(9)
		{
			pxTaskStatus->ulRunTimeCounter = pxTCB->ulRunTimeCounter;
		}
		#else
		{
			pxTaskStatus->ulRunTimeCounter = 0;
		}
		#endif

		/* Obtaining the task state is a little fiddly, so is only done if the value
		of eState passed into this function is eInvalid - otherwise the state is
		just set to whatever is passed in. */
		if( eState != eInvalid )  ------(10)
		{
			pxTaskStatus->eCurrentState = eState;
		}
		else
		{
			pxTaskStatus->eCurrentState = eTaskGetState( xTask );
		}

		/* Obtaining the stack space takes some time, so the xGetFreeStackSpace
		parameter is provided to allow it to be skipped. */
		if( xGetFreeStackSpace != pdFALSE ) ------(11)
		{
			#if ( portSTACK_GROWTH > 0 )
			{
				pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxEndOfStack );
			}
			#else
			{
				pxTaskStatus->usStackHighWaterMark = prvTaskCheckFreeStackSpace( ( uint8_t * ) pxTCB->pxStack );
			}
			#endif
		}
		else
		{
			pxTaskStatus->usStackHighWaterMark = 0;
		}
	}

(1)、获取该任务的任务句柄
(2)、获取任务句柄,存放在任务状态结构体中
(3)、获取任务名的首地址,存放在任务状态结构体中
(4)、获取当前任务优先级,存放在任务状态结构体中
(5)、获取任务堆栈首地址,存放在任务状态结构体中
(6)、获取任务标号,存放在任务状态结构体中
(7)、这段宏定义完成的任务就是,如果任务处于挂起状态,那么有可能它是被无限期阻塞所导致的,所以此时判断是否是这种可能,如果是则将它的状态反馈为阻塞态,而非挂起态。
(8)、这段条件编译是判断用户是否使用了互斥量,因为当用户使用了互斥量时,互斥信号量有可能会导致低优先级的任务优先级会拉高,这点在以后会讲述。所以这里如果使用了互斥量,那么就会获取其最初始的优先级大小,然后存放在任务状态结构体中
(9)、这段条件编译如果用户配置了任务事件信息统计,则会获取当前任务的运行时间。当配置configGENERATE_RUN_TIME_STATS == 1时需要用户自己再定义两个函数,具体配置会在后面的一个章节中讲述,这里只需要知道vTaskGetInfo()函数是可以获取任务运行时间的,不过本章没有用到。
(10)、判断用户传入的状态参数是否是无效的,如果是则获取当前任务状态但会耗费一些时间,否则将用户传入的状态参数作为当前任务状态。
(11)、是否获取任务历史最小剩余堆栈,如果传入参数pdTRUE,则会获取任务历史最小剩余堆栈同样会耗费一些时间,否则不获取。

总结一下vTaskGetInfo()函数可以获取的任务信息有:
1.任务句柄 xHandle
2.任务名 pcTaskName
3.任务当前优先级 uxCurrentPriority
4.任务堆栈基地址 pxStackBase
5.任务编号 xTaskNumber
6.当前任务状态 eCurrentState
7.任务初始优先级 uxBasePriority
8.任务运行时间 ulRunTimeCounter
9.任务历史剩余堆栈最小值 usStackHighWaterMark

函数用法示例:

	TaskStatus_t  TaskStatus;
	
	vTaskGetInfo(QueryTask_Handler,&TaskStatus,pdTRUE,eInvalid);
	
	printf("------------Get Task Info------------\r\n");
	printf("eCurrentState = %d\r\n",TaskStatus.eCurrentState);
	printf("pcTaskName = %s\r\n",TaskStatus.pcTaskName);
	printf("pxStackBase = %#x\r\n",(int)TaskStatus.pxStackBase);
	printf("usStackHighWaterMark = %d\r\n",TaskStatus.usStackHighWaterMark);
	printf("uxBasePriority = %ld\r\n",TaskStatus.uxBasePriority);
	printf("uxCurrentPriority = %ld\r\n",TaskStatus.uxCurrentPriority);
	printf("xTaskNumber = %ld\r\n",TaskStatus.xTaskNumber);
	printf("xHandle = %#x\r\n",(void *)TaskStatus.xHandle);
	printf("QueryTask_Handler= %#x\r\n",(void *)QueryTask_Handler);
	printf("------------Get Task Info------------\r\n");

2.5xTaskGetApplicationTaskTag()

获取某个任务的标签值
标签值的功能由用户自行决定, 此函数就是来获取这个标签值的。
要使用此函数话宏 configUSE_APPLICATION_TASK_TAG必须为1

/*****************************相关宏的配置*****************************/
#define configUSE_APPLICATION_TASK_TAG	 必须置为1
/*******************************函数原型*******************************/
函数原型:void xTaskGetApplicationTaskTag(TaskHandle_t xTask)
传 入 值:xTask 要获取标签值的任务的任务句柄,若为NULL表示获取当前任务的标签值
返 回 值:任务的标签值

2.6xTaskGetCurrentTaskHandle()

获取当前正在运行任务的任务句柄,其实获取到的就是任务控制块

/*****************************相关宏的配置*****************************/
#define INCLUDE_xTaskGetCurrentTaskHandle	必须置为1
/*******************************函数原型*******************************/
函数原型:TaskHandle_t xTaskGetCurrentTaskHandle(void)
返 回 值:当前任务的任务句柄

2.7xTaskGetHandle()

根据任务名字查找某个任务的句柄

/*****************************相关宏的配置*****************************/
#define INCLUDE_xTaskGetHandle	必须置为1
/*******************************函数原型*******************************/
函数原型:TaskHandle_t xTaskGetHandle(const char* pcNameToQuery)
传 入 值:pcNameToQuery 任务名
返 回 值:任务名所对应的任务句柄;返回NULL表示没有对应的任务

2.8xTaskGetIdleTaskHandle()

获取空闲任务的句柄

/*****************************相关宏的配置*****************************/
#define INCLUDE_xTaskGetIdleTaskHandle	必须置为1
/*******************************函数原型*******************************/
函数原型:TaskHandle_t xTaskGetIdleTaskHandle(void)
返 回 值:空闲任务的任务句柄

2.9uxTaskGetStackHighWaterMark()

每个任务在创建的时候就确定了堆栈大小,此函数用于检查任务从创建好到现在的历史剩余最小值,这个值越小说明任务堆栈溢出的可能性就越大

/*****************************相关宏的配置*****************************/
#define INCLUDE_uxTaskGetStackHighWaterMark	必须置为1
/*******************************函数原型*******************************/
函数原型:UBaseType_t uxTaskGetStackHighWaterMark(TaskHandle_t xTask)
传 入 值:xTask 要查询的任务的任务句柄,若为NULL表示查询自身任务的高水位线
返 回 值:任务堆栈的高水位线值,即堆栈的历史剩余最小值

2.10eTaskGetState()

获取某个任务的状态,比如:运行态、阻塞态、挂起态、就绪态等

/*****************************相关宏的配置*****************************/
#define INCLUDE_eTaskGetState	必须置为1
/*******************************函数原型*******************************/
函数原型:eTaskState eTaskGetState(TaskHandle_t xTask)
传 入 值:xTask 要查询的任务的任务句柄
返 回 值:返回eTaskState枚举类型值

2.11pcTaskGetName()

根据任务句柄来获取该任务的任务名字

/*******************************函数原型*******************************/
函数原型:char* pcTaskGetName(TaskHandle_t xTaskToQuery)
传 入 值:xTaskToQuery 要查询的任务的任务句柄,若为NULL表示查询自身任务名
返 回 值:返回任务所对应的任务名

2.12xTaskGetTickCount()

用于查询任务调度器从启动到现在时间计数器xTickCount的值。xTickCount是系统的时钟节拍值,并不是真实的时间值。每个滴答定时器中断xTickCount就会加一,中断周期取决于系统时钟节拍数

/*******************************函数原型*******************************/
函数原型:TickType_t xTaskGetTickCount(void)
返 回 值:时间计数器xTickCount的值

2.13xTaskGetTickCountFromISR()

在中断服务函数中获取时间计数器值

/*******************************函数原型*******************************/
函数原型:TickType_t xTaskGetTickCountFromISR(void)
返 回 值:时间计数器xTickCount的值

2.14xTaskGetSchedulerState()

获取任务调度器的状态,开启、关闭还是挂起

/*****************************相关宏的配置*****************************/
#define INCLUDE_xTaskGetSchedulerState	必须置为1
/*******************************函数原型*******************************/
函数原型:BaseType_t xTaskGetSchedulerState(void)
返 回 值:taskCHEDULER_NOT_STARTED 调度器未启动
		 taskCHEDULER_RUNNING 调度器正在运行
		 taskCHEDULER_SUSPENDED 调度器挂起

2.15uxTaskGetNumberOfTask()

获取当前系统中存在的任务数量

/*******************************函数原型*******************************/
函数原型:UBaseType_t uxTaskGetNumberOfTask(void)
返 回 值:当前系统中存在的任务数量,此值包含各种状态下的任务数

2.16vTaskList()※※※※※

很多时候,我们并不需要这么多信息,我们只需要几个常用的关键信息即可。所以FreeRTOS为我们提供了vTaskList(),该函数不仅可以获取关键信息,而且用法简单,以表格的形式输出当前系统中所有任务的详细信息

/*******************************函数原型*******************************/
函数原型:void vTaskList(char *pcWriteBuffer)
传 入 值:pcWriteBuffer 保存任务状态信息表的存储区

该函数的函数声明很简单,输入形参就一个字符指针。该指针需要用户自定义,用以存放任务信息。函数源码这里就不分析了。我们直接给出其用法示例:

  char InfoBuffer[200];
  vTaskList(InfoBuffer);
  printf("taskName\ttaskState\ttaskPrio\ttaskStack\ttaskNum\r\n");
  printf("%s",InfoBuffer);

下图是其输出信息
在这里插入图片描述
从上图可以看出,该函数可以获取任务状态,优先级,剩余堆栈大小,任务序号这四项信息。

2.17vTaskGetRunTimeStats()

获取每个任务的运行时间

/*****************************相关宏的配置*****************************/
#define configGENERATE_RUN_TIME_STATS 			 必须置为1
#define configUSE_STATS_FORMATTING_FUNCTIONS	 必须置为1
/*******************************函数原型*******************************/
函数原型:void vTaskGetRunTimeStats(char *pcWriteBuffer)
传 入 值:pcWriteBuffer 保存任务时间信息的存储区

2.18vTaskSetApplicationTaskTag()

用于设置某个任务的标签值

/*****************************相关宏的配置*****************************/
#define configUSE_APPLICATION_TASK_TAG	 必须置为1
/*******************************函数原型*******************************/
函数原型:void vTaskSetApplicationTaskTag(TaskHandle_t xTask,
								   TaskHookFunction_t pxHookFunction)
传 入 值:xTask 要要设置标签值的任务的任务句柄
		 pxHookFunction 要设置的标签值

2.19vTaskSetThreadLocalStoragePointer()

设置线程本地存储指针的值,每个任务都有自已的指针数组作为线程本地存储,使用这些线程本地存储可以用来在任务控制块中存储一些只属于任务自已的应用信息

/*****************************相关宏的配置*****************************/
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS	 本地存储指针数组的大小
/*******************************函数原型*******************************/
函数原型:void vTaskSetThreadLocalStoragePointer(TaskHandle_t xTaskToSet,
												BaseType_t xIndex,
												void* pvValue)
传 入 值:xTaskToSet 要设置线程本地存储指针的任务的任务句柄
		 xIndex 要设置的线程本地存储指针数组的索引
		 pvValue 要存储的值

2.20pvTaskGetThreadLocalStoragePointer()

获取线程本地存储指针

/*****************************相关宏的配置*****************************/
#define configNUM_THREAD_LOCAL_STORAGE_POINTERS	 本地存储指针数组的大小
/*******************************函数原型*******************************/
函数原型:void *pvTaskGetThreadLocalStoragePointer(TaskHandle_t xTaskToQuery,
                                 				  BaseType_t xIndex )
传 入 值:xTaskToQuery 要获取线程本地存储指针的任务的任务句柄
		 xIndex 要获取的线程本地存储指针数组的索引

三、函数应用

3.1任务壮态查询 API函数实验

3.1.1实验要求

本实验设计三个任务: start_task、led0_task 和 query_task ,这三个任务的功能如下:
start_task:用来创建其他 2个任务。
led0_task :控制LED0灯闪烁,提示系统正在运行 。
query_task :任务壮态和信息查询任务
实验需要一个按键 KEY_UP,这四个按键的功能如下:
KEY_UP: 控制程序的运行步骤 。

3.1.2程序代码

任务优先级、堆栈大小和句柄等的设置如下:

#define START_TASK_PRIO 1 //任务优先级 
#define START_STK_SIZE 128 //任务堆栈大小
TaskHandle_t StartTask_Handler; //任务句柄 
void start_task(void *pvParameters); //任务函数 
#define LED0_TASK_PRIO 2 //任务优先级 
#define LED0_STK_SIZE 128 //任务堆栈大小
TaskHandle_t Led0Task_Handler; //任务句柄 
void led0_task(void *pvParameters); //任务函数 
#define QUERY_TASK_PRIO 3 //任务优先级 
#define QUERY_STK_SIZE 256 //任务堆栈大小
TaskHandle_t QueryTask_Handler; //任务句柄 
void query_task(void *pvParameters); //任务函数 
char InfoBuffer[1000]; //保存信息的数组 保

main()函数

int main(void) 
{ 
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组 4 
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口 
LED_Init(); //初始化 LED
KEY_Init(); //初始化按键 
LCD_Init(); //初始化 LCD 

POINT_COLOR = RED; 
LCD_ShowString(30,10,200,16,16,"ATK STM32F103/407"); 
LCD_ShowString(30,30,200,16,16,"FreeRTOS Examp 11-1"); 
LCD_ShowString(30,50,200,16,16,"Task Info Query"); 
LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK"); 
LCD_ShowString(30,90,200,16,16,"2016/11/25"); 

//创建开始任务
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(); //开启任务调度 开启任务调度 
}

在 main函数中我们主要完成硬件的初始化,在硬件初始化完成后创建了任务 start_task()并且开启了 FreeRTOS的任务调度

开始任务任务函数

void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //进入临界区
    //创建LED0任务
    xTaskCreate((TaskFunction_t )led0_task,             
                (const char*    )"led0_task",           
                (uint16_t       )LED0_STK_SIZE,        
                (void*          )NULL,                  
                (UBaseType_t    )LED0_TASK_PRIO,        
                (TaskHandle_t*  )&Led0Task_Handler);   
    //创建QUERY任务
    xTaskCreate((TaskFunction_t )query_task,     
                (const char*    )"query_task",   
                (uint16_t       )QUERY_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )QUERY_TASK_PRIO,
                (TaskHandle_t*  )&QueryTask_Handler); 
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

任务函数

//led0任务函数
void led0_task(void *pvParameters)
{

	while(1)
	{
		LED0=~LED0;
        vTaskDelay(500);			//延时500ms,也就是500个时钟节拍	
	}
}

//query任务函数
void query_task(void *pvParameters)
{
	u32 TotalRunTime;
	UBaseType_t ArraySize,x;
	TaskStatus_t *StatusArray;
	
	//第一步:函数uxTaskGetSystemState()的使用
	printf("/********第一步:函数uxTaskGetSystemState()的使用**********/\r\n");
	ArraySize=uxTaskGetNumberOfTasks();		//获取系统任务数量
	StatusArray=pvPortMalloc(ArraySize*sizeof(TaskStatus_t));//申请内存
	if(StatusArray!=NULL)					//内存申请成功
	{
		ArraySize=uxTaskGetSystemState((TaskStatus_t* 	)StatusArray, 	//任务信息存储数组
									   (UBaseType_t		)ArraySize, 	//任务信息存储数组大小
								       (uint32_t*		)&TotalRunTime);//保存系统总的运行时间
		printf("TaskName\t\tPriority\t\tTaskNumber\t\t\r\n");
		for(x=0;x<ArraySize;x++)
		{
			//通过串口打印出获取到的系统任务的有关信息,比如任务名称、
			//任务优先级和任务编号。
			printf("%s\t\t%d\t\t\t%d\t\t\t\r\n",				
					StatusArray[x].pcTaskName,
					(int)StatusArray[x].uxCurrentPriority,
					(int)StatusArray[x].xTaskNumber);
			
		}
	}
	vPortFree(StatusArray);	//释放内存
	printf("/**************************结束***************************/\r\n");
	printf("按下KEY_UP键继续!\r\n\r\n\r\n");
	while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);		//等待KEY_UP键按下
	
	//第二步:函数vTaskGetInfo()的使用
	TaskHandle_t TaskHandle;	
	TaskStatus_t TaskStatus;
	
	printf("/************第二步:函数vTaskGetInfo()的使用**************/\r\n");
	TaskHandle=xTaskGetHandle("led0_task");			//根据任务名获取任务句柄。
	//获取LED0_Task的任务信息
	vTaskGetInfo((TaskHandle_t	)TaskHandle, 		//任务句柄
				 (TaskStatus_t*	)&TaskStatus, 		//任务信息结构体
				 (BaseType_t	)pdTRUE,			//允许统计任务堆栈历史最小剩余大小
			     (eTaskState	)eInvalid);			//函数自己获取任务运行壮态
	//通过串口打印出指定任务的有关信息。
	printf("任务名:                %s\r\n",TaskStatus.pcTaskName);
	printf("任务编号:              %d\r\n",(int)TaskStatus.xTaskNumber);
	printf("任务壮态:              %d\r\n",TaskStatus.eCurrentState);
	printf("任务当前优先级:        %d\r\n",(int)TaskStatus.uxCurrentPriority);
	printf("任务基优先级:          %d\r\n",(int)TaskStatus.uxBasePriority);
	printf("任务堆栈基地址:        %#x\r\n",(int)TaskStatus.pxStackBase);
	printf("任务堆栈历史剩余最小值:%d\r\n",TaskStatus.usStackHighWaterMark);
	printf("/**************************结束***************************/\r\n");
	printf("按下KEY_UP键继续!\r\n\r\n\r\n");
	while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);		//等待KEY_UP键按下
	
	//第三步:函数eTaskGetState()的使用	
	eTaskState TaskState;
	char TaskInfo[10];
	printf("/***********第三步:函数eTaskGetState()的使用*************/\r\n");
	TaskHandle=xTaskGetHandle("query_task");		//根据任务名获取任务句柄。
	TaskState=eTaskGetState(TaskHandle);			//获取query_task任务的任务壮态
	memset(TaskInfo,0,10);						
	switch((int)TaskState)
	{
		case 0:
			sprintf(TaskInfo,"Running");
			break;
		case 1:
			sprintf(TaskInfo,"Ready");
			break;
		case 2:
			sprintf(TaskInfo,"Suspend");
			break;
		case 3:
			sprintf(TaskInfo,"Delete");
			break;
		case 4:
			sprintf(TaskInfo,"Invalid");
			break;
	}
	printf("任务壮态值:%d,对应的壮态为:%s\r\n",TaskState,TaskInfo);
	printf("/**************************结束**************************/\r\n");
	printf("按下KEY_UP键继续!\r\n\r\n\r\n");
	while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10);		//等待KEY_UP键按下
	
	//第四步:函数vTaskList()的使用	
	printf("/*************第三步:函数vTaskList()的使用*************/\r\n");
	vTaskList(InfoBuffer);							//获取所有任务的信息
	printf("%s\r\n",InfoBuffer);					//通过串口打印所有任务的信息
	printf("/**************************结束**************************/\r\n");
	while(1)
	{
		LED1=~LED1;
        vTaskDelay(1000);                           //延时1s,也就是1000个时钟节拍	
	}
}

3.2任务运行时间信息统计实验

3.2.1实验要求

本实验设计四 个任务: start_task、task1_task 、task2_task 和 RunTimeStats_task,这四个任 务的任功能如下:
start_task:用来创建其他 3个任务。
task1_task :应用任务 1,控制 LED0灯闪烁,并且刷新 LCD屏幕上指定区域的颜色。
task2_task :应用任务 2,控制LED1灯闪烁,并且刷新 LCD屏幕上指定区域的颜色。
RunTimeStats_task:获取按键值,当 KEY_UP键按下以后就调用函数 vTaskGetRunTimeStats()获取任务的运行时间信息,并且将其通过串口输出到调试助手上。
实验需要一个按键 KEY_UP,用来获取系统中任务运行时间信息。

3.2.2程序代码

任务优先级、堆栈大小和句柄等的设置如下:

//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);

//任务优先级
#define TASK1_TASK_PRIO		2
//任务堆栈大小	
#define TASK1_STK_SIZE 		128  
//任务句柄
TaskHandle_t Task1Task_Handler;
//任务函数
void task1_task(void *pvParameters);

//任务优先级
#define TASK2_TASK_PRIO		3
//任务堆栈大小	
#define TASK2_STK_SIZE 		128  
//任务句柄
TaskHandle_t Task2Task_Handler;
//任务函数
void task2_task(void *pvParameters);

//任务优先级
#define RUNTIMESTATS_TASK_PRIO	4
//任务堆栈大小	
#define RUNTIMESTATS_STK_SIZE 	128  
//任务句柄
TaskHandle_t RunTimeStats_Handler;
//任务函数
void RunTimeStats_task(void *pvParameters);

char RunTimeInfo[400];		//保存任务运行时间信息

main函数

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4	 
	delay_init();	    				//延时函数初始化	 
	uart_init(115200);					//初始化串口
	LED_Init();		  					//初始化LED
	KEY_Init();							//初始化按键
	LCD_Init();							//初始化LCD
	
	POINT_COLOR = RED;
	LCD_ShowString(30,10,200,16,16,"ATK STM32F103/407");	
	LCD_ShowString(30,30,200,16,16,"FreeRTOS Examp 11-2");
	LCD_ShowString(30,50,200,16,16,"Get Run Time Stats");
	LCD_ShowString(30,70,200,16,16,"ATOM@ALIENTEK");
	LCD_ShowString(30,90,200,16,16,"2016/11/25");
	
	//创建开始任务
    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();           //进入临界区
    //创建TASK1任务
    xTaskCreate((TaskFunction_t )task1_task,             
                (const char*    )"task1_task",           
                (uint16_t       )TASK1_STK_SIZE,        
                (void*          )NULL,                  
                (UBaseType_t    )TASK1_TASK_PRIO,        
                (TaskHandle_t*  )&Task1Task_Handler);   
    //创建TASK2任务
    xTaskCreate((TaskFunction_t )task2_task,     
                (const char*    )"task2_task",   
                (uint16_t       )TASK2_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )TASK2_TASK_PRIO,
                (TaskHandle_t*  )&Task2Task_Handler); 
	//创建RunTimeStats任务
	xTaskCreate((TaskFunction_t )RunTimeStats_task,     
                (const char*    )"RunTimeStats_task",   
                (uint16_t       )RUNTIMESTATS_STK_SIZE,
                (void*          )NULL,
                (UBaseType_t    )RUNTIMESTATS_TASK_PRIO,
                (TaskHandle_t*  )&RunTimeStats_Handler); 
    vTaskDelete(StartTask_Handler); //删除开始任务
    taskEXIT_CRITICAL();            //退出临界区
}

任务函数

//task1任务函数
void task1_task(void *pvParameters)
{
	u8 task1_num=0;
	
	POINT_COLOR = BLACK;

	LCD_DrawRectangle(5,110,115,314); 	//画一个矩形	
	LCD_DrawLine(5,130,115,130);		//画线
	POINT_COLOR = BLUE;
	LCD_ShowString(6,111,110,16,16,"Task1 Run:000");
	while(1)
	{
		task1_num++;	//任务执1行次数加1 注意task1_num1加到255的时候会清零!!
		LED0=!LED0;
		LCD_Fill(6,131,114,313,lcd_discolor[task1_num%14]); //填充区域
		LCD_ShowxNum(86,111,task1_num,3,16,0x80);	//显示任务执行次数
        vTaskDelay(1000);                           //延时1s,也就是1000个时钟节拍	
	}
}

//task2任务函数
void task2_task(void *pvParameters)
{
	u8 task2_num=0;
	
	POINT_COLOR = BLACK;

	LCD_DrawRectangle(125,110,234,314); //画一个矩形	
	LCD_DrawLine(125,130,234,130);		//画线
	POINT_COLOR = BLUE;
	LCD_ShowString(126,111,110,16,16,"Task2 Run:000");
	while(1)
	{
		task2_num++;	//任务2执行次数加1 注意task1_num2加到255的时候会清零!!
        LED1=!LED1;
		LCD_ShowxNum(206,111,task2_num,3,16,0x80);  //显示任务执行次数
		LCD_Fill(126,131,233,313,lcd_discolor[13-task2_num%14]); //填充区域
        vTaskDelay(1000);                           //延时1s,也就是1000个时钟节拍	
	}
}

//RunTimeStats任务
void RunTimeStats_task(void *pvParameters)
{
	u8 key=0;
	while(1)
	{
		key=KEY_Scan(0);
		if(key==WKUP_PRES)
		{
			memset(RunTimeInfo,0,400);				//信息缓冲区清零
			vTaskGetRunTimeStats(RunTimeInfo);		//获取任务运行时间信息
			printf("任务名\t\t\t运行时间\t运行所占百分比\r\n");
			printf("%s\r\n",RunTimeInfo);
		}
		vTaskDelay(10);                           	//延时10ms,也就是1000个时钟节拍	
	}
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/529789.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

教你用JMeter做接口测试的几个简单实例

目录 前言 1、登录&#xff08;POST&#xff09; 登录 2、获取学生信息&#xff08;GET&#xff09; 获取学生信息 3、添加学生信息&#xff08;POST&#xff0c;JSON&#xff09; 添加学生信息 4、学生充值金币&#xff08;POST&#xff0c;Cookie&#xff09; 学生金…

【Linux】11. 进程控制

小实验(谨慎测试) 1. 进程退出码的引出 2. 进程码的使用 3. 进程退出 3.1 进程退出情况 进程退出分三种情况&#xff1a; 1.代码运行完毕&#xff0c;结果正确 – return 0; 2.代码运行完毕&#xff0c;结果不正确 – 根据退出码判断错误情况 3.代码没有运行完毕&#xff0c;…

如何0基础自学黑客(网络安全)技术,万字长文教你如何学习黑客(网络安全)

一、自学网络安全学习的误区和陷阱 1.不要试图先成为一名程序员&#xff08;以编程为基础的学习&#xff09;再开始学习 我在之前的回答中&#xff0c;我都一再强调不要以编程为基础再开始学习网络安全&#xff0c;一般来说&#xff0c;学习编程不但学习周期长&#xff0c;而…

【数字化转型-06】数字化转型咨询项目中如何做好高层访谈

咨询项目中少不了至关重要的一步&#xff0c;那就是高层访谈&#xff0c;做好高层访谈&#xff0c;对于咨询项目至关重要&#xff0c;我们接触的维度越高&#xff0c;就会越能把控项目的真实意图&#xff0c;有的放矢&#xff0c;不会让下面的人带偏&#xff1b;另一方面我们也…

Vue3 使用 Ts 泛型 封装本地存储

前期回顾 NVM —— 你把我玩明白_彩色之外的博客-CSDN博客本文将学习 使用 NVM 管理node版本https://blog.csdn.net/m0_57904695/article/details/130670262?spm1001.2014.3001.5501 目录 新建 \src\utils\storage-utils.ts 使用 泛型示例 泛型交换变量 泛型 strin…

在Linux系统中用vim编写第一个C语言之gcc编译器

文章目录 在Linux系统中用vim编写第一个C语言HelloWorld第一步 创建第二步 编写第三步&#xff0c;编译第四步 运行 gcc四步骤gcc常用选项 在Linux系统中用vim编写第一个C语言HelloWorld 第一步 创建 vim HelloWorld.c第二步 编写 #include<stdio.h>int main(){printf(…

Android Jsoup爬取网页数据及其局限性,接口爬取数据的思路

1.Jsoup jsoup 是一款Java 的HTML解析器&#xff0c;可直接解析某个URL地址、HTML文本内容。它提供了一套非常省力的API&#xff0c;可通过DOM&#xff0c;CSS以及类似于jQuery的操作方法来取出和操作数据。 需求是需要获取某个网站上的排行榜数据&#xff0c;用作App展示&am…

【axios】后端未收到前端post传参

今天遇到过问题&#xff0c;前端post请求参数明明已经传过去了&#xff0c;可是后端说没收到&#xff0c;不知道后端大哥是不是故意搞我。 代码前端图如下↓ 代码 import axios from axios //对象形式 const val {pass:123,user:name}axios.post(/api/login, val).then(res>…

Vue3-黑马(十三)

目录&#xff1a; &#xff08;1&#xff09;vue3-router-动态路由3 &#xff08;2&#xff09;vue3-进阶router-动态菜单 &#xff08;3&#xff09;vue3-进阶-router-令牌-获取用户信息 &#xff08;1&#xff09;vue3-router-动态路由3 登录页面后&#xff0c;如果点击了…

Android技术探索与实践:从新功能体验到故障调试的全方位探索

目录 Android技术探索与实践&#xff1a;从新功能体验到故障调试的全方位探索 第一章&#xff1a;技术解析 Android平台的架构和工作原理 应用组件的生命周期和交互方式 Android开发中常用的设计模式和技术框架解析 第二章:产品新功能体验测评 深入了解最新发布的Androi…

【安卓源码】Binder机制5 -- Java层Framework Binder机制和 AIDL

图中红色代表整个framework层 binder架构相关组件&#xff1b; Binder类代表Server端&#xff0c;BinderProxy类代码Client端&#xff1b;图中蓝色代表Native层Binder架构相关组件&#xff1b;上层framework层的Binder逻辑是建立在Native层架构基础之上的&#xff0c;核心逻辑都…

shell编程:概述、脚本入门、变量、运算符、条件判断、流程控制、读取控制台、函数、正则表达式、文本处理工具、综合案例

第 1 章 Shell 概述 1&#xff09;Linux 提供的 Shell 解析器有 [atguiguhadoop101 ~]$ cat /etc/shells /bin/sh /bin/bash /usr/bin/sh /usr/bin/bash /bin/tcsh /bin/csh2&#xff09;bash 和 sh 的关系 sh&#xff1a;比较基础bash&#xff1a;功能更加强大&#xff0c;默…

三十四、Hybrid 接口用法解析

文章目录 前言交换机接口类型有哪些Hybrid 端口使用场景什么时候必须使用 Hybrid 一、Hybrid 特点二、Hybrid 当做 access和trunk使用三、Hybrid 特殊用法 前言 交换机接口类型有哪些 Access、trunk、Hybrid、qinq Hybrid 端口使用场景 接pc、服务器、接交换机、接路由器&a…

Linux守护进程

"忍耐的灵魂啊&#xff0c;安静地运转吧~" 我们先来看看这个场景。这是一个常见的基于TCP套接字的网络服务器&#xff0c;服务端接收客户端发送的消息&#xff0c;收到后并向echo回响给客户端。 对于Linux而言&#xff0c;终端只能有一个前台进程&#xff0c;这也是为…

行业唯一丨冠珠出席“中国企业社会责任高峰论坛”,并荣获人民日报社“ESG年度案例”

践行社会责任&#xff0c;推动品牌高质量发展。5月11日&#xff0c;由人民日报社指导、人民日报社经济社会部主办的“中国企业社会责任高峰论坛”在上海盛大举行。 本次论坛围绕乡村振兴、共同富裕、绿色低碳等重点议题进行深入研讨&#xff0c;邀请国家发展和改革委员会、商务…

教程硬货|微信小程序开发之基于vue的微信开发工具JS文件解读(一)

文章目录 1 前言2 前期准备3 微信开发者工具3.1 创建项目3.2 页面介绍 4 读懂Pages4.1 index.wxss4.2 index.wxml4.3 index.json4.4 index.js 5 logs6 小程序的主要文件6.1 app.js6.2 app.json 7 讨论 1 前言 鉴于前段时间出的第一篇记录安装Nodejs和HBuilderX搭建、部署微信小…

【C++】内存分区模型

目录 1、缘起 2、内存分区模型 2.1、程序运行前 2.2、程序运行后 3、总结 1、缘起 前几天学习完了 C 的 基础语法 知识点&#xff0c;现在终于要踏上学习 C 核心编程 的旅程了&#xff0c;期待沿途中所遇到的风景。 2、内存分区模型 C 程序在执行时&#xff0c;将内存大…

【Python Cookie 和代理 IP】零基础也能轻松掌握的学习路线与参考资料

一、Python Cookie 1、什么是Cookie&#xff1f; Cookie是一种在客户端保存数据的机制&#xff0c;服务器通过在HTTP响应头中添加Set-Cookie头实现。浏览器在接收到响应头中的Set-Cookie后&#xff0c;会将这个Cookie保存在本地。之后每次请求都会将本地保存的Cookie自动添加…

WPF插件之 - PropertyChanged.Fody插件的使用详解

总目录 文章目录 总目录一、PropertyChanged.Fody是什么&#xff1f;二、PropertyChanged.Fody的安装三、PropertyChanged.Fody的功能1. 特性1 实现属性通知的功能2 通知其他属性4 不进行属性通知3 指定属性更改时将调用的方法5 设置当前属性依赖的属性6 不检查是否相等7 DoNot…

lua:浅谈对元表和元方法的认识

前言 本篇在讲什么 浅谈对Lua元表和元方法的理解 本篇适合什么 适合初学Lua的小白 本篇需要什么 对Lua语法有简单认知 依赖Lua5.1的环境 依赖Sublime Text3编辑器 本篇的特色 具有全流程的图文教学 重实践&#xff0c;轻理论&#xff0c;快速上手 提供全流程的源码…