FreeRTOS的列表和列表项
列表和列表項(xiàng)
列表
列表是FreeRTOS中的一個(gè)數(shù)據(jù)結(jié)構(gòu),概念上和鏈表有點(diǎn)類型,是一個(gè)循環(huán)雙向鏈表,列表被用來跟蹤FreeRTOS中的任務(wù)。列表的類型是List_T,具體定義如下:
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;- listFIRST_LIST_INTEGRITY_CHECK_VALUE和listSECOND_LIST_INTEGRITY_CHECK_VALUE都是用來檢查列表完整性的,需要將宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 設(shè)置為1,默認(rèn)不開啟。
- uxNumberOfItems:記錄列表項(xiàng)的數(shù)量
- pxIndex:指向當(dāng)前的列表項(xiàng),可用來遍歷列表,類型是ListItem_t *
- xListEnd:作為一個(gè)標(biāo)記,表示列表最后一個(gè)列表項(xiàng),類型是MiniListItem_t 。
列表項(xiàng)
FreeRTOS提供了兩種列表項(xiàng):列表項(xiàng)(ListItem_t 類型)和迷你列表項(xiàng)(MiniListItem_t 類型)。對(duì)于列表項(xiàng),具體定義為:
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. */- listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE檢查列表項(xiàng)完整性
- xItemValue:列表項(xiàng)的值
- pxNext:指向下一個(gè)列表項(xiàng)
- pxPrevious:指向前一個(gè)列表項(xiàng)
- pvOwner:記錄此列表項(xiàng)歸誰擁有,通常是任務(wù)控制塊
- pvContainer:記錄該列表項(xiàng)歸哪個(gè)列表
迷你列表項(xiàng):
struct xMINI_LIST_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;struct xLIST_ITEM * configLIST_VOLATILE pxNext;struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; }; typedef struct xMINI_LIST_ITEM MiniListItem_t;可以看出迷你列表項(xiàng)只是比列表項(xiàng)少了幾個(gè)成員變量,迷你列表項(xiàng)所有的成員變量列表項(xiàng)都有。
對(duì)于列表結(jié)構(gòu)體List_t中的xListEnd是MiniListItem_t類型,表示最后一個(gè)列表項(xiàng),pxIndex是ListItem_t指針類型,指向真正有數(shù)據(jù)的列表項(xiàng)。
列表和列表項(xiàng)初始化
列表初始化
新創(chuàng)建的或者定義的列表需要對(duì)其做初始化處理,列表初始化其實(shí)就是初始化列表結(jié)構(gòu)體List_t中的各個(gè)成員變量,列表的初始化通過函數(shù)vListInitialise()來完成。
void vListInitialise( List_t * const pxList ) {/* The list structure contains a list item which is used to mark theend of the list. To initialise the list the list end is insertedas the only list entry. */pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. *//* The list end value is the highest possible value in the list toensure it remains at the end of the list. */pxList->xListEnd.xItemValue = portMAX_DELAY;/* The list end next and previous pointers point to itself so we knowwhen the list is empty. */pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */pxList->uxNumberOfItems = ( UBaseType_t ) 0U;/* Write known values into the list ifconfigUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ); }函數(shù)的參數(shù)是一個(gè)列表
- pxIndex 指向強(qiáng)制類型轉(zhuǎn)換的xListEnd
- xItemValue 列表項(xiàng)的值為portMAX_DELAY
- pxNext :指向自己
- pxPrevious :指向自己
- uxNumberOfItems :列表中的列表項(xiàng)數(shù)目為0
下圖為初始化后的列表
列表項(xiàng)初始化
void vListInitialiseItem( ListItem_t * const pxItem ) {/* Make sure the list item is not recorded as being on a list. */pxItem->pvContainer = NULL;/* Write known values into the list item ifconfigUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ); }函數(shù)的參數(shù)是一個(gè)列表項(xiàng)指針,只是將列表項(xiàng)的pvContainer初始化為NULL
下圖為列表項(xiàng)初始后的列表項(xiàng)
列表項(xiàng)插入
列表項(xiàng)插入相當(dāng)于和在循環(huán)雙向鏈表中按照數(shù)值的遞增插入數(shù)據(jù)原理是一樣的。
列表項(xiàng)的插入式通過函數(shù)vListInsert來完成的
參數(shù):
- pxList:要插入的列表
- pxNewListItem :要插入的列表項(xiàng)
vListInsert是根據(jù)pxNewListItem 中的成員變量xItemValue的值來決定插入位置。根據(jù)xItemValue的升序方式排序。
具體插入過程如下:
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) { ListItem_t *pxIterator; const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;/* Only effective when configASSERT() is also defined, these tests may catchthe list data structures being overwritten in memory. They will not catchdata errors caused by incorrect configuration or use of FreeRTOS. */listTEST_LIST_INTEGRITY( pxList );listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );/* Insert the new list item into the list, sorted in xItemValue order.If the list already contains a list item with the same item value then thenew list item should be placed after it. This ensures that TCB's which arestored in ready lists (all of which have the same xItemValue value) get ashare of the CPU. However, if the xItemValue is the same as the back markerthe iteration loop below will not end. Therefore the value is checkedfirst, and the algorithm slightly modified if necessary. */if( xValueOfInsertion == portMAX_DELAY ){pxIterator = pxList->xListEnd.pxPrevious;}else{/* *** NOTE ***********************************************************If you find your application is crashing here then likely causes arelisted below. In addition see http://www.freertos.org/FAQHelp.html formore tips, and ensure configASSERT() is defined!http://www.freertos.org/a00110.html#configASSERT1) Stack overflow -see http://www.freertos.org/Stacks-and-stack-overflow-checking.html2) Incorrect interrupt priority assignment, especially on Cortex-Mparts where numerically high priority values denote low actualinterrupt priorities, which can seem counter intuitive. Seehttp://www.freertos.org/RTOS-Cortex-M3-M4.html and the definitionof configMAX_SYSCALL_INTERRUPT_PRIORITY onhttp://www.freertos.org/a00110.html3) Calling an API function from within a critical section or whenthe scheduler is suspended, or calling an API function that doesnot end in "FromISR" from an interrupt.4) Using a queue or semaphore before it has been initialised orbefore the scheduler has been started (are interrupts firingbefore vTaskStartScheduler() has been called?).**********************************************************************/for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) /*lint !e826 !e740 The mini list structure is used as the list end to save RAM. This is checked and valid. */{/* There is nothing to do here, just iterating to the wantedinsertion position. */}}pxNewListItem->pxNext = pxIterator->pxNext;pxNewListItem->pxNext->pxPrevious = pxNewListItem;pxNewListItem->pxPrevious = pxIterator;pxIterator->pxNext = pxNewListItem;/* Remember which list the item is in. This allows fast removal of theitem later. */pxNewListItem->pvContainer = ( void * ) pxList;( pxList->uxNumberOfItems )++; }列表項(xiàng)插入過程
一個(gè)初始化的空列表如下:
插入值為40的列表項(xiàng)后
插入值60的列表項(xiàng)
插入50后的列表項(xiàng)為
列表末尾插入
末尾插入就不根據(jù)xItemValue了,直接插入末端。原理和在循環(huán)雙向鏈表的末尾插入數(shù)據(jù)是一樣的
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )列表項(xiàng)的刪除
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove );- pxItemToRemove :要?jiǎng)h除的列表項(xiàng)
列表的遍歷
列表結(jié)構(gòu)體中的pxIndex是用來遍歷鏈表的,在說列表項(xiàng)插入的時(shí)候,也用到了列表的遍歷,具體代碼如下:
for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext )FreeRTOS提供了一個(gè)函數(shù)來完成列表的遍歷,這個(gè)函數(shù)是listGET_OWNER_OF_NEXT_ENTRY。每調(diào)用一次該函數(shù)pxIndex變量就會(huì)指向下一個(gè)列表項(xiàng),并且返回這個(gè)列表項(xiàng)的pxOwner變量值
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList ) \ { \ List_t * const pxConstList = ( pxList ); \/* Increment the index to the next item and return the item, ensuring */ \/* we don't return the marker used at the end of the list. */ \( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \{ \( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \} \( pxTCB ) = ( pxConstList )->pxIndex->pvOwner; \ }pxTCB用來保存pxIndex所指向的列表項(xiàng)pvOwner變量值。pxList是要遍歷的列表
將pxIndex指向下一個(gè)列表項(xiàng)
如果指向的列表項(xiàng)是xListEnd ,表示已經(jīng)到了列表末尾,然后跳過末尾,再一次重新指向列表的第一個(gè)列表項(xiàng)。
if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \{ \( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext; \}將pxIndex所指向的新列表項(xiàng)的pvOwner賦值給pxTCB
( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;列表項(xiàng)的插入和刪除實(shí)驗(yàn)
實(shí)驗(yàn)設(shè)計(jì),三個(gè)任務(wù):
start_task:創(chuàng)建其他兩個(gè)任務(wù)
task1_task:應(yīng)用任務(wù)1,控制LED0閃爍,用來提示系統(tǒng)正在運(yùn)行
task2_task:列表和列表項(xiàng)操作任務(wù),調(diào)用列表和列表相關(guān)的API,并且通過串口輸出相應(yīng)的信息來觀察這些API函數(shù)的運(yùn)行過程。
任務(wù)設(shè)置
#define START_STACK_SIZE 128 #define START_TASK_PIO 1 TaskHandle_t Start_Handler; void start_task(void * pvParameters);#define TASK1_STACK_SIZE 128 #define TASK1_TASK_PIO 2 TaskHandle_t Task1_Handler; void task1_task(void * pvParameters);#define TASK2_STACK_SIZE 128 #define TASK2_TASK_PIO 3 TaskHandle_t Task2_Handler; void task2_task(void * pvParameters);列表項(xiàng)和列表的定義
//定義一個(gè)測(cè)試用的列表和是哪個(gè)列表項(xiàng) List_t TestList; ListItem_t ListItem1; ListItem_t ListItem2; ListItem_t ListItem3;main函數(shù)
int main(void) {HAL_Init(); //初始化HAL庫(kù) Stm32_Clock_Init(360,25,2,8); //設(shè)置時(shí)鐘,180Mhzdelay_init(180); //初始化延時(shí)函數(shù)uart_init(115200); //初始化串口LED_Init(); //初始化LED KEY_Init(); //初始化按鍵SDRAM_Init(); //初始化SDRAMLCD_Init(); //初始化LCDPOINT_COLOR = RED;LCD_ShowString(30,10,200,16,16,"Apollo STM32F4/F7"); 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/10/9");//創(chuàng)建開始任務(wù)xTaskCreate(start_task,"start_task",START_STACK_SIZE,NULL,START_TASK_PIO,&Start_Handler);vTaskStartScheduler(); }任務(wù)函數(shù)
//開始任務(wù)任務(wù)函數(shù) void start_task(void * pvParameters) {taskENTER_CRITICAL(); //進(jìn)入臨界區(qū)//創(chuàng)建任務(wù)xTaskCreate(task1_task,"task1_task",TASK1_STACK_SIZE,NULL,TASK1_TASK_PIO,&Task1_Handler);xTaskCreate(task2_task,"task1_task",TASK2_STACK_SIZE,NULL,TASK2_TASK_PIO,&Task2_Handler);vTaskDelete(Start_Handler);//退出臨界區(qū)taskEXIT_CRITICAL(); }//task1任務(wù)函數(shù) void task1_task(void * pvParameters) {while(1){LED0 = !LED0;vTaskDelay(500);} } //list任務(wù)函數(shù) void task2_task(void * pvParameters) {//初始化列表和列表項(xiàng)vListInitialise(&TestList);vListInitialiseItem(&ListItem1);vListInitialiseItem(&ListItem2);vListInitialiseItem(&ListItem3);ListItem1.xItemValue=40;ListItem2.xItemValue = 60;ListItem3.xItemValue=50;//第二步:打印列表和其他列表項(xiàng)的地址printf("/*******************列表和列表項(xiàng)地址*******************/\r\n");printf("項(xiàng)目 地址 \r\n");printf("TestList %#x \r\n",(int)&TestList);printf("TestList->pxIndex %#x \r\n",(int)TestList.pxIndex);printf("TestList->xListEnd %#x \r\n",(int)(&TestList.xListEnd));printf("ListItem1 %#x \r\n",(int)&ListItem1);printf("ListItem2 %#x \r\n",(int)&ListItem2);printf("ListItem3 %#x \r\n",(int)&ListItem3);printf("/************************結(jié)束**************************/\r\n");printf("按下KEY_UP鍵繼續(xù)!\r\n\r\n\r\n");while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10); //第三步:向列表TestList添加列表項(xiàng)ListItem1,并通過串口打印所有//列表項(xiàng)中成員變量pxNext和pxPrevious的值,通過這兩個(gè)值觀察列表//項(xiàng)在列表中的連接情況。vListInsert(&TestList,&ListItem1); //插入列表項(xiàng)ListItem1printf("/******************添加列表項(xiàng)ListItem1*****************/\r\n");printf("項(xiàng)目 地址 \r\n");printf("TestList->xListEnd->pxNext %#x \r\n",(int)(TestList.xListEnd.pxNext));printf("ListItem1->pxNext %#x \r\n",(int)(ListItem1.pxNext));printf("/*******************前后向連接分割線********************/\r\n");printf("TestList->xListEnd->pxPrevious %#x \r\n",(int)(TestList.xListEnd.pxPrevious));printf("ListItem1->pxPrevious %#x \r\n",(int)(ListItem1.pxPrevious));printf("/************************結(jié)束**************************/\r\n");printf("按下KEY_UP鍵繼續(xù)!\r\n\r\n\r\n");while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10); //第四步:向列表TestList添加列表項(xiàng)ListItem2,并通過串口打印所有//列表項(xiàng)中成員變量pxNext和pxPrevious的值,通過這兩個(gè)值觀察列表//項(xiàng)在列表中的連接情況。vListInsert(&TestList,&ListItem2); //插入列表項(xiàng)ListItem2printf("/******************添加列表項(xiàng)ListItem2*****************/\r\n");printf("項(xiàng)目 地址 \r\n");printf("TestList->xListEnd->pxNext %#x \r\n",(int)(TestList.xListEnd.pxNext));printf("ListItem1->pxNext %#x \r\n",(int)(ListItem1.pxNext));printf("ListItem2->pxNext %#x \r\n",(int)(ListItem2.pxNext));printf("/*******************前后向連接分割線********************/\r\n");printf("TestList->xListEnd->pxPrevious %#x \r\n",(int)(TestList.xListEnd.pxPrevious));printf("ListItem1->pxPrevious %#x \r\n",(int)(ListItem1.pxPrevious));printf("ListItem2->pxPrevious %#x \r\n",(int)(ListItem2.pxPrevious));printf("/************************結(jié)束**************************/\r\n");printf("按下KEY_UP鍵繼續(xù)!\r\n\r\n\r\n");while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10); //第五步:向列表TestList添加列表項(xiàng)ListItem3,并通過串口打印所有//列表項(xiàng)中成員變量pxNext和pxPrevious的值,通過這兩個(gè)值觀察列表//項(xiàng)在列表中的連接情況。vListInsert(&TestList,&ListItem3); //插入列表項(xiàng)ListItem3printf("/******************添加列表項(xiàng)ListItem3*****************/\r\n");printf("項(xiàng)目 地址 \r\n");printf("TestList->xListEnd->pxNext %#x \r\n",(int)(TestList.xListEnd.pxNext));printf("ListItem1->pxNext %#x \r\n",(int)(ListItem1.pxNext));printf("ListItem3->pxNext %#x \r\n",(int)(ListItem3.pxNext));printf("ListItem2->pxNext %#x \r\n",(int)(ListItem2.pxNext));printf("/*******************前后向連接分割線********************/\r\n");printf("TestList->xListEnd->pxPrevious %#x \r\n",(int)(TestList.xListEnd.pxPrevious));printf("ListItem1->pxPrevious %#x \r\n",(int)(ListItem1.pxPrevious));printf("ListItem3->pxPrevious %#x \r\n",(int)(ListItem3.pxPrevious));printf("ListItem2->pxPrevious %#x \r\n",(int)(ListItem2.pxPrevious));printf("/************************結(jié)束**************************/\r\n");printf("按下KEY_UP鍵繼續(xù)!\r\n\r\n\r\n");while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10); //第六步:刪除ListItem2,并通過串口打印所有列表項(xiàng)中成員變量pxNext和//pxPrevious的值,通過這兩個(gè)值觀察列表項(xiàng)在列表中的連接情況。uxListRemove(&ListItem2); //刪除ListItem2printf("/******************刪除列表項(xiàng)ListItem2*****************/\r\n");printf("項(xiàng)目 地址 \r\n");printf("TestList->xListEnd->pxNext %#x \r\n",(int)(TestList.xListEnd.pxNext));printf("ListItem1->pxNext %#x \r\n",(int)(ListItem1.pxNext));printf("ListItem3->pxNext %#x \r\n",(int)(ListItem3.pxNext));printf("/*******************前后向連接分割線********************/\r\n");printf("TestList->xListEnd->pxPrevious %#x \r\n",(int)(TestList.xListEnd.pxPrevious));printf("ListItem1->pxPrevious %#x \r\n",(int)(ListItem1.pxPrevious));printf("ListItem3->pxPrevious %#x \r\n",(int)(ListItem3.pxPrevious));printf("/************************結(jié)束**************************/\r\n");printf("按下KEY_UP鍵繼續(xù)!\r\n\r\n\r\n");while(KEY_Scan(0)!=WKUP_PRES) delay_ms(10); //第七步:刪除ListItem2,并通過串口打印所有列表項(xiàng)中成員變量pxNext和//pxPrevious的值,通過這兩個(gè)值觀察列表項(xiàng)在列表中的連接情況。TestList.pxIndex=TestList.pxIndex->pxNext; //pxIndex向后移一項(xiàng),這樣pxIndex就會(huì)指向ListItem1。vListInsertEnd(&TestList,&ListItem2); //列表末尾添加列表項(xiàng)ListItem2printf("/***************在末尾添加列表項(xiàng)ListItem2***************/\r\n");printf("項(xiàng)目 地址 \r\n");printf("TestList->pxIndex %#x \r\n",(int)TestList.pxIndex);printf("TestList->xListEnd->pxNext %#x \r\n",(int)(TestList.xListEnd.pxNext));printf("ListItem2->pxNext %#x \r\n",(int)(ListItem2.pxNext));printf("ListItem1->pxNext %#x \r\n",(int)(ListItem1.pxNext));printf("ListItem3->pxNext %#x \r\n",(int)(ListItem3.pxNext));printf("/*******************前后向連接分割線********************/\r\n");printf("TestList->xListEnd->pxPrevious %#x \r\n",(int)(TestList.xListEnd.pxPrevious));printf("ListItem2->pxPrevious %#x \r\n",(int)(ListItem2.pxPrevious));printf("ListItem1->pxPrevious %#x \r\n",(int)(ListItem1.pxPrevious));printf("ListItem3->pxPrevious %#x \r\n",(int)(ListItem3.pxPrevious));printf("/************************結(jié)束**************************/\r\n\r\n\r\n");while(1){LED1=!LED1;vTaskDelay(1000); //延時(shí)1s,也就是1000個(gè)時(shí)鐘節(jié)拍 } }總結(jié)
以上是生活随笔為你收集整理的FreeRTOS的列表和列表项的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: FreeRTOS中断配置与临界段
- 下一篇: FreeRTOS时间管理