目录
- 一、任务相关 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个时钟节拍
}
}