又黄又粗又爽免费观看,色吧电影网,军人武警gay男同gvus69,精品久久久久久久久中文字幕

position>home>Softball

FreeRTOS及其應用,萬字長文,基礎入門

[導讀]嵌入式系統不只是及其基礎ARM+Linux,不是應用只有安卓,凡是長文電子產品都可稱為嵌入式系統。物聯網行業的入門興起,也提升了FreeRTOS市場占有率。及其基礎本文就是應用介紹FreeRTOS基礎及其應用,只是長文個人整理,可能存在問題,入門其目的及其基礎只是簡要介紹系統的基礎,只能作為入門資料。應用

微信公眾號:嵌入式系統

FreeRTOS及其應用,萬字長文,基礎入門

嵌入式系統不只是長文ARM+Linux,不是入門只有安卓,凡是及其基礎電子產品都可稱為嵌入式系統。物聯網行業的應用興起,也提升了FreeRTOS市場占有率。長文本文就是介紹FreeRTOS基礎及其應用,只是個人整理,可能存在問題,其目的只是簡要介紹系統的基礎,只能作為入門資料。

目錄

一、 為什么要學習RTOS 

二、 操作系統基礎

三、 初識 FreeRTOS

四、 任務

五、 隊列 

六、 軟件定時器

七、 信號量

八、 事件 

九、 任務通知

十、 內存管理

十一、 通用接口

一、 為什么要學習 RTOS

進入嵌入式這個領域,入門首先接觸的是單片機編程,尤其是C51 單片機來,基礎的單片機編程通常都是指裸機編程,即不加入任何 RTOS(Real Time Operating System 實時操作系統)。常用的有國外的FreeRTOS、μC/OS、RTX 和國內的 RT-thread、Huawei LiteOS 和 AliOS-Things 等,其中開源且免費的 FreeRTOS 的市場占有率較高。

1.1 前后臺系統

在裸機系統中,所有的操作都是在一個無限的大循環里面實現,支持中斷檢測。外部中斷緊急事件在中斷里面標記或者響應,中斷服務稱為前臺,main 函數里面的while(1)無限循環稱為后臺,按順序處理業務功能,以及中斷標記的可執行的事件。小型的電子產品用的都是裸機系統,而且也能夠滿足需求。

1.2 多任務系統

多任務系統的事件響應也是在中斷中完成的,但是事件的處理是在任務中完成的。如果事件對應的任務的優先級足夠高,中斷對應的事件會立刻執行。相比前后臺系統,多任務系統的實時性又被提高了。

在多任務系統中,根據程序的功能,把這個程序主體分割成一個個獨立的,無限循環且不能返回的子程序,稱之為任務。每個任務都是獨立的,互不干擾的,且具備自身的優先級,它由操作系統調度管理。加入操作系統后,開發人員不需要關注每個功能模塊之間的沖突,重心放在子程序的實現。缺點是整個系統隨之帶來的額外RAM開銷,但對目前的單片機的來影響不大。

1.3 學習RTOS的意義

學習 RTOS,一是項目需要,隨著產品要實現的功能越來越多,單純的裸機系統已經不能完美地解決問題,反而會使編程變得更加復雜,如果想降低編程的難度,就必須引入 RTOS實現多任務管理。二是技能需要,掌握操作系統,和基于RTOS的編程,實現更好的職業規劃,對個人發展尤其是錢途是必不可少的。

以前一直覺得學操作系統就必須是linux,實際每個系統都有其應用場景,對于物聯網行業,殺雞焉用牛刀,小而美,且應用廣泛的FreeRTOS 是首選。有一個操作系統的基礎,即使后續基于其他系統開發軟件,也可觸類旁通,對新技術快速入門。目前接觸的幾款芯片都是基于FreeRTOS。

如何學習RTOS?最簡單的就是在別人移植好的系統之上,看看 RTOS 里面的 API 使用說明,然后調用這些 API 實現自己想要的功能即可。完全不用關心底層的移植,這是最簡單快速的入門方法。這種學習方式,如果是做產品,可以快速的實現功能,弊端是當程序出現問題的時候,如果對RTOS不夠了解,會導致調試困難,無從下手。

