1、 编写任务列表。
1.1、在FreeRTOS文件夹下新建task_list.c和task_list.h文件,添加到工程中。
1.2、 撸代码
#include "task_lists.h"
List_t pxReadyTasksLists[ configMAX_PRIORITIES ];
//初始就绪链表======================================================
void prvInitialiseTaskLists( void )
{
UBaseType_t uxPriority;
for (uxPriority=0; uxPriority<configMAX_PRIORITIES; uxPriority++)
{
vListInitialise(&pxReadyTasksLists[uxPriority]);
}
}
2、 编写芯片相关的函数
2.1、 在FreeRTOS文件夹下新建port.c和port.h,添加到工程中。
2.2、 撸代码
①pxPortInitialiseStack 函数是栈的初始化
②prvStartFirstTask 触发 vPortSVCHandler
③xPortStartScheduler启动调度器。
④ vPortSVCHandler处理函数
⑤xPortPendSVHandler处理函数。是由#define portYIELD() 触发
3、 编写任务相关的函数
3.1、 在FreeRTOS文件夹下新建task.c和task.h,添加到工程中。
3.1、 撸代码
#include "task.h"
TCB_t * volatile pxCurrentTCB=NULL;
static void prvInitialiseNewTask( TaskFunction_t pxTaskCode, /* 任务入口*/
const char * const pcName, /* 任务名称*/
const uint32_t ulStackDepth, /* 任务栈大小,单位为字*/
void * const pvParameters, /* 任务形参*/
TaskHandle_t * const pxCreatedTask, /* 任务栈的起始地址*/
TCB_t *pxNewTCB ) /* 任务控制块*/
{
StackType_t *pxTopOfStack;
UBaseType_t x;
/* 获取栈顶地址*/
pxTopOfStack = pxNewTCB->pxStack + (ulStackDepth-(uint32_t)1);
/* 向下做8字节对齐*/
pxTopOfStack = ( StackType_t * ) ( ( ( uint32_t ) pxTopOfStack ) & ( ~( ( uint32_t ) 0x0007 ) ) );
/* 将任务的名字存储在TCB中*/
for (x=0; x<configMAX_TASK_NAME_LEN; x++)
{
pxNewTCB->pcTaskName[x] = pcName[x];
if (pcName[x]==0x00)
break;
}
pxNewTCB->pcTaskName[configMAX_TASK_NAME_LEN-1] = '\0';
vListInitialiseItem(&(pxNewTCB->xStateListItem));
listSET_LIST_ITEM_OWNER(&(pxNewTCB->xStateListItem),pxNewTCB);
pxNewTCB->pxTopOfStack = pxPortInitialiseStack(pxTopOfStack,pxTaskCode,pvParameters);
/* 让任务句柄指向任务控制块*/
if ( (void*)pxCreatedTask !=NULL)
{
pxCreatedTask[0] = (TaskHandle_t)pxNewTCB;
}
}
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint32_t ulStackDepth,
void * const pvParameters,
StackType_t * const puxStackBuffer,
TCB_t * const pxTaskBuffer )
{
TCB_t *pxNewTCB;
TaskHandle_t xReturn = NULL;
if ( pxTaskBuffer!=NULL && puxStackBuffer!=NULL)
{
pxNewTCB = (TCB_t*)pxTaskBuffer;
pxNewTCB->pxStack = (StackType_t*)puxStackBuffer;
prvInitialiseNewTask( pxTaskCode, /* 任务入口*/
pcName, /* 任务名称*/
ulStackDepth, /* 任务栈大小,单位为字*/
pvParameters, /* 任务形参*/
&xReturn, /* 任务句柄*/
pxNewTCB); /* 任务控制块*/
}
return xReturn;
}
extern TCB_t Task1TCB;
extern TCB_t Task2TCB;
void vTaskStartScheduler( void )
{
pxCurrentTCB = &Task1TCB;
/* 启用调度器*/
xPortStartScheduler();
//理论是不会到这里
while(1){}
}
void vTaskSwitchContext( void )
{
if( pxCurrentTCB == &Task1TCB )
{
pxCurrentTCB = &Task2TCB;
} else
{
pxCurrentTCB = &Task1TCB;
}
}
4、编写2个任务
4.1、 在User文件夹下新建app_task.c和app_task.h,添加到工程中。
4.1、 撸代码
#include "app_task.h"
uint32_t flag1=0;
uint32_t flag2=0;
void delay (uint32_t count)
{
for(; count!=0; count--);
}
void Task1_Entry( void *p_arg )
{
for( ;; )
{
flag1 = 1;
delay( 100 );
flag1 = 0;
delay( 100 );
portYIELD();
}
}
void Task2_Entry( void *p_arg )
{
for( ;; )
{
flag2 = 1;
delay( 100 );
flag2 = 0;
delay( 100 );
portYIELD();
}
}
5、 修改mian.c
#include "portmacro.h"
#include "list.h"
#include "task_lists.h"
#include "task.h"
#include "app_task.h"
#include "port.h"
TaskHandle_t Task1_Handle;
#define TASK1_STACK_SIZE 20
StackType_t Task1Stack[TASK1_STACK_SIZE];
TCB_t Task1TCB;
TaskHandle_t Task2_Handle;
#define TASK2_STACK_SIZE 20
StackType_t Task2Stack[TASK2_STACK_SIZE];
TCB_t Task2TCB;
int main(void)
{
/* 就绪列表初始化*/
prvInitialiseTaskLists();
/* 创建任务1*/
Task1_Handle = xTaskCreateStatic(Task1_Entry,"task1",TASK1_STACK_SIZE,0,Task1Stack,&Task1TCB);
/* 插入就绪列表*/
vListInsertEnd( &( pxReadyTasksLists[1] ), &( ((TCB_t *)(&Task1TCB))->xStateListItem ) );
/* 创建任务2*/
Task2_Handle = xTaskCreateStatic(Task2_Entry,"task2",TASK2_STACK_SIZE,0,Task2Stack,&Task2TCB);
/* 插入就绪列表*/
vListInsertEnd( &( pxReadyTasksLists[2] ), &( ((TCB_t *)(&Task2TCB))->xStateListItem ) );
/*启动任务*/
vTaskStartScheduler();
//理论是不会到这里
while(1){}
}
项目结构如下:
运行结果如下