目录
列表是 FreeRTOS 中的一个数据结构,概念上和链表有点类似,列表被用来跟踪 FreeRTOS 中的任务。与列表相关的全部东西都在文件 list.c 和 list.h 中。在 list.h 中定义了一个叫 List_t 的结构体,如下:
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE;
configLIST_VOLATILE UBaseType_t uxNumberOfltems;
ListItem_t * configLIST_VOLATILE pxIndex;
MiniListItem_t xListEnd;
listSECOND_LIST_INTEGRITY_CHECK_VALUE
} List_t;
列表项就是存放在列表中的项目,FreeRTOS 提供了两种列表项:列表项和迷你列表项。这两个都在文件 list.h 中有定义,先来看一下列表项,定义如下:
struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
configLIST_VOLATILE TickType_t xItemValue;
struct xLIST_ITEM * configLIST_VOLATILE pxNext;
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
void * pvOwner;
void * configLIST pvContainer;
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE_VOLATILE
};
typedef struct xLIST_ITEM ListItem_t
struct xMINI_LIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
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_t 中的各个成员变量,列表的初始化通过使函数 vListInitialise()来完成,此函数在 list.c 中有定义,函数如下:
void vListInitialise( List_t * const pxList )
{
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );
pxList->xListEnd.xItemValue = portMAX_DELAY;
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );
pxList->uxNumberOfItems = ( UBaseType_t ) 0U;
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}
列表项初始化由函数 vListInitialiseItem()来完成,函数如下:
void vListInitialiseItem( ListItem_t * const pxItem )
{
pxItem->pvContainer = NULL; //初始化pvContainer 为 NULL
//初始化用于完整性检查的变量,如果开启了这个功能的话。
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
}
- 列表项插入
列表项的插入操作通过函数 vListInsert()来完成,函数原型如下:
void vListInsert( List_t * const pxList,ListItem_t * const pxNewListItem )
通过图片来演示一下这个插入过程,向一个空的列表中插入三个列表项,这三个列表项的值分别为 40,60 和 50。
- 插入与删除实验
本实验设计 3 个任务:start_task、task1_task 和 list_task,这三个任务的任务功能如下:
start_task: 用来创建其他 2 个任务。
task1_task:应用任务 1,控制 LED0 闪烁,用来提示系统正在运行。
task2_task: 列表和列表项操作任务,调用列表和列表项相关的 API 函数,并且通过串口输出相应的信息来观察这些 API 函数的运行过程。
任务优先级、堆栈大小和任务句柄等的设置:
#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 LIST_TASK_PRIO 3 //任务优先级
#define LIST_STK_SIZE 128 //任务堆栈大小
TaskHandle_t ListTask_Handler; //任务句柄
void list_task(void *pvParameters); //任务函数
列表和列表项的定义:
main函数:
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组 4
delay_init(168); //初始化延时函数
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 7-1");
LCD_ShowString(30,50,200,16,16,"list and listItem");
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(); //开启任务调度
}
验证:
- 列表 TestList 地址为 b4。
- 列表项 ListItem1、ListItem2 和 ListItem3 的地址分别为 c8、dc 和 f0
- 列表 TestList 的xListEnd 地址为 bc。
- 列表 TestList 的pxIndex 指向地址 bc,而这个地址正是迷你列表项 xListEnd,说明 pxIndex指向 xListEnd,这个和我们分析列表初始化函数 vListInitialise()的时候得到的结果是一致的。
- xListEnd 的 pxNext 指向地址 c8,而 c8 是 ListItem1 的地址,说明 xListEnd 的 pxNext 指向 ListItem1。
- 列表项 ListItem1 的 pxNext 指向地址 bc,而 bc 是 xListEnd 的地址,说明 ListItem1 的pxNext 指向xListEnd。
- xListEnd 的pxPrevious 指向地址c8,而 c8 是ListItem1 的地址,说明 xListEnd 的pxPrevious指向 ListItem2。
- ListItem1 的 pxPrevious 指向地址 bc,bc 是xListEnd 的地址,说明 ListItem1 的 pxPrevious指向 xListEnd。
- xListEnd 的 pxNext 指向 ListItem1。
- ListItem1 的 pxNext 指向 ListItem2。
- ListItem2 的 pxNext 指向 xListEnd。
- 列表项的 pxPrevious 分析过程类似,后面的步骤中就不做分析了,只看 pxNext 成员变量。
- xListEnd 的 pxNext 指向 ListItem1。
- ListItem1 的 pxNext 指向 ListItem3。
- ListItem3 的 pxNext 指向 ListItem2。
- ListItem2 的 pxNext 指向 xListEnd。