各種RTOS內核實現方式都差不多,我們只需要深入學習其中一款就行。萬變不離其宗,正如掌握了C51基礎,后續換其他型號或者更高級的ARM單片機,在原理和方法上,都是有借鑒意義,可以比較快的熟悉并掌握新單片機的使用。

二、 操作系統基礎

2.1 鏈表

鏈表作為 C 語言中一種基礎的數據結構,在平時寫程序的時候用的并不多,但在操作系統里面使用的非常多。FreeRTOS 中存在著大量的基礎數據結構鏈表和鏈表項的操作(list 和 list item)。FreeRTOS 中與鏈表相關的操作均在 list.h 和 list.c 這兩個文件中實現。

鏈表比數組,最大優勢是占用的內存空間可以隨著需求擴大或縮小,動態調整。實際FreeRTOS中各種任務的記錄都是依靠鏈表動態管理,具體的可以參考源碼的任務控制塊tskTCB。任務切換狀態,就是將對應的鏈表進行操作,鏈表操作涉及創建和插入、刪除和查找。

2.2 隊列

隊列是一種只允許在表的前端(front)進行刪除操作,而在表的后端(rear)進行插入操作。隊尾放入數據,對頭擠出。先進先出,稱為FIFO

2.3 任務

在裸機系統中,系統的主體就是 main 函數里面順序執行的無限循環,這個無限循環里面 CPU 按照順序完成各種事情。在多任務系統中,根據功能的不同,把整個系統分割成一個個獨立的且無法返回的函數,這個函數我們稱為任務。系統中的每一任務都有多種運行狀態。系統初始化完成后,創建的任務就可以在系統中競爭一定的資源,由內核進行調度。? 就緒(Ready):該任務在就緒列表中,就緒的任務已經具備執行的能力,只等待調度器進行調度,新創建的任務會初始化為就緒態。 

? 運行(Running):該狀態表明任務正在執行,此時它占用處理器,調度器選擇運行的永遠是處于最高優先級的就緒態任務。 

? 阻塞(Blocked):任務當前正在等待某個事件,比如信號量或外部中斷。 

? 掛起態(Suspended):處于掛起態的任務對調度器而言是不可見的。

掛起態與阻塞態的區別,當任務有較長的時間不允許運行的時候,我們可以掛起任務,這樣子調度器就不會管這個任務的任何信息,直到調用恢復任務的 接口;而任務處于阻塞態的時候,系統還需要判斷阻塞態的任務是否超時,是否可以解除阻塞。

各任務運行時使用消息、信號量等方式進行通信,不能是全局變量。任務通常會運行在一個死循環中,不會退出,如果不再需要,可以調用刪除任務。

2.4 臨界區

臨界區就是一段在執行的時候不能被中斷的代碼段。在多任務操作系統里面,對全局變量的操作不能被打斷,不能執行到一半就被其他任務再次操作。一般被打斷,原因就是系統調度或外部中斷。對臨界區的保護控制,歸根到底就是對系統中斷的使能控制。在使用臨界區時,關閉中斷響應,對部分優先級的中斷進行屏蔽,因此臨界區不允許運行時間過長。為了對臨界區進行控制,就需要使用信號量通信,實現同步或互斥操作。

三、 初識 FreeRTOS

3.1 FreeRTOS源碼

FreeRTOS 由美國的 Richard Barry 于 2003 年發布, 2018 年被亞馬遜收購,改名為 AWS FreeRTOS,版本號升級為 V10,支持MIT開源協議,亞馬遜收購 FreeRTOS 也是為了進入物聯網和人工智能,新版本增加了物聯網行業的網絡協議等功能。

FreeRTOS 是開源免費的,可從官網 www.freertos.org 下載源碼和說明手冊。例如展銳的UIS8910使用的是V10。以FreeRTOSv10.4.1為例,包含 Demo 例程,Source內核的源碼,License許可文件。

3.1.1 Source 文件夾

FreeRTOS/ Source 文件夾下的文件:

包括FreeRTOS 的通用的頭文件include和 C 文件,包括任務、隊列、定時器等,適用于各種編譯器和處理器,是通用的。

需要特殊處理適配的在portblle文件夾,其下內容與編譯器和處理器相關, FreeRTOS 要想運行在一個單片機上面,它們就必須關聯在一起,通常由匯編和 C 聯合編寫。通常難度比較高,不過一般芯片原廠提供移植好的接口文件。這里不介紹移植的方法,因為自己也不明白。

Portblle/MemMang 文件夾下存放的是跟內存管理相關的,總共有五個 heap 文件,有5種內存動態分配方式,一般物聯網產品選用 heap4.c 。

3.1.2 Demo 文件夾

里面包含了 FreeRTOS 官方為各個單片機移植好的工程代碼,FreeRTOS 為了推廣自己,會給針對不同半導體廠商的評估板實現基礎功能范例, Demo下就是參考范例。

3.1.3 FreeRTOSConfig.h配置

FreeRTOSConfig.h頭文件對FreeRTOS 所需的功能的宏均做了定義,需要根據應用情況配置合適的參數,其作用類似MTK功能機平臺的主mak文件,部分定義如下:

1. #define configUSE_PREEMPTION            1  
2. #define configUSE_IDLE_HOOK             0  
3. #define configUSE_TICK_HOOK             0  
4. #define configCPU_CLOCK_HZ              ( SystemCoreClock )  
5. #define configTICK_RATE_HZ              ( ( TickType_t ) 1000 )  

例如系統時鐘tick等參數在就這個文件配置,具體作用可以看注釋。一般情況下使用SDK不需要改動,特殊情況下咨詢原廠再調整。

3.2 FreeRTOS 編碼規范

接觸一個新平臺或者SDK,明白它的編碼規范,文件作用,可以提高源碼閱讀效率,快速熟悉其內部實現。

3.2.1 數據類型

FreeRTOS針對不同的處理器,對標準C的數據類型進行了重定義。

1. #define portCHAR        char  
2. #define portFLOAT       float  
3. #define portDOUBLE      double  
4. #define portLONG        long  
5. #define portSHORT       short  
6. #define portSTACK_TYPE  uint32_t  
7. #define portBASE_TYPE   long  

應用編碼中,推薦使用的是下面這種風格。

1. typedef int int32_t;  
2. typedef short int16_t;  
3. typedef char int8_t;  
4. typedef unsigned int uint32_t;  
5. typedef unsigned short uint16_t;  
6. typedef unsigned char uint8_t;

3.2.2 變量名

FreeRTOS 中,定義變量的時候往往會把變量的類型當作前綴,好處看到就知道其類型。 

char 型變量的前綴是 c 

short 型變量的前綴是 s 

long 型變量的前綴是 l 

復雜的結構體,句柄等定義的變量名的前綴是 x 

變量是無符號型的再加前綴 u,是指針變量則加前綴 p

3.2.3 函數名

函數名包含了函數返回值的類型、函數所在的文件名和函數的功能,如果是私有的函數則會加一個 prv(private)的前綴。 

例如vTaskPrioritySet()函數的返回值為 void 型,在 task.c 這個文件中定義。

3.2.4 宏

宏內容是由大寫字母表示,前綴是小寫字母,表示該宏在哪個頭文件定義,如:

1. #define taskYIELD()                 portYIELD()  

表示該宏是在task.h。

3.2.5 個人解讀

1、編碼不缺編碼規范,但是實際使用中很難完全依照標準執行,即使freeRTOS源碼也是如此。 

2、關于函數或者宏定義中帶文件名的作用,使用Source Insight 編輯代碼,該前綴的意義不大。 

3、規則是活的,只要所有人都按一個規則執行,它就是標準。

3.3 FreeRTOS應用開發

關于freeRTOS的應用開發,主要是任務的創建和調度,任務間的通信與同步,涉及隊列、信號量等操作系統通用接口。結合應用需求,涉及定時器、延時、中斷控制等接口。

特別說明,有些功能的實現方式有多種形式,只針對常用方式進行說明,例如task的創建,只說明動態創建方式,因為很少使用靜態方式。

四、 任務

4.1 創建任務

xTaskCreate()使用動態內存的方式創建一個任務。

1. ret = xTaskCreate((TaskFunction_t) master_task_main,  /* 任務入口函數 */(1)
2.                   “MASTER”,   /* 任務名字 */(2)
3.                   64*1024,   /* 任務棧大小 */(3)
4.                   NULL,    ,/* 任務入口函數參數 */(4)
5.                   TASK_PRIORITY_NORMAL,  /* 任務的優先級 */(5)
6.                   &task_master_handler);  /* 任務控制塊指針 */(6)

創建任務就是軟件運行時的一個while(1)的入口,一般閱讀其他代碼,找到這個函數,再跟蹤到任務入口函數,學習基于freeRTOS系統的代碼,首先就是找到main和這個接口。

(1):任務入口函數,即任務函數的名稱,需要我們自己定義并且實現。

 (2):任務名字,字符串形式,最大長度由 FreeRTOSConfig.h 中定義的 configMAX_TASK_NAME_LEN 宏指定,多余部分會被自動截掉,只是方便調試。

(3):任務堆棧大小,單位為字, 4 個字節,這個要注意,否則系統內存緊缺。

(4):任務入口函數形參,不用的時候配置為 0 或者NULL 即可。


(5) :任務的優先級,在 FreeRTOS 中,數值越大優先級越高,0 代表最低優先級。基于其SDK開發,可將自定義的所有業務功能task設為同一個優先級,按時間片輪詢調度。

(6):任務控制塊指針,使用動態內存的時候,任務創建函數 xTaskCreate()會返回一個指針指向任務控制塊,也可以設為NULL,因為任務句柄后期可以不使用。

4.2 開啟調度

當任務創建成功后處于就緒狀態(Ready),在就緒態的任務可以參與操作系統的調度。操作系統任務調度器只啟動一次,之后就不會再次執行了,FreeRTOS 中啟動任務調度器的函數是 vTaskStartScheduler(),并且啟動任務調度器的時候就不會返回,從此任務管理都由FreeRTOS 管理,此時才是真正進入實時操作系統中的第一步。

vTaskStartScheduler開啟調度時,順便會創建空閑任務和定時器任務。

FreeRTOS 為了任務啟動和任務切換使用了三個異常:SVC、PendSV 和SysTick。

SVC(系統服務調用,亦簡稱系統調用)用于任務啟動。

PendSV(可掛起系統調用)用于完成任務切換,它是可以像普通的中斷一樣被掛起的,它的最大特性是如果當前有優先級比它高的中斷在運行,PendSV會延遲執行,直到高優先級中斷執行完畢,這樣產生的PendSV 中斷就不會打斷其他中斷的運行。

SysTick 用于產生系統節拍時鐘,提供一個時間片,如果多個任務共享同一個優先級,則每次 SysTick 中斷,下一個任務將獲得一個時間片。

FreeRTOS 中的任務是搶占式調度機制,高優先級的任務可打斷低優先級任務,低優先級任務必須在高優先級任務阻塞或結束后才能得到調度。相同優先級的任務采用時間片輪轉方式進行調度(也就是分時調度),時間片輪轉調度僅在當前系統中無更高優先級就緒任務存在的情況下才有效。

4.3 啟動方式

FreeRTOS有兩種啟動方式,效果一樣,看個人喜好。

第一種:main 函數中將硬件初始化, RTOS 系統初始化,所有任務的創建完成,最后一步開啟調度。目前看到的幾個芯片SDK都是這種方式。

第二種:main 函數中將硬件和 RTOS 系統先初始化好,只創建一個任務后就啟動調度器,然后在這個任務里面創建其它應用任務,當所有任務都創建成功后,啟動任務再把自己刪除。

4.4 任務創建源碼分析

xTaskCreate()創建任務。

1. BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,  
2.                         const char * const pcName, /*lint !e971 Unqualified char types are allowed for strings and single characters only. */  
3.                         const configSTACK_DEPTH_TYPE usStackDepth,  
4.                         void * const pvParameters,  
5.                         UBaseType_t uxPriority,  
6.                         TaskHandle_t * const pxCreatedTask )  
7. {   
8.     TCB_t * pxNewTCB;  
9.     BaseType_t xReturn;  
10.   
11.     /* If the stack grows down then allocate the stack then the TCB so the stack 
12.      * does not grow into the TCB.  Likewise if the stack grows up then allocate 
13.      * the TCB then the stack. */  
14.     #if ( portSTACK_GROWTH > 0 )  
15.         {   
16.             /**/
17.         }  
18.     #else /* portSTACK_GROWTH */  
19.         {   
20.             StackType_t * pxStack;  
21.   
22.             /* Allocate space for the stack used by the task being created. */  
23.             pxStack = pvPortMalloc( ( ( ( size_t ) usStackDepth ) * sizeof( StackType_t ) ) ); /*lint !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack and this allocation is the stack. */  
24.   
25.             if( pxStack != NULL )  
26.             {   
27.                 /* Allocate space for the TCB. */  
28.                 pxNewTCB = ( TCB_t * ) pvPortMalloc( sizeof( TCB_t ) ); /*lint !e9087 !e9079 All values returned by pvPortMalloc() have at least the alignment required by the MCU's stack, and the first member of TCB_t is always a pointer to the task's stack. */  
29.   
30.                 if( pxNewTCB != NULL )  
31.                 {   
32.                     /* Store the stack location in the TCB. */  
33.                     pxNewTCB->pxStack = pxStack;  
34.                 }  
35.                 else  
36.                 {   
37.                     /* The stack cannot be used as the TCB was not created.  Free 
38.                      * it again. */  
39.                     vPortFree( pxStack );  
40.                 }  
41.             }  
42.             else  
43.             {   
44.                 pxNewTCB = NULL;  
45.             }  
46.         }  
47.     #endif /* portSTACK_GROWTH */  
48.   
49.     if( pxNewTCB != NULL )  
50.     {   
51.         #if ( tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE != 0 ) /*lint !e9029 !e731 Macro has been consolidated for readability reasons. */  
52.             {   
53.                 /* Tasks can be created statically or dynamically, so note this 
54.                  * task was created dynamically in case it is later deleted. */  
55.                 pxNewTCB->ucStaticallyAllocated = tskDYNAMICALLY_ALLOCATED_STACK_AND_TCB;  
56.             }  
57.         #endif /* tskSTATIC_AND_DYNAMIC_ALLOCATION_POSSIBLE */  
58.   
59.         prvInitialiseNewTask( pxTaskCode, pcName, ( uint32_t ) usStackDepth, pvParameters, uxPriority, pxCreatedTask, pxNewTCB, NULL );  
60.         prvAddNewTaskToReadyList( pxNewTCB ); //將新任務加入到就緒鏈表候著
61.         xReturn = pdPASS;  
62.     }  
63.     else  
64.     {   
65.         xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;  
66.     }  
67.   
68.     return xReturn;  
69. }

申請任務控制塊內存,檢查配置參數,初始化,將任務信息加入到就緒鏈表,等待調度。前面鏈表部分提到,freeRTOS的任務信息都是使用鏈表記錄,在task.c有

1. PRIVILEGED_DATA static List_t pxReadyTasksLists[configMAX_PRIORITIES];//就緒
2. PRIVILEGED_DATA static List_t xDelayedTaskList1;    //延時
3. PRIVILEGED_DATA static List_t xDelayedTaskList2; 
4. PRIVILEGED_DATA static List_t xPendingReadyList;  //掛起
5. PRIVILEGED_DATA static List_t xSuspendedTaskList;   //阻塞

分別記錄就緒態、阻塞態和掛起的任務,其中阻塞態有2個,是因為特殊考慮,時間溢出 的問題,實際開發單片機項目計時超過24h的可以借鑒。其中pxReadyTasksLists鏈表數組,其下標就是任務的優先級。4.5 任務調度源碼分析

創建完任務的時候,vTaskStartScheduler開啟調度器,空閑任務、定時器任務也是在開啟調度函數中實現的。

