main.c
#include "led.h"
#include "delay.h"
#include "sys.h"
#include "FreeRTOS.h"
#include "task.h"
//任务优先级
#define START_TASK_PRIO 1
//任务堆栈大小
#define START_STK_SIZE 50
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);
//任务优先级
#define LED0_TASK_PRIO 2
//任务堆栈大小
#define LED0_STK_SIZE 50
//任务句柄
TaskHandle_t LED0Task_Handler;
//任务函数
void led0_task(void *pvParameters);
//任务优先级
#define QUERY_TASK_PRIO 3
//任务堆栈大小
#define QUERY_STK_SIZE 100
//任务句柄
TaskHandle_t QUERYTask_Handler;
//任务函数
void query_task(void *pvParameters);
char InfoBuffer[1000];
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
//创建开始任务
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(); //进入临界区
//创建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);
//创建LED1任务
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);
}
}
//QUERY任务函数
void query_task(void *pvParameters)
{//1
UBaseType_t Priority;
//3
uint32_t TotalRunTime;
UBaseType_t ArraySize;
TaskStatus_t * StatusArray;//结构体指针,采用分配内存,也可直接定义结构体分配内存,再将结构体数组名传入函数
TaskStatus_t *px;
int x;
//4
TaskStatus_t SingleStatus;
//5
TaskHookFunction_t LED0HookFunction;//函数指针
//6
TaskHandle_t TestHandler1;
TaskHandle_t TestHandler2;
//8
TaskHandle_t Idle_TaskHandler;
//9
UBaseType_t restvalue;
//10
eTaskState TaskState;
//11
char *p;
//12
TickType_t TickType;
//14
BaseType_t SchedulerState;
//15
UBaseType_t NumberOfTasks;
//1、函数 UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask )\
宏 INCLUDE_uxTaskPriorityGet 为 1
Priority=uxTaskPriorityGet(QUERYTask_Handler);//传入任务句柄,返回先级
printf("QUERYTask的优先级是:%d\r\n",(int)Priority);
printf("led0_task的优先级是:%d\r\n",(int)uxTaskPriorityGet(LED0Task_Handler));
//2、函数 void vTaskPrioritySet( TaskHandle_t xTask,UBaseType_t uxNewPriority ),
// 宏INCLUDE_vTaskPrioritySet 定义为 1
vTaskPrioritySet( LED0Task_Handler, 4 );
printf("led0_task新优先级是:%d\r\n",(int)uxTaskPriorityGet(LED0Task_Handler));
vTaskPrioritySet( LED0Task_Handler, 2 );
printf("led0_task设置回原来的优先级是:%d\r\n",(int)uxTaskPriorityGet(LED0Task_Handler));
//3、函数UBaseType_t uxTaskGetSystemState( TaskStatus_t * const pxTaskStatusArray,\
const UBaseType_t uxArraySize,\
uint32_t * const pulTotalRunTime ) \
宏configUSE_TRACE_FACILITY 为 1
ArraySize=uxTaskGetNumberOfTasks();//获取系统中的任务个数
StatusArray=pvPortMalloc( ArraySize*sizeof (TaskStatus_t));//任务数*任务状态结构体的大小=任务状态结构体数组的大小,并返回申请是否成功
if(StatusArray!=NULL)//如果申请成功
{
uxTaskGetSystemState( (TaskStatus_t *) StatusArray,
(UBaseType_t ) ArraySize,
(uint32_t * ) &TotalRunTime);//取地址
//调用后,也将各任务TaskStatus_t结构体的信息存入到申请的内存(StatusArray)
//访问StatusArray数组,打印信息
printf("**************第一种遍历结构体数组方式*********************\r\n");
printf("TaskName\tTaskNumber\tCurrentPriority\tCurrentState\tRunTimeCounter\tStackHighWaterMark\r\n");
for(px=StatusArray;px<=StatusArray+sizeof(ArraySize);px++)
{
printf("%s\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d\r\n",px->pcTaskName,
(int)(px->xTaskNumber),
(int)(px->uxCurrentPriority),
(eTaskState)(px->eCurrentState),
(uint32_t)(px->ulRunTimeCounter),
(uint16_t)(px->usStackHighWaterMark));
}
printf("**************第二种遍历结构体数组方式*********************\r\n");
printf("TaskName\tTaskNumber\tCurrentPriority\tCurrentState\tRunTimeCounter\tStackHighWaterMark\r\n");
for(x=0;x<=sizeof(ArraySize);x++)
{
printf("%s\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d\r\n",StatusArray[x].pcTaskName,
(int)StatusArray[x].xTaskNumber,
(int)StatusArray[x].uxCurrentPriority,
StatusArray[x].eCurrentState,
StatusArray[x].ulRunTimeCounter,
StatusArray[x].usStackHighWaterMark);
}
}
//4、函数void vTaskGetInfo( TaskHandle_t xTask,\
TaskStatus_t * pxTaskStatus\
BaseType_t xGetFreeStackSpace,\
eTaskState eState )获取指定的单个任务的壮态\
宏configUSE_TRACE_FACILITY 为 1,
vTaskGetInfo( (TaskHandle_t) LED0Task_Handler,//TaskHandle_t结构体指针,也就是任务句柄
(TaskStatus_t *) &SingleStatus,//TaskStatus_t结构体,取地址,传给指针
(BaseType_t)pdTRUE,//设为pdFALSE来跳过这个步骤,pdTRUE就会去统计任务堆栈历史最小剩余大小
(eTaskState)eInvalid);//自己获取任务运行状态
printf("4————查看单个任务状态\r\n");
printf("4————TaskName\tTaskNumber\tCurrentPriority\tCurrentState\tRunTimeCounter\tStackHighWaterMark\r\n");
printf("\t%s\t\t%d\t\t%d\t\t%d\t\t%d\t\t%d\r\n",SingleStatus.pcTaskName,
(int)SingleStatus.xTaskNumber,
(int)SingleStatus.uxCurrentPriority,
SingleStatus.eCurrentState,
SingleStatus.ulRunTimeCounter,
SingleStatus.usStackHighWaterMark);
//5、函数TaskHookFunction_t xTaskGetApplicationTaskTag( TaskHandle_t xTask ) 传入任务句柄,返回任务标签 \
宏configUSE_APPLICATION_TASK_TAG 为 1
LED0HookFunction=xTaskGetApplicationTaskTag(LED0Task_Handler);
printf("5————LED0HookFunction=%#x\r\n",(int)LED0HookFunction);
//6、函数 TaskHandle_t xTaskGetCurrentTaskHandle( void ) 返回当前任务句柄\
INCLUDE_xTaskGetCurrentTaskHandle 为 1
TestHandler1=xTaskGetCurrentTaskHandle();
printf("6————TestHandler1=%#x\r\n",(int)TestHandler1);
printf("6————QUERYTask_Handler=%#x\r\n",(int)QUERYTask_Handler); //结果一致
//7、TaskHandle_t xTaskGetHandle( const char * pcNameToQuery )根据任务名字获取任务的任务句柄
// INCLUDE_xTaskGetHandle 为 1
TestHandler2=xTaskGetHandle( "led0_task");//字符串
printf("7—————TestHandler2=%#x\r\n",(int)TestHandler2);
printf("7—————LED0Task_Handler=%#x\r\n",(int)LED0Task_Handler); //结果一致
//8、TaskHandle_t xTaskGetIdleTaskHandle( void ) 返 回 空 闲 任 务 的 任 务 句 柄 \
INCLUDE_xTaskGetIdleTaskHandle 必须为 1
Idle_TaskHandler=xTaskGetIdleTaskHandle();
printf("8————Idle_TaskHandler=%#x\r\n",(int)Idle_TaskHandler); //结果一致
//9、UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask ) 返回从创建好到现在的历史剩余最小值\
INCLUDE_uxTaskGetStackHighWaterMark 为 1
restvalue=uxTaskGetStackHighWaterMark(LED0Task_Handler);
printf("9————restvalue=%d\r\n",(int)restvalue); //结果一致
//10、eTaskState eTaskGetState( TaskHandle_t xTask ) 查询某个任务的运行壮态\
INCLUDE_eTaskGetState 必须为 1
TaskState=eTaskGetState(LED0Task_Handler);//获取LED0任务的状态
printf("10————LED0TaskState=%d\r\n",(int)TaskState);
TaskState=eTaskGetState(QUERYTask_Handler);//获取QUERY任务的状态
printf("10————QUERYTaskState=%d\r\n",(int)TaskState);
//11、char *pcTaskGetName( TaskHandle_t xTaskToQuery ) 根据任务句柄来查询对应的任务名
p=pcTaskGetName(LED0Task_Handler);
printf("11————LED0Taskname:%s\r\n",p);
p=pcTaskGetName(QUERYTask_Handler);
printf("11————QUERYTaskname:%s\r\n",p);
//12、TickType_t xTaskGetTickCount( void )查询任务调度器从启动到现在时间计数器 xTickCount 的值\
的时钟节拍值,并不是真实的时间值。 每个滴答定时器中断 xTickCount 就会加 1,\
宏 configUSE_16_BIT_TICKS,宏为 1 的时候返回值 xTixkCount 就是个 16 位的变量,当为 0 的时候就是个 32 位的变量。
TickType=xTaskGetTickCount();//宏为0,返回32位的
printf("12————xTickCount的值:%d\r\n",TickType);
//13、TickType_t xTaskGetTickCountFromISR( void ) 中断服务函数中获取时间计数器xTickCount 的值。
//14、BaseType_t xTaskGetSchedulerState( void )获取 FreeRTOS 的任务调度器运行情况:运行?关闭?还是挂起! \
宏 INCLUDE_xTaskGetSchedulerState 为 1
SchedulerState=xTaskGetSchedulerState();
printf ("14———调度器的状态:%d\r\n",(int)SchedulerState);
/*taskSCHEDULER_SUSPENDED ( ( BaseType_t ) 0 )
taskSCHEDULER_NOT_STARTED ( ( BaseType_t ) 1 )
taskSCHEDULER_RUNNING ( ( BaseType_t ) 2 )
*/
//15、UBaseType_t uxTaskGetNumberOfTasks( void )查询系统当前存在的任务数量\
此值=挂起态的任务+阻塞态的任务+就绪态的任务+空闲任务+运行态的任务的总数
NumberOfTasks=uxTaskGetNumberOfTasks();
printf ("15————当前任务总数:%d \r\n",(int)NumberOfTasks);
//16、void vTaskList( char * pcWriteBuffer ) 创建一个表格来描述每个任务的详细信息
vTaskList(InfoBuffer);//申请一个空间(字符数组),调用函数后,将信息存入该数组
printf ("\r\n");
printf ("任务名 运行状态 优先级 高水位线 任务号\t\r\n");
printf("%s",InfoBuffer);//将整个字符数组打印,含有转移字符,自动变成表
while(1)
{
LED1=0;
vTaskDelay(200);
LED1=1;
vTaskDelay(800);
}
}
FreeRTOSConfig.h
#ifndef FREERTOS_CONFIG_H
#define FREERTOS_CONFIG_H
#include "sys.h"
#include "usart.h"
//针对不同的编译器调用不同的stdint.h文件
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
#include <stdint.h>
extern uint32_t SystemCoreClock;
#endif
//断言
#define vAssertCalled(char,int) printf("Error:%s,%d\r\n",char,int)
#define configASSERT(x) if((x)==0) vAssertCalled(__FILE__,__LINE__)
/***************************************************************************************************************/
/* FreeRTOS基础配置配置选项 */
/***************************************************************************************************************/
#define configUSE_PREEMPTION 1 //1使用抢占式内核,0使用协程
#define configUSE_TIME_SLICING 1 //1使能时间片调度(默认式使能的)
#define configUSE_PORT_OPTIMISED_TASK_SELECTION 1 //1启用特殊方法来选择下一个要运行的任务
//一般是硬件计算前导零指令,如果所使用的
//MCU没有这些硬件指令的话此宏应该设置为0!
#define configUSE_TICKLESS_IDLE 0 //1启用低功耗tickless模式
#define configUSE_QUEUE_SETS 1 //为1时启用队列集
#define configCPU_CLOCK_HZ (SystemCoreClock) //CPU频率
#define configTICK_RATE_HZ (1000) //时钟节拍频率,这里设置为1000,周期就是1ms
#define configMAX_PRIORITIES (32) //可使用的最大优先级
#define configMINIMAL_STACK_SIZE ((unsigned short)130) //空闲任务使用的堆栈大小
#define configMAX_TASK_NAME_LEN (16) //任务名字字符串长度
#define configUSE_16_BIT_TICKS 0 //系统节拍计数器变量数据类型,
//1表示为16位无符号整形,0表示为32位无符号整形
#define configIDLE_SHOULD_YIELD 1 //为1时空闲任务放弃CPU使用权给其他同优先级的用户任务
#define configUSE_TASK_NOTIFICATIONS 1 //为1时开启任务通知功能,默认开启
#define configUSE_MUTEXES 1 //为1时使用互斥信号量
#define configQUEUE_REGISTRY_SIZE 8 //不为0时表示启用队列记录,具体的值是可以
//记录的队列和信号量最大数目。
#define configCHECK_FOR_STACK_OVERFLOW 0 //大于0时启用堆栈溢出检测功能,如果使用此功能
//用户必须提供一个栈溢出钩子函数,如果使用的话
//此值可以为1或者2,因为有两种栈溢出检测方法。
#define configUSE_RECURSIVE_MUTEXES 1 //为1时使用递归互斥信号量
#define configUSE_MALLOC_FAILED_HOOK 0 //1使用内存申请失败钩子函数
#define configUSE_APPLICATION_TASK_TAG 1
#define configUSE_COUNTING_SEMAPHORES 1 //为1时使用计数信号量
/***************************************************************************************************************/
/* FreeRTOS与内存申请有关配置选项 */
/***************************************************************************************************************/
#define configSUPPORT_DYNAMIC_ALLOCATION 1 //支持动态内存申请
#define configTOTAL_HEAP_SIZE ((size_t)(20*1024)) //系统所有总的堆大小
/***************************************************************************************************************/
/* FreeRTOS与钩子函数有关的配置选项 */
/***************************************************************************************************************/
#define configUSE_IDLE_HOOK 0 //1,使用空闲钩子;0,不使用
#define configUSE_TICK_HOOK 0 //1,使用时间片钩子;0,不使用
/***************************************************************************************************************/
/* FreeRTOS与运行时间和任务状态收集有关的配置选项 */
/***************************************************************************************************************/
#define configGENERATE_RUN_TIME_STATS 0 //为1时启用运行时间统计功能
#define configUSE_TRACE_FACILITY 1 //为1启用可视化跟踪调试
#define configUSE_STATS_FORMATTING_FUNCTIONS 1 //与宏configUSE_TRACE_FACILITY同时为1时会编译下面3个函数
//prvWriteNameToBuffer(),vTaskList(),
//vTaskGetRunTimeStats()
/***************************************************************************************************************/
/* FreeRTOS与协程有关的配置选项 */
/***************************************************************************************************************/
#define configUSE_CO_ROUTINES 0 //为1时启用协程,启用协程以后必须添加文件croutine.c
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) //协程的有效优先级数目
/***************************************************************************************************************/
/* FreeRTOS与软件定时器有关的配置选项 */
/***************************************************************************************************************/
#define configUSE_TIMERS 1 //为1时启用软件定时器
#define configTIMER_TASK_PRIORITY (configMAX_PRIORITIES-1) //软件定时器优先级
#define configTIMER_QUEUE_LENGTH 5 //软件定时器队列长度
#define configTIMER_TASK_STACK_DEPTH (configMINIMAL_STACK_SIZE*2) //软件定时器任务堆栈大小
/***************************************************************************************************************/
/* FreeRTOS可选函数配置选项 */
/***************************************************************************************************************/
#define INCLUDE_xTaskGetSchedulerState 1
#define INCLUDE_vTaskPrioritySet 1
#define INCLUDE_uxTaskPriorityGet 1
#define INCLUDE_vTaskDelete 1
#define INCLUDE_vTaskCleanUpResources 1
#define INCLUDE_vTaskSuspend 1
#define INCLUDE_vTaskDelayUntil 1
#define INCLUDE_vTaskDelay 1
#define INCLUDE_eTaskGetState 1
#define INCLUDE_xTimerPendFunctionCall 1
#define INCLUDE_xTaskGetHandle 1
#define INCLUDE_uxTaskGetStackHighWaterMark 1
#define INCLUDE_xTaskGetIdleTaskHandle 1
#define INCLUDE_xTaskGetSchedulerState 1
/***************************************************************************************************************/
/* FreeRTOS与中断有关的配置选项 */
/***************************************************************************************************************/
#ifdef __NVIC_PRIO_BITS
#define configPRIO_BITS __NVIC_PRIO_BITS
#else
#define configPRIO_BITS 4
#endif
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15 //中断最低优先级
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5 //系统可管理的最高中断优先级
#define configKERNEL_INTERRUPT_PRIORITY ( configLIBRARY_LOWEST_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
#define configMAX_SYSCALL_INTERRUPT_PRIORITY ( configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY << (8 - configPRIO_BITS) )
/***************************************************************************************************************/
/* FreeRTOS与中断服务函数有关的配置选项 */
/***************************************************************************************************************/
#define xPortPendSVHandler PendSV_Handler
#define vPortSVCHandler SVC_Handler
#endif /* FREERTOS_CONFIG_H */