目录
一、函数vTaskList()
1、 函数说明
2、返回的字符串表格说明
3、函数的使用方法
二、 vTaskList()的应用示例
1、示例功能、项目设置
2、软件设计
(1)main.c
(2)freertos.c
(3)FreeRTOSConfig.h
三、运行与调试
一、函数vTaskList()
1、 函数说明
函数vTaskList()是内核信息统计用途的API函数,用于返回内核中所有任务的字符串列表信息,包括每个任务的名称、状态、优先级、高水位值、任务编号等。其原型定义如下:
#if ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )void vTaskList( char * pcWriteBuffer ){TaskStatus_t *pxTaskStatusArray;UBaseType_t uxArraySize, x;char cStatus;//此处省去1万言}#endif /* ( ( configUSE_TRACE_FACILITY == 1 ) && ( configUSE_STATS_FORMATTING_FUNCTIONS > 0 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) */
参数pcWriteBuffer是预先创建的一个字符数组的指针,用于存储返回的字符串信息。这个字符数组必须足够大,FreeRTOS不会检查这个数组的大小。这个函数的使用示例代码如下:
char infoBuffer[300];
vTaskList(infoBuffer);
返回的数据存储在字符数组infoBuffer中,使用了“\t”“\n”等转义字符,以便用表格方式显示。
2、返回的字符串表格说明
函数vTaskList()返回的是一个用字符串表达的表格。例如:
Task_LED1 \tx\t8\t50\t2\r\n
Tmr Svc \tR\t2\t246\t4\r\n
IDLE \tR\t0\t118\t3\r\n
Task_ADC \tB\t24\t134\t1\r\n\0
其中,每行字符串的第1列是任务名称,这里除了用户的两个任务Task_LED1和Task_ADC,还有系统自动创建的空闲任务IDLE和定时器服务任务Tmr Svc。
其中,每行字符串的第2列是用“\t”分隔的多个参数,依次为状态、优先级、栈空间高水位值和任务编号。
其中的第2列,任务状态用字母表示,各字母的意义如下:
- X,运行状态,也就是调用函数vTaskList()的任务的状态。
- B,阻塞状态。
- R,就绪状态。
- S,挂起状态,或无限等待时间的阻塞状态。
- D,被删除的任务,但是空闲任务还没有释放其使用的内存。
例如,对于上图中的任务Task_LED1,其状态字符串是“\tX\t8\t50\t2\r\n”,表示它处于运行状态,优先级为8,栈空间高水位值为50,任务编号为2。
3、函数的使用方法
vTaskList()的代码实现用到了函数sprintf(),会使编译后的应用的大小明显增大。所以,函数一般只在调试时使用,不要在发布版本里使用。要使用这个函数,需要将以下3个参数都设置为1。如果不这样操作,编译器会警告。
- configUSE_TRACE_FACILITY,默认值为1,可在CubeMX里设置。
- configUSE_STATS_FORMATTING_FUNCTION,默认值为0,可在CubeMX里设置。
- configSUPPORT_DYNAMIC_ALLOCATION,默认值为1,不能在CubeMX里设置。
修改FreeRTOSConfig.h,定义宏,覆盖FreeRTOS.h相关的宏定义:
//vTaskList()
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configSUPPORT_DYNAMIC_ALLOCATION 1
二、 vTaskList()的应用示例
使用本文作者写的其他文章作为本文示例的参考文章,项目背景、项目配置完全相同。特别地,创建的FreeRTOS任务完全相同。项目的软件设计大部分相同。
参考文章:细说STM32单片机FreeRTOS任务管理API函数及多任务编程的实现方法-CSDN博客 https://wenchm.blog.csdn.net/article/details/147249948?spm=1011.2415.3001.5331
1、示例功能、项目设置
与参考文章相同。
2、软件设计
(1)main.c
与参考文章相同。
(2)freertos.c
下面的任务函数代码,CubeMX自动生成函数框架,手动重写函数体:
/* USER CODE BEGIN Header_AppTask_info */
/**
* @brief Function implementing the Task_info thread.
* @param argument: Not used
* @retval None
*/
/* USER CODE END Header_AppTask_info */
void AppTask_info(void *argument)
{/* USER CODE BEGIN AppTask_info *////*----------获取单个任务信息----------*///TaskHandle_t taskHandle=xTaskGetCurrentTaskHandle(); ///<获取当前任务句柄TaskHandle_t taskHandle=xTaskGetIdleTaskHandle(); ///<获取空闲任务句柄//TaskHandle_t taskHandle=xTaskGetHandle("Task_ADC"); ///<通过任务名称获取句柄//TaskHandle_t taskHandle=Task_ADCHandle; ///<直接使用句柄变量TaskStatus_t taskInfo; ///<任务信息BaseType_t getFreeStackSpace=pdTRUE; ///<是否获取高水位值eTaskState taskState=eInvalid; ///<当前任务状态vTaskGetInfo(taskHandle, &taskInfo, getFreeStackSpace, taskState); ///<获取任务信息taskENTER_CRITICAL(); ///<开始临界代码段,禁止任务调度printf("Task_Info: Show task info and get it by vTaskGetInfo(). \r\n");printf("Task Name = %s\r\n",taskInfo.pcTaskName);printf("Task Number = %ld\r\n",taskInfo.xTaskNumber);printf("Task State = %d\r\n",taskInfo.eCurrentState);printf("Task Priority = %ld\r\n",taskInfo.uxCurrentPriority);printf("High Water Mark = %d\r\n\r\n",taskInfo.usStackHighWaterMark);///*----------获取每个任务的高水位值----------*/printf("Task_Info: Get High Water Mark of tasks. \r\n");taskHandle=xTaskGetIdleTaskHandle();UBaseType_t hwm=uxTaskGetStackHighWaterMark(taskHandle);printf("Idle Task = %ld\r\n",hwm);taskHandle=Task_ADCHandle;hwm=uxTaskGetStackHighWaterMark(taskHandle);printf("Task_ADC = %ld\r\n",hwm);taskHandle=Task_infoHandle;hwm=uxTaskGetStackHighWaterMark(taskHandle);printf("Task_Info = %ld\r\n\r\n",hwm);///*----------获取内核信息----------*/printf("Task_Info: Get Kernel Info. \r\n");UBaseType_t taskNum=uxTaskGetNumberOfTasks(); ///<获取任务数量printf("uxTaskGetNumberOfTasks() = %ld\r\n\r\n",taskNum);char infoBuffer[300];vTaskList(infoBuffer); ///<返回字符串表格,用/t/n制表printf("vTaskList: \r\n");printf("TaskName Status Priority HighLevel Index\r\n");printf("%s\r\n",infoBuffer);taskEXIT_CRITICAL(); ///<结束临界代码段,允许任务调度UBaseType_t loopCount=0;/* Infinite loop */for(;;){loopCount++;HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_6); ///<PA6=LED1 flashingvTaskDelay(pdMS_TO_TICKS(3000));if (loopCount==10) ///<循环10次后退出break;printf("Task_Info is deleted,and then only Task_ADC is running. \r\n\r\n");vTaskDelete(NULL); ///<删除任务自身}/* USER CODE END AppTask_info */
}
其它部分的代码与参考项目完全相同。
(3)FreeRTOSConfig.h
使用一些函数,如函数xTaskGetIdleTaskHandle()时,可能会出现编译错误,显示这个函数未定义。这是因为在源程序tasks.c中,这个函数有个预编译条件,只有当参数INCLUDE_xTaskGetldleTaskHandle值为1时,才编译这个函数。CubeMX中没有这个参数的对应设置项,而文件FreeRTOS.h中,这个参数的默认值为0。我们需要将这个参数的值修改为1,但是要注意,不能在文件FreeRTOS.h中直接修改这个参数的值,而要在文件FreeRTOSConfig.h的用户代码沙箱段内,重新定义这个宏,即下面的代码:
/* USER CODE BEGIN Defines */
/* Section where parameter definitions can be added (for instance, to override default ones in FreeRTOS.h) */
//xTaskGetIdleTaskHandle()
#define INCLUDE_xTaskGetIdleTaskHandle 1//vTaskList()
#define configUSE_TRACE_FACILITY 1
#define configUSE_STATS_FORMATTING_FUNCTIONS 1
#define configSUPPORT_DYNAMIC_ALLOCATION 1/* USER CODE END Defines */
这个沙箱段在文件FreeRTOSConfig.h中的最下方,就是用于重新定义一些无法在CubeMX中可视化设置的参数,用于替换其在文件FreeRTOS.h中的默认定义。
三、运行与调试
构建项目后,将其下载到开发板上并运行,可以在串口助手上看到各种信息。任务Task_ADC周期性地通过ADC3采集电压值,并在串口助手上显示;任务Task_Info读取的信息在串口助手上显示,LED1闪烁几次后,任务Task_Info被删除,LED1不再闪烁,修改延迟时间会小小改变删除任务的效果。这个结果与参考文章的结果相同。
不同于参考文章,本示例的运行结果还包含主要考察的函数vTaskList()的应用效果: