freeRTOS中的链表结构:
/* * Definition of the only type of object that a list can contain. 链表中的节点 */ struct xLIST_ITEM { listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ configLIST_VOLATILE TickType_t xItemValue; /*< The value being listed. In most cases this is used to sort the list in descending order. */ struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< Pointer to the next ListItem_t in the list. */ struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */ void * pvOwner; /*< Pointer to the object (normally a TCB) that contains the list item. There is therefore a two way link between the object containing the list item and the list item itself. 指向该节点的拥有者 及内嵌在哪个数据结构中 */ void * configLIST_VOLATILE pvContainer; /*< Pointer to the list in which this list item is placed (if any).通常指向链表的根节点 */ listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ }; typedef struct xLIST_ITEM ListItem_t; /* For some reason lint wants this as two separate definitions. */
/* * Definition of the type of queue used by the scheduler. 链表 */ typedef struct xLIST { listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ configLIST_VOLATILE UBaseType_t uxNumberOfItems; 链表节点计数器 ListItem_t * configLIST_VOLATILE pxIndex; /*< Used to walk through the list. Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY ().链表节点索引指针 */ MiniListItem_t xListEnd; /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */ listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ } List_t;
struct xMINI_LIST_ITEM 链表的最后一个节点或者说是第一个节点 一个marker { listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */ configLIST_VOLATILE TickType_t xItemValue; struct xLIST_ITEM * configLIST_VOLATILE pxNext; struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; }; typedef struct xMINI_LIST_ITEM MiniListItem_t;
对链表的插入删除操作可参见源码中的list.c。
任务的定义与切换:
main()函数里面顺序执行的无限循环,在这个循环中,CPU按照顺序完成各种操作。
多任务系统中,根据功能的不同,把整个系统分割成一个个独立的且无法返回的函数,这种函数就被称为任务。
多任务系统中,每个任务都是独立的、互不干扰的,所以要为每个任务分配独立的栈空间,这个栈空间通常是一个预先定义好的全局数组。也可以是动态分配的一段内存空间。
TCB任务控制块,相当于人物的身份证,里面存有任务的所有信息。以后对任务的全部操作都可以通过任务控制块来实现。
/* * Task control block. A task control block (TCB) is allocated for each task, * and stores task state information, including a pointer to the task's context * (the task's run time environment, including register values) */ typedef struct tskTaskControlBlock { volatile StackType_t *pxTopOfStack; /*< Points to the location of the last item placed on the tasks stack. THIS MUST BE THE FIRST MEMBER OF THE TCB STRUCT. */栈顶 ListItem_t xStateListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */ 任务节点 ListItem_t xEventListItem; /*< Used to reference a task from an event list. */ UBaseType_t uxPriority; /*< The priority of the task. 0 is the lowest priority. */ StackType_t *pxStack; /*< Points to the start of the stack. */ 任务栈起始地址 char pcTaskName[ configMAX_TASK_NAME_LEN ];/*< Descriptive name given to the task when created. Facilitates debugging only. */ /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ } tskTCB; /* The old tskTCB name is maintained above then typedefed to the new TCB_t name below to enable the use of older kernel aware debuggers. */ typedef tskTCB TCB_t;
任务创建函数,静态创建(PCB和栈的内存需要预先定义好,任务删除时,内存不能释放),动态创建(创建任务时动态分配,任务删除,可以释放)。
TaskHandle_t xTaskCreateStatic( TaskFunction_t pxTaskCode, //函数入口 const char * const pcName, //任务名称 const uint32_t ulStackDepth, //任务栈大小 void * const pvParameters, //任务形参 UBaseType_t uxPriority, StackType_t * const puxStackBuffer, //任务栈起始地址 StaticTask_t * const pxTaskBuffer ) /*lint !e971 Unqualified char types are allowed for strings and single characters only. */ 任务控制块地址
定义就绪列表,任务创建好,需要把任务添加到就绪列表中,表示任务已经就绪,系统随时可以调度。就绪列表实际上就是一个List_t类型的数组。数组的下标对应任务的优先级,同一优先级的任务插入就绪队列中的同一条链表中。
将任务插入就序列表,TCB里面有一个xStateListItem成员,我们将任务插入就序列表中,就是通过将TCB中的该节点插入就序列表来实现的。
实现调度器,主要功能就是实现任务的切换,即从就序列表里面找到优先级最高的任务执行,
vTaskStartScheduler() /* 启动FreeRTOS调度程序运行。 通常,在调度程序启动之前,将执行main()(或main()调用的函数)。 启动调度程序后,只会执行任务和中断。 启动调度程序会导致在调度程序处于“初始化”状态时创建的优先级最高的任务进入“运行”状态。 */