1.列表
- 列表是FreeRTOSde中的一個數據結構,概念上和鏈表雷士,列表被用來跟蹤FreeRTOS中的任務,與列表相關的全放在list.c和list.h中,在list.h中定義了一個結構體如下:
typedef struct xLIST { listFIRST_LIST_INTEGRITY_CHECK_VALUE //用來檢查列表的完整性 configLIST_VOLATILE UBaseType_t uxNumberOfItems; //用來記錄列表中列表項的數量 ListItem_t * configLIST_VOLATILE pxIndex; //用來記錄當前列表項索引號,用於遍歷列表 MiniListItem_t xListEnd; //列表中最后一個列表項,用來表示列表結束,,這是一個mini列表項 listSECOND_LIST_INTEGRITY_CHECK_VALUE //用來檢查列表的完整性 } List_t;
2.列表項
- 列表項就是存放在列表中的項目,FreeRTOS提供了兩種列表項:列表項和迷你列表項,定義在list.h文件中;
- 列表項,跟雙鏈表相似
struct xLIST_ITEM { listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE //檢查列表的完整性 configLIST_VOLATILE TickType_t xItemValue; //列表項值 struct xLIST_ITEM * configLIST_VOLATILE pxNext; //pxNext指向下一個列表項 struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; //pxPrevious指向前一個列表項 void * pvOwner; //記錄此列表項歸誰擁有,通常是任務控制塊 void * configLIST_VOLATILE pvContainer; //用來記錄此列表項歸哪個列表 listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE //檢查列表的完整性 }; typedef struct xLIST_ITEM ListItem_t;
- 迷你列表項,定義在list.h文件中,如下:
struct xMINI_LIST_ITEM { listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE //檢查迷你列表項的完整性 configLIST_VOLATILE TickType_t xItemValue; //記錄列表項的值 struct xLIST_ITEM * configLIST_VOLATILE pxNext; //pxNext指向下一個列表項 struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; //pxPrevious指向上一個列表項 }; typedef struct xMINI_LIST_ITEM MiniListItem_t;
- 列表項和迷你列表項的區別:迷你列表項別列表項少了幾個成員變量;在有些情況下我們不需要列表項這么全的功能,可能只需其中的幾個成員變量,如果此時使用列表項的話會造成內存浪費;
3.列表初始化
- 列表的初始化其實是初始化列表結構體List_t中的各個成員變量,列表通過vListInitialse()來完成,定於於list.c中
void vListInitialise( List_t * const pxList ) { pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); //xListEnd用來表示列表的末尾,pxIndex表示列表項的索引號 pxList->xListEnd.xItemValue = portMAX_DELAY; //xListEnd根據MCU不同,值也不同,stm32為32位,所以 XListEnd為oxffffffffUL pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); //初始化列表項xListEnd的pxNext變量 pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );//初始化列表項xListEnd的pxPrevious變量,指向xListEnd自身 pxList->uxNumberOfItems = ( UBaseType_t ) 0U; //此時沒有其他列表項,因此值為0(這里沒有算xListEnd) listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ); //初始化列表項中用於完整性檢查的字段,不同MCU值不同,32位系統為0x5a5a5a5aUL listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ); //初始化列表項中用於完整性檢查的字段,不同MCU值不同,32位系統為0x5a5a5a5aUL }
4.列表項初始化
- 列表項的初始化是通過vListInitialiseItem()來完成,定於於list.c中
void vListInitialiseItem( ListItem_t * const pxItem ) { pxItem->pvContainer = NULL; listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ); listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );}
- 列表項的初始化比較簡單,只需要將pvContainer的初始值設為NULL,並且給完整性檢查的變量賦值即可;
5.列表項插入
- 列表項插入分為:頭插入和尾插入。
頭插入
- 通過函數VListInert()來完成,函數原型為:
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) //pxList:需要插入的列表, pxNewListItem:需要插入的列表項
- 列表項的插入過程如圖所示:
尾插入
- 通過函數vListInsertEnd()來實現,函數原型為:
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) //pxList:列表項要插入的列表, pxNewListItem:要插入的列表項
- 尾插入過程如下圖所示:
6.列表項的刪除
- 列表項的刪除是通過uxListRemove()函數來完成的,函數原型為:
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) //pxItemToRemove:要刪除的列表項
7.列表的遍歷
- 列表的遍歷是通過listGET_OWNER_OF_NEXT_ENTRY()函數來實現的,每調用一次這個函數,列表的pxIndex變量就會指向下一個列表項,並返回這個列表項的pxOwner變量值,函數原型如下:
//pxTCB:用來保存pxIndex所指向的列表項的pvOwner變量值 //pxList:變量指向下一個列表項 #define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )
8.程序驗證
- 部分程序如下所示:
//list_task 任務 void list_task(void *pvParameters); // 任務函數 #define list_task_zise 300 // 任務堆棧的大小 #define list_task_prio 3 // 任務優先級 TaskHandle_t list_task_handler; // 任務句柄 // 定義一個列表和一個列表項 List_t test_list; //定義一個列表 ListItem_t test_listItem1; //定義一個列表項test_listItem1 ListItem_t test_listItem2; //定義一個列表項test_listItem2 ListItem_t test_listItem3; //定義一個列表項test_listItem3 void start_task( void * pvParameters ) { taskENTER_CRITICAL(); // 創建臨界區 // 創建led1任務 xTaskCreate((TaskFunction_t )led1_task, (const char * )"led1_task", (uint16_t )start_task_zise, (void * )NULL, (UBaseType_t )led1_task_prio, (TaskHandle_t * )&led1_task_handler); // 創建led2任務 xTaskCreate((TaskFunction_t )list_task, (const char * )"list_task", (uint16_t )list_task_zise, (void * )NULL, (UBaseType_t )list_task_prio, (TaskHandle_t * )&list_task_handler); vTaskDelete(start_task_handler); //刪除開始任務 taskEXIT_CRITICAL(); // 退出臨界區 } //list任務函數 void list_task( void * pvParameters ) { vListInitialise(&test_list); //初始化列表 vListInitialiseItem(&test_listItem1); //初始化列表項 vListInitialiseItem(&test_listItem2); //初始化列表項 vListInitialiseItem(&test_listItem3); //初始化列表項 test_listItem1.xItemValue = 40; //設置test_listItem1列表項值為40 test_listItem2.xItemValue = 50; //設置test_listItem2列表項值為50 test_listItem3.xItemValue = 60; //設置test_listItem3列表項值為60 // 打印列表和其他列表項的地址 printf("/*******************列表和列表項地址*******************/\r\n"); printf("項目 地址 \r\n"); printf("test_list %#x \r\n",(int)&test_list); printf("test_list->pxIndex %#x \r\n",(int)test_list.pxIndex); printf("test_list->xListEnd %#x \r\n",(int)(&test_list.xListEnd)); printf("test_listItem1 %#x \r\n",(int)&test_listItem1); printf("test_listItem2 %#x \r\n",(int)&test_listItem2); printf("test_listItem3 %#x \r\n",(int)&test_listItem3); printf("/************************結束**************************/\r\n\r\n"); vListInsert(&test_list, &test_listItem1); //插入列表項test_listItem1 vListInsert(&test_list, &test_listItem2); //插入列表項test_listItem2 vListInsert(&test_list,&test_listItem3); //插入列表項test_listItem3 printf("/******************添加列表項test_listItem123*****************/\r\n"); printf("項目 地址 \r\n"); printf("test_list->xListEnd->pxNext %#x \r\n",(int)(test_list.xListEnd.pxNext)); printf("test_listItem1->pxNext %#x \r\n",(int)(test_listItem1.pxNext)); printf("test_listItem2->pxNext %#x \r\n",(int)(test_listItem2.pxNext)); printf("test_listItem3->pxNext %#x \r\n",(int)(test_listItem3.pxNext)); printf("/*******************前后向連接分割線********************/\r\n"); printf("test_list->xListEnd->pxPrevious %#x \r\n",(int)(test_list.xListEnd.pxPrevious)); printf("test_listItem1->pxPrevious %#x \r\n",(int)(test_listItem1.pxPrevious)); printf("test_listItem2->pxPrevious %#x \r\n",(int)(test_listItem2.pxPrevious)); printf("test_listItem3->pxPrevious %#x \r\n",(int)(test_listItem3.pxPrevious)); printf("/************************結束**************************/\r\n\r\n"); uxListRemove(&test_listItem2); //刪除列表項test_listItem2 printf("/******************刪除列表項test_listItem2*****************/\r\n"); printf("項目 地址 \r\n"); printf("test_list->xListEnd->pxNext %#x \r\n",(int)(test_list.xListEnd.pxNext)); printf("test_listItem1->pxNext %#x \r\n",(int)(test_listItem1.pxNext)); printf("test_listItem3->pxNext %#x \r\n",(int)(test_listItem3.pxNext)); printf("/*******************前后向連接分割線********************/\r\n"); printf("test_list->xListEnd->pxPrevious %#x \r\n",(int)(test_list.xListEnd.pxPrevious)); printf("test_listItem1->pxPrevious %#x \r\n",(int)(test_listItem1.pxPrevious)); printf("test_listItem3->pxPrevious %#x \r\n",(int)(test_listItem3.pxPrevious)); printf("/************************結束**************************/\r\n\r\n"); test_list.pxIndex=test_list.pxIndex->pxNext; //pxIndex向后移一項,這樣pxIndex就會指向ListItem1。 vListInsertEnd(&test_list,&test_listItem2); //列表末尾添加列表項ListItem2 printf("/******************添加列表項test_listItem2*****************/\r\n"); printf("項目 地址 \r\n"); printf("test_list->xListEnd->pxNext %#x \r\n",(int)(test_list.xListEnd.pxNext)); printf("test_listItem2->pxNext %#x \r\n",(int)(test_listItem2.pxNext)); printf("test_listItem1->pxNext %#x \r\n",(int)(test_listItem1.pxNext)); printf("test_listItem3->pxNext %#x \r\n",(int)(test_listItem3.pxNext)); printf("/*******************前后向連接分割線********************/\r\n"); printf("test_list->xListEnd->pxPrevious %#x \r\n",(int)(test_list.xListEnd.pxPrevious)); printf("test_listItem2->pxPrevious %#x \r\n",(int)(test_listItem2.pxPrevious)); printf("test_listItem1->pxPrevious %#x \r\n",(int)(test_listItem1.pxPrevious)); printf("test_listItem3->pxPrevious %#x \r\n",(int)(test_listItem3.pxPrevious)); printf("/************************結束**************************/\r\n\r\n"); }
- 打印信息為:
/*******************列表和列表項地址*******************/ 項目 地址 test_list 0x200000b4 test_list->pxIndex 0x200000bc test_list->xListEnd 0x200000bc test_listItem1 0x200000c8 test_listItem2 0x200000dc test_listItem3 0x200000f0 /************************結束**************************/ /******************添加列表項test_listItem123*****************/ 項目 地址 test_list->xListEnd->pxNext 0x200000c8 test_listItem1->pxNext 0x200000dc test_listItem2->pxNext 0x200000f0 test_listItem3->pxNext 0x200000bc /*******************前后向連接分割線********************/ test_list->xListEnd->pxPrevious 0x200000f0 test_listItem1->pxPrevious 0x200000bc test_listItem2->pxPrevious 0x200000c8 test_listItem3->pxPrevious 0x200000dc /************************結束**************************/ /******************刪除列表項test_listItem2*****************/ 項目 地址 test_list->xListEnd->pxNext 0x200000c8 test_listItem1->pxNext 0x200000f0 test_listItem3->pxNext 0x200000bc /*******************前后向連接分割線********************/ test_list->xListEnd->pxPrevious 0x200000f0 test_listItem1->pxPrevious 0x200000bc test_listItem3->pxPrevious 0x200000c8 /************************結束**************************/ /******************添加列表項test_listItem2*****************/ 項目 地址 test_list->xListEnd->pxNext 0x200000dc test_listItem2->pxNext 0x200000c8 test_listItem1->pxNext 0x200000f0 test_listItem3->pxNext 0x200000bc /*******************前后向連接分割線********************/ test_list->xListEnd->pxPrevious 0x200000f0 test_listItem2->pxPrevious 0x200000bc test_listItem1->pxPrevious 0x200000dc test_listItem3->pxPrevious 0x200000c8 /************************結束**************************/