為什么要空閑任務?因為 FreeRTOS一旦啟動,就必須要保證系統中每時每刻都有一個任務處于運行態(Runing),并且空閑任務不可以被掛起與刪除,空閑任務的優先級是最低的,以便系統中其他任務能隨時搶占空閑任務的 CPU 使用權。這些都是系統必要的東西,也無需自己實現。

1. void vTaskStartScheduler( void )  
2. {   
3.     BaseType_t xReturn;  
4.   
5.     /* Add the idle task at the lowest priority. */  
6.     #if ( configSUPPORT_STATIC_ALLOCATION == 1 )  
7.         {   
8.      /***/
9.         }  
10.     #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */  
11.         {   
12.             /*創建空閑任務*/  
13.             xReturn = xTaskCreate( prvIdleTask,  
14.                                    configIDLE_TASK_NAME,  
15.                                    configMINIMAL_STACK_SIZE,  
16.                                    ( void * ) NULL,  
17.                                    portPRIVILEGE_BIT,  //優先級為0
18.                                    &xIdleTaskHandle );  
19.         }  
20.     #endif /* configSUPPORT_STATIC_ALLOCATION */  
21.   
22.     #if ( configUSE_TIMERS == 1 )  
23.         {   
24.             if( xReturn == pdPASS )  
25.             {   
26.                 //創建定時器task,接收開始、結束定時器等命令
27.                 xReturn = xTimerCreateTimerTask(); 
28.             }  
29.             else  
30.             {   
31.                 mtCOVERAGE_TEST_MARKER();  
32.             }  
33.         }  
34.     #endif /* configUSE_TIMERS */  
35.   
36.     if( xReturn == pdPASS )  
37.     {   
38.         /* freertos_tasks_c_additions_init() should only be called if the user 
39.          * definable macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is 
40.          * the only macro called by the function. */  
41.         #ifdef FREERTOS_TASKS_C_ADDITIONS_INIT  
42.             {   
43.                 freertos_tasks_c_additions_init();  
44.             }  
45.         #endif  
46.   
47.         portDISABLE_INTERRUPTS();  
48.   
49.         #if ( configUSE_NEWLIB_REENTRANT == 1 )  
50.             {   
51.                 _impure_ptr = &( pxCurrentTCB->xNewLib_reent );  
52.             }  
53.         #endif /* configUSE_NEWLIB_REENTRANT */  
54.   
55.         xNextTaskUnblockTime = portMAX_DELAY;  
56.         xSchedulerRunning = pdTRUE;  
57.         xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;  
58.   
59.         portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();  
60.   
61.         traceTASK_SWITCHED_IN();  
62.   
63.         /* Setting up the timer tick is hardware specific and thus in the 
64.          * portable interface. */  
65.         if( xPortStartScheduler() != pdFALSE )  
66.         {   
67.             /* 系統開始運行 */  
68.         }  
69.         else  
70.         {   
71.             /* Should only reach here if a task calls xTaskEndScheduler(). */  
72.         }  
73.     }  
74.     else  
75.     {   
76.        /*****/
77. } 

4.6 任務狀態切換

FreeRTOS 系統中的每一個任務都有多種運行狀態,具體如下:

? 任務掛起函數

vTaskSuspend()

掛起指定任務,被掛起的任務絕不會得到 CPU 的使用權

vTaskSuspendAll()

將所有的任務都掛起

? 任務恢復函數

vTaskResume()
vTaskResume()
xTaskResumeFromISR()

任務恢復就是讓掛起的任務重新進入就緒狀態,恢復的任務會保留掛起前的狀態信息,在恢復的時候根據掛起時的狀態繼續運行。xTaskResumeFromISR() 專門用在中斷服務程序中。無論通過調用一次或多次vTaskSuspend()函數而被掛起的任務,也只需調用一次恢復即可解掛 。

? 任務刪除函數 vTaskDelete()用于刪除任務。當一個任務可以刪除另外一個任務,形參為要刪除任 務創建時返回的任務句柄,如果是刪除自身, 則形參為 NULL。

4.7 任務使用注意點

1、中斷服務函數是不允許調用任何會阻塞運行的接口。一般在中斷服務函數中只做標記事件的發生,然后通知任務,讓對應任務去執行相關處理 。

2、將緊急的處理事件的任務優先級設置偏高一些。 

3、空閑任務(idle 任務)是 FreeRTOS 系統中沒有其他工作進行時自動進入的系統任務,永遠不會掛起空閑任務,不應該陷入死循環。

4、創建任務使用的內存不要過多,按需申請。如果浪費太多,后續應用申請大空間可能提示內存不足。

五、 隊列

5.1 隊列的概念

隊列用于任務間通信的數據結構,通過消息隊列服務,任務或中斷服務將消息放入消息隊列中。其他任務或者自身從消息隊列中獲得消息。實現隊列可以在任務與任務間、中斷和任務間傳遞信息。隊列操作支持阻塞等待,向已經填滿的隊列發送數據或者從空隊列讀出數據,都會導致阻塞,時間自定義。消息隊列的運作過程具如下:

5.2 隊列創建

xQueueCreate()用于創建一個新的隊列并返回可用于訪問這個隊列的句柄。隊列句柄其實就是一個指向隊列數據結構類型的指針。

1. master_queue = xQueueCreate(50, sizeof(task_message_struct_t));  

創建隊列,占用50個單元,每個單元為sizeof(task_message_struct_t)字節,和 malloc比較類似。其最終使用的函數是 xQueueGenericCreate(),后續信號量等也是使用它創建,只是最后的隊列類型不同。

申請內存后,xQueueGenericReset再對其進行初始化,隊列的結構體xQUEUE成員:

1. typedef struct QueueDefinition /* The old naming convention is used to prevent breaking kernel aware debuggers. */  
2. {   
3.     int8_t * pcHead;           /*< Points to the beginning of the queue storage area. */  
4.     int8_t * pcWriteTo;        /*< Points to the free next place in the storage area. */  
5.     //類型
6.     union  
7.     {   
8.         QueuePointers_t xQueue;     /*< Data required exclusively when this structure is used as a queue. */  
9.         SemaphoreData_t xSemaphore; /*< Data required exclusively when this structure is used as a semaphore. */  
10.     } u;  
11.   
12.     //當前向隊列寫數據阻塞的任務列表或者從隊列取數阻塞的鏈表
13.     List_t xTasksWaitingToSend;  
14.     List_t xTasksWaitingToReceive;   
15.   
16.     //隊列里有多少個單元被占用,應用中需要
17.     volatile UBaseType_t uxMessagesWaiting; 
18. 
19.     UBaseType_t uxLength;                   /*< The length of the queue defined as the number of items it will hold, not the number of bytes. */  
20.     UBaseType_t uxItemSize;                 /*< The size of each items that the queue will hold. */  
21.   
22.  /

Popular articles

主站蜘蛛池模板: 再深点灬舒服灬太大| 国产真实迷j在线播放| 国产大片免费天天看| 嘟嘟嘟www免费高清在线中文| 久久精品亚洲一区二区三区浴池| 三上悠亚中文字幕在线播放| 在线观看亚洲视频| 亚洲精品www久久久久久| 真希友田视频中文字幕在线看| 动漫人物桶动漫人物免费观看| 久久伊人精品一区二区三区| 免费91麻豆精品国产自产在线观看| 精品综合久久久久久98| 精品一区二区三区在线观看| 打开腿给医生检查黄文| 男人边摸边吃奶边做下面| 亚洲一区天堂| 久久精品一区二区三区不卡| 一级成人理伦片| 久久久国产乱子伦精品| 国产一级做a爰片久久毛片| 2021国产麻豆剧果冻传媒电影| 日b视频免费看| 中国毛片在线观看| 欧美日韩中文字幕在线视频| 北条麻妃一本到高清在线观看| 女人是男人的未来的人| 日韩在线视频一区二区三区| 中文字幕在线观| 亚洲福利二区| 亚洲国产中文在线视频| 国产精品怡红院在线观看| 亚洲一区二区在线视频| 爽爽日本在线视频免费| 免费看的一级毛片| 国产精品igao视频网| 亚洲免费人成在线视频观看| 日本青娱乐| 精品无码久久久久久国产| 无翼乌邪恶工番口番邪恶| 天天躁夜夜躁狠狠躁2021|