日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

FreeRTOS及其应用,万字长文,基础入门

發布時間:2023/12/20 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 FreeRTOS及其应用,万字长文,基础入门 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

嵌入式系統不只是ARM+Linux,不是只有安卓,凡是電子產品都可稱為嵌入式系統。物聯網行業的興起,也提升了FreeRTOS市場占有率。本文就是介紹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.??/******/ 23.?}?xQUEUE;??

5.3 隊列刪除

隊列刪除函數 vQueueDelete()需傳入要刪除的消息隊列的句柄即可,刪除之后這個消息隊列的所有信息都會被系統回收清空,而且不能再次使用這個消息隊列了。實際應用中很少使用。

5.4 向隊列發送消息

任務或者中斷服務程序都可以給消息隊列發送消息,當發送消息時,如果隊列未滿或者允許覆蓋入隊,FreeRTOS 會將消息拷貝到消息隊列隊尾,否則,會根據用戶指定的超時時間進行阻塞,消息發送接口很多,最簡單的是 xQueueSend(),用于向隊列尾部發送一個隊列消息。消息以拷貝的形式入隊,該函數絕對不能在中斷服務程序里面被調用,中斷中必須使用帶有中斷保護功能的 xQueueSendFromISR()來代替。

BaseType_t?xQueueSend(QueueHandle_t?xQueue,const?void*?pvItemToQueue,?TickType_t?xTicksToWait);

用于向隊列尾部發送一個隊列消息。

參數

xQueue 隊列句柄

pvItemToQueue 指針,指向要發送到隊列尾部的隊列消息。?

xTicksToWait 隊列滿時,等待隊列空閑的最大超時時間。如果隊列滿并且xTicksToWait 被設置成 0,函數立刻返回。超時時間的單位為系統節拍周期 tick,延時為 portMAX_DELAY 將導致任務掛起(沒有超時)。?

返回值

消息發送成功成功返回 pdTRUE,否則返回 errQUEUE_FULL。

xQueueSendToBack與xQueueSend完全相同, xQueueSendFromISR()與 xQueueSendToBackFromISR(),帶FromISR表示只能在中斷中使用,freeRTOS所以帶這個后綴的都是這個含義。xQueueSendToFront()和QueueSendToFrontFromISR()用于向隊列隊首發送一個消息。這些在任務中發送消息的函數都是 xQueueGenericSend()展開的宏定義。

1.?BaseType_t?xQueueGenericSend(?QueueHandle_t?xQueue,??? 2.??????????????????const?void?*?const?pvItemToQueue,??? 3.??????????????????????????TickType_t?xTicksToWait,??? 4.??????????????????const?BaseType_t?xCopyPosition?)??//發送數據到消息隊列的位置

一般使用xQueueSend和xQueueSendFromISR,如不確定當前運行的是系統服務,還是中斷服務,一般ARM都支持查詢中斷狀態寄存器判斷,可以封裝一層接口,只管發消息,內部判斷是否使用支持中斷嵌套的版本,UIS8910就是如此。特殊情況下,如發送網絡數據包未收到服務器響應,期望立刻入隊再次發送它,可以xQueueSendToFront向隊頭發消息。

5.5 從隊列讀取消息

當任務試圖讀隊列中的消息時,可以指定一個阻塞超時時間,當且僅當消息隊列中有消息的時候,任務才能讀取到消息。如果隊列為空,該任務將保持阻塞狀態以等待隊列數據有效。當其它任務或中斷服務程序往其等待的隊列中寫入了數據,該任務將自動由阻塞態轉為就緒態。當任務等待的時間超過了指定的阻塞時間,即使隊列中尚無有效數據,任務也會自動從阻塞態轉移為就緒態。所有的task主入口while循環體都是按這個執行。例如:

1.?static?void?track_master_task_main()?? 2.?{?? 3.?????track_task_message_struct_t?queue_item?=?{0}; 4.?????/****/ 5.??? 6.?????while(1)?? 7.?????{?? 8.?????????if(xQueueReceive(master_queue,?&queue_item,?portMAX_DELAY))//阻塞等待 9.?????????{?? 10.?????????????track_master_task_msg_handler(&queue_item);?? 11.?????????}?? 12.?????}?? 13.?}??

xQueueReceive()用于從一個隊列中接收消息并把消息從隊列中刪除。如果不想刪除消息的話,就調用 xQueuePeek()函數。xQueueReceiveFromISR()與xQueuePeekFromISR()是中斷版本,用于在中斷服務程序中接收一個隊列消息并把消息。這兩個函數只能用于中斷,是不帶有阻塞機制的,實際項目沒有使用。

5.6 查詢隊列使用情況

uxQueueMessagesWaiting()查詢隊列中存儲的信息數目,具有中斷保護的版本為uxQueueMessagesWaitingFromISR()。查詢隊列的空閑數目uxQueueSpacesAvailable()。

5.7 隊列使用注意點

使用隊列函數需要注意以下幾點:

1、中斷中必須使用帶FromISR后綴的接口;?

2、發送或者是接收消息都是以拷貝的方式進行,如果消息內容過于龐大,可以將消息的地址作為消息進行發送、接收。

1.?typedef?struct???? 2.?{???? 3.?????TaskHandle_t?src_mod_id;???? 4.?????int?message_id;???? 5.?????int32_t?param;???? 6.?????union???? 7.?????{???? 8.?????????int32_t?result;???? 9.?????????int32_t?socket_id;???? 10.?????};???? 11.?????void*?pvdata;??//大數據使用動態申請內存保存,隊列只傳遞指針?? 12.?}?track_task_message_struct_t;???

3、隊列并不屬于任何任務,所有任務都可以向同一隊列寫入和讀出,一個隊列可以由多任務或中斷讀寫。?

4、隊列的深度要結合實際,可以多申請點,前提是每個隊列單元盡可能小。?

5、隊列存在一定限制,在隊頭沒有取出來之前,是無法取出第二個,和STL鏈表存在差異。

六、 軟件定時器

6.1 軟件定時器的概念

定時器有硬件定時器和軟件定時器之分,硬件定時器是芯片本身提供的定時功能精度高,并且是中斷觸發方式。軟件定時器是由操作系統封裝的接口,它構建在硬件定時器基礎之上,使系統能夠提供不受硬件定時器資源限制,其實現的功能與硬件定時器也是類似的。

在操作系統中,通常軟件定時器以系統節拍周期為計時單位。系統節拍配置為configTICK_RATE_HZ,該宏在 FreeRTOSConfig.h 中,一般是100或者1000。根據實際系統 CPU 的處理能力和實時性需求設置合適的數值,系統節拍周期的值越小,精度越高,但是系統開銷也將越大,因為這代表在 1 秒中系統進入時鐘中斷的次數也就越多。

6.2 軟件定時器創建

軟件定時器需先創建才允許使用,動態創建方式是xTimerCreate(),返回一個句柄。軟件定時器在創建成功后是處于休眠狀態的,沒有開始計時運行。FreeRTOS的軟件定時器支持單次模式和周期模式。

單次模式:當用戶創建了定時器并啟動了定時器后,定時時間到了,只執行一次回調函數,之后不再執行。周期模式:定時器會按照設置的定時時間循環執行回調函數,直到用戶將定時器停止或刪除。

實際項目中使用這種模式對單片機喂狗就比較省事。

1.?TimerHandle_t?xTimerCreate(?const?char?*?const?pcTimerName,?//定時器名稱 2.?????????????????????????????const?TickType_t?xTimerPeriodInTicks,??//定時時間 3.?????????????????????????????const?UBaseType_t?uxAutoReload,??//是否自動重載 4.?????????????????????????????void?*?const?pvTimerID,??//回調函數的參數 5.?????????????????????????????TimerCallbackFunction_t?pxCallbackFunction?)??//回調函數

6.3 軟件定時器開啟

新創建的定時器沒有開始計時啟動,可以使用

xTimerStart()、 xTimerReset()、 xTimerStartFromISR()?、xTimerResetFromISR()? xTimerChangePeriod()、xTimerChangePeriodFromISR()

這些函數將其狀態轉換為活躍態,開始運行。區別:如果定時器設定60秒間隔,已經運行了30秒,reset是將定時器重置為原來設定的時間間隔,也就是重新開始延時60秒。ChangePeriod重新設置計時周期。

6.4 軟件定時器停止

xTimerStop() 用于停止一個已經啟動的軟件定時器,xTimerStopFromISR()是中斷版本。

6.5 軟件定時器刪除

xTimerDelete()用于刪除一個已經被創建成功的軟件定時器,釋放資源,刪除之后不能再使用。實際項目中,任務和隊列都是按需創建,一直使用,但是定時器不使用的就應該刪除,并且刪除后一定要將句柄置為NULL。

6.6 軟件定時器源碼分析

軟件定時器任務是在系統開始調度的時候就被創建:vTaskStartScheduler()—xTimerCreateTimerTask。

1.?BaseType_t?xTimerCreateTimerTask(?void?)?? 2.?{?? 3.?????BaseType_t?xReturn?=?pdFAIL;?? 4.??? 5.?????prvCheckForValidListAndQueue();??//創建定時器任務的隊列 6.??? 7.?????if(?xTimerQueue?!=?NULL?)?? 8.?????{?? 9.?????????#if?(?configSUPPORT_STATIC_ALLOCATION?==?1?)?? 10.?????????????{?? 11.???????????????????????/**/ 12.?????????????}?? 13.?????????#else?/*?if?(?configSUPPORT_STATIC_ALLOCATION?==?1?)?*/?? 14.?????????????{?? 15.??????????????????//創建定時器任務 16.?????????????????xReturn?=?xTaskCreate(?prvTimerTask,?? 17.????????????????????????????????????????configTIMER_SERVICE_TASK_NAME,?? 18.????????????????????????????????????????configTIMER_TASK_STACK_DEPTH,?? 19.????????????????????????????????????????NULL,?? 20.????????????????????????????????????????(?(?UBaseType_t?)?configTIMER_TASK_PRIORITY?)?|?portPRIVILEGE_BIT,?? 21.????????????????????????????????????????&xTimerTaskHandle?);?? 22.?????????????}?? 23.?????????#endif?/*?configSUPPORT_STATIC_ALLOCATION?*/?? 24.?????}?? 25.??????/**/ 26.?????return?xReturn;?? 27.?}??

任務創建后,等候命令執行

1.static?portTASK_FUNCTION(?prvTimerTask,?pvParameters?)?? 2.?{?? 3.??????/**/ 4.??? 5.?????for(?;?;?)?? 6.?????{?? 7.?????????//最近即將超時的定時器還有多長時間溢出 8.?????????xNextExpireTime?=?prvGetNextExpireTime(?&xListWasEmpty?);?? 9.??? 10.?????????//阻塞等待,定時器溢出或受到命令,進入下一步(原因不明) 11.?????????prvProcessTimerOrBlockTask(?xNextExpireTime,?xListWasEmpty?);?? 12.??? 13.?????????//接收命令并處理,見下面 14.?????????prvProcessReceivedCommands();?? 15.?????}?? 16.?}??

所有定時器接口,都是使用xTimerGenericCommand向隊列發送控制命令,命令如下:

1.?#define?tmrCOMMAND_START_DONT_TRACE?????????????(?(?BaseType_t?)?0?)?? 2.?#define?tmrCOMMAND_START????????????????????????(?(?BaseType_t?)?1?)?? 3.?#define?tmrCOMMAND_RESET????????????????????????(?(?BaseType_t?)?2?)?? 4.?#define?tmrCOMMAND_STOP?????????????????????????(?(?BaseType_t?)?3?)?? 5.?#define?tmrCOMMAND_CHANGE_PERIOD????????????????(?(?BaseType_t?)?4?)?? 6.?#define?tmrCOMMAND_DELETE???????????????????????(?(?BaseType_t?)?5?)??

6.7 軟件定時器使用注意點

1、查看其他開源代碼,對定時器的使用并不多,但實際項目中過多依賴定時器,導致應用邏輯混亂。?

2、freeRTOS 的定時器不是無限制的,其根源是接收定時器控制命令消息的隊列,默認只有10個單元。

1.?xTimerQueue?=?xQueueCreate(?(?UBaseType_t?)?configTIMER_QUEUE_LENGTH,?sizeof(?DaemonTaskMessage_t?)?);??

定時器過多,可能出現發起定時器命令失敗,原因是隊列已滿。可以將默認的10擴大為15,后續盡量使用信號量來優化代碼。?

4、軟件定時器的回調函數要快進快出,而且不能有任何阻塞任務運行的情況,不能有vTaskDelay() 以及其它能阻塞任務運行的函數。特別說明,其回調函數是在定時器任務執行的,并不是開啟定時器的任務。

七、 信號量

7.1 信號量的概念

信號量(Semaphore)是一種實現任務間通信的機制,可以實現任務之間同步或臨界資源的互斥訪問,常用于協助一組相互競爭的任務來訪問臨界資源。在多任務系統中,各任務之間需要同步或互斥實現臨界資源的保護,信號量功能可以為用戶提供這方面的支持。可以簡單認為是為支持多任務同時操作的全局變量(個人理解)。

7.1.1 二值信號量

比如有一個停車位,多個人都想占用停車,這種情況就可以使用一個變量標記車位狀態,它只有兩種情況,被占用或者沒被占用。在多任務中使用二值信號量表示,用于任務與任務、任務與中斷的同步。在freeRTOS中,二值信號量看作只有一個消息的隊列,因此這個隊列只能為空或滿。

7.1.2 計數信號量

如果有100個停車位,可以停100輛車,每進去一輛車,車位的數量就要減一,當停車場停滿了 100 輛車的時候,再來的車就不能停進去了。這種場景就需要計數信號量來表示多個狀態。二進制信號量可以被認為是長度為 1 的隊列,而計數信號量則可以被認為長度大于 1 的隊列,信號量使用者依然不必關心存儲在隊列中的消息,只需關心隊列是否有消息即可。

7.1.3 互斥信號量

還是前面車位問題,只剩一個空車位,雖然員工車離得近,但是領導車來了,要優先安排給領導使用,這就是由地位決定。互斥信號量其實是特殊的二值信號量,由于其特有的優先級繼承機制從而使它更適用于簡單互鎖,也就是保護臨界資源。

優先級翻轉問題:假設有任務H,任務M和任務L三個任務,優先級逐次降低。低優先級的任務L搶先占有資源,導致高優先級的任務H阻塞等待,此時再有中等優先級的任務M,它不需要該資源,且優先級高于任務L,它優先執行;之后再執行任務L,最后才執行任務H。看起來就是高優先級的任務反而不如低優先級的任務,即優先級翻轉。

改進型的互斥信號量具有優先級繼承機制,操作系統對獲取到臨界資源的任務提高其優先級為所有等待該資源的任務中的最高優先級。一旦任務釋放了該資源,就恢復到原來的優先級。

任務L先占用資源,任務H申請不到資源會進入阻塞態,同時系統就會把當前正在使用資源的任務L的優先級臨時提高到與任務H優先級相同,即使任務M被喚醒了,因為它的優先級比任務H低,所以無法打斷任務L,因為任務L的優先級被臨時提升到 H;任務L使用完該資源,任務H優先級最高,將接著搶占 CPU 的使用權,這樣保證任務H在任務M前優先執行。

上面的這些就是為了說明,二值信號量因為優先級翻轉,不能用于對臨界區的訪問。

7.1.4 遞歸互斥信號量

信號量是每獲取一次,可用信號量個數就會減少一個,釋放一次就增加一個。但是遞歸信號量則不同。對于已經獲取遞歸互斥量的任務可以重復獲取該遞歸互斥量,該任務擁有遞歸信號量的所有權。任務成功獲取幾次遞歸互斥量,就要返還幾次,在此之前遞歸互斥量都處于無效狀態,其他任務無法獲取,只有持有遞歸信號量的任務才能獲取與釋放。類似棧的效果。

7.2 二值信號量的應用

二值信號量是任務與任務間、任務與中斷間同步的重要手段。例如,任務A使用串口發出AT數據后,獲取二值信號量無效進入阻塞;

某個時間后,任務B中串口收到正確的回復,釋放二值信號量。

任務A就立即從阻塞態中解除,進入就緒態,等待運行。這種機制用在模塊AT交互很合適。

7.3 計數信號量的應用

計數信號量可以用于資源管理,允許多個任務獲取信號量訪問共享資源。例如有公共資源車位3個,但是有多個任務要使用,這種場景就必須使用計數信號量。三個資源最多支持 3 個任務訪問,那么第 4 個任務訪問的時候,會因為獲取不到信號量而進入阻塞。也就是第4個人無法占用車位,必須前面有車離開。等到其中一個有任務(比如任務 1) 釋放掉該資源的時候,第 4 個任務才能獲取到信號量從而進行資源的訪問。其運作的機制類似下圖。

在這里插入圖片描述

7.4 互斥信號量的應用

多任務環境下往往存在多個任務競爭同一臨界資源的應用場景,互斥量可被用于對臨界資源的保護從而實現獨占式訪問。互斥量可以降低信號量存在的優先級翻轉問題帶來的影響。

比如有兩個任務需要對串口進行發送數據,其硬件資源只有一個,那么兩個任務肯定不能同時發送,不然導致數據錯誤,那么就可以用互斥量對串口資源進行保護,當一個任務正在使用串口的時候,另一個任務則無法使用串口,等到前一個任務使用串口完成后, 另外一個任務才能獲得串口的使用權。

另外需要注意的是互斥量不能在中斷服務函數中使用,因為其特有的優先級繼承機制只在任務起作用,在中斷的上下文環境毫無意義。

互斥信號量可以在多個任務之間進行資源保護,而臨界區只能是在同一個任務進行,但是其速度快。(個人理解)

7.5 信號量接口

所有信號量semaphore使用套路相近,都是創建creat、刪除delete、釋放give和獲取take四種;釋放和獲取支持任務級和中斷級FromISR,其中互斥量和遞歸互斥量不支持中斷。使用對應的信號量,需要在FreeRTOSConfig.h開啟對應的功能。

7.5.1 信號量創建

xSemaphoreCreateBinary()用于創建一個二值信號量,并返回一個句柄,默認二值信號量為空,在使用函數 xSemaphoreTake()獲取之前必須 先 調 用 函 數 xSemaphoreGive() 釋放后才可以獲取。

xSemaphoreCreateCounting()創建計數信號量。

1.?#define?xSemaphoreCreateCounting(?uxMaxCount,?uxInitialCount?)???

uxMaxCount 計數信號量的最大值,當達到這個值的時候,信號量不能再被釋放。uxInitialCount 創建計數信號量的初始值。

xSemaphoreCreateMutex()用于創建一個互斥量,并返回一個互斥量句柄,只能被同一個任務獲取一次,如果同一個任務想再次獲取則會失敗。

xSemaphoreCreateRecursiveMutex()用于創建一個遞歸互斥量,遞歸信號量可以被同一個任務獲取很多次,獲取多少次就需要釋放多少次。遞歸信號量與互斥量一樣,都實現了優先級繼承機制,可以減少優先級反轉的反生。

7.5.2 信號量刪除

vSemaphoreDelete()用于刪除一個信號量,包括二值信號量,計數信號量,互斥量和遞 歸互斥量。如果有任務阻塞在該信號量上,暫時不要刪除該信號量。傳入的參數為創建時返回的句柄。

7.5.3 信號量釋放

當信號量有效的時候,任務才能獲取信號量,信號量變得有效就是釋放信號量。每調用一次該函數就釋放一個信號量,注意釋放的次數,尤其是計數信號量。

xSemaphoreGive()是任務中釋放信號量的宏,可以用于二值信號量、計數信號量、互斥量的釋放,但不能釋放由函數xSemaphoreCreateRecursiveMutex()創建的遞歸互斥量,遞歸互斥信號量用xSemaphoreGiveRecursive()釋放。xSemaphoreGiveFromISR()帶中斷保護釋放一個信號量,被釋放的信號量可以是二值信號量和計數信號量,不能釋放互斥量和遞歸互斥量,因為互斥量和遞歸互斥量不可在中斷中使用,互斥量的優先級繼承機制只能在任務中起作用。

7.5.4 信號量獲取

與釋放信號量對應的是獲取信號量,當信號量有效的時候,任務才能獲取信號量,當任務獲取了某個信號量的時候,該信號量的可用個數就減一,當它減到0 的時候,任務就無法再獲取了,并且獲取的任務會進入阻塞態(如果設定了阻塞超時時間)。

xSemaphoreTake()函數用于獲取信號量,不帶中斷保護。獲取的信號量對象可以是二值信號量、計數信號量和互斥量,但是遞歸互斥量并不能使用它。

1.?#define?xSemaphoreTake(?xSemaphore,?xBlockTime?)??

xSemaphore 信號量句柄?

xBlockTime 等待信號量可用的最大超時時間,單位為 tick?

獲取 成 功 則 返 回 pdTRUE ,在 指定的 超時 時間 中 沒 有 獲 取 成 功 則 返 回errQUEUE_EMPTY。

使用xSemaphoreTakeRecursive()獲取遞歸互斥量。xSemaphoreTakeFromISR()是獲取信號量的中斷版本,是一個不帶阻塞機制獲取信號量的函數,獲取對象必須由是已經創建的信號量,信號量類型可以是二值信號量和計數信號量,它與 xSemaphoreTake()函數不同,它不能用于獲取互斥量,因為互斥量不可以在中斷中使用,并且互斥量特有的優先級繼承機制只能在任務中起作用,而在中斷中毫無意義。

7.6 信號量使用注意點

1、建議合理使用信號量進行事件同步處理,減少對定時器的依賴。

2、使用前合理設定超時時間和依賴關系,避免多個任務互相等待對方釋放的信號量而死鎖。

八、 事件

8.1 事件的概念

信號量用于單個任務與任務或任務與中斷之間的同步,但有些任務可能與多個任務由關聯,此時信號量實現就比較麻煩,可以使用事件機制。

事件是一種實現任務間通信的機制,多任務環境下,任務、中斷之間往往需要同步操作,一個事件發生會告知等待中的任務,即形成一個任務與任務、中斷與任務間的同步。事件可以提供一對多、多對多的同步操作。一對多同步模型:一個任務等待多個事件的觸發,這種情況是比較常見的。

任務可以通過設置事件位來實現事件的觸發和等待操作。FreeRTOS 的事件僅用于同步,不提供數據傳輸功能。

8.2 事件的應用

在某些場合,可能需要多個事件發生了才能進行下一步操作。各個事件可分別發送或一起操作事件標志組,而任務可以等待多個事件,任務僅對感興趣的事件進行關注。當有感興趣的事件發生時并且符合感興趣的條件,任務將被喚醒并進行后續的處理動作。

其機制類似一個全局變量,子任務使用特殊的接口函數對指定的位進行寫1或者清零,主任務阻塞等待該變量滿足設定的規則,則返回運行。

例如項目中的喂狗機制,多個任務,只要有一個任務發生異常,則主任務停止喂狗,等待被重啟。不使用事件機制,則3個任務定時向主master task發送消息,表明自身任務運行正常;同時master task定時查詢,是否收到3個任務的消息,如果全都收到表示正常,清除進入下一個定時檢查周期;如果其中一個未收到則表示對應任務異常,故意停止喂狗等待被重啟。

使用事件機制,則相對容易,3個任務定時設置對應的標志位,master task只需要等待指定的事件位,超時就表示異常;不需要自身定時查詢,也省去了定時發消息。當然缺點是master task只能阻塞等待事件不能執行其他業務邏輯。

8.3 事件接口

xEventGroupCreate()用于創建一個事件組,vEventGroupDelete()刪除事件對象控制塊來釋放系統資源。

事件組置位,任務中使用 xEventGroupSetBits(),中斷中使用xEventGroupSetBitsFromISR();

xEventGroup 事件句柄。uxBitsToSet 指定事件中的事件標志位。如設置 uxBitsToSet 為 0x09 則位 3和位 0 都需要被置位。返回調用 xEventGroupSetBits() 時事件組中的值。

事件組清除位,任務中使用xEventGroupClearBits(),中斷中使用 xEventGroupClearBitsFromISR(),都是用于清除事件組指定的位,如果在獲取事件的時候沒有將對應的標志位清除,那么就需要用這個函數來進行顯式清除。

xEventGroup 事件句柄。uxBitsToClear 指定事件組中的哪個位需要清除。如設置 uxBitsToSet 為 0x09則位 3和位 0 都需要被清除。

讀取事件標志,任務中使用 xEventGroupGetBits(),中斷中使用xEventGroupGetBitsFromISR()。

重點是等待事件函數 xEventGroupWaitBits(),獲取任務感興趣的事件且支持等待超時機制,當且僅當任務等待的事件發生時,任務才能獲取到事件信息。否則任務將保持阻塞狀態以等待事件發生。當其它任務或中斷服務程序往其等待的事件設置對應的標志位,該任務將自動由阻塞態轉為就緒態。

EventGroupWaitBits()用于獲取事件組中的一個或多個事件發生標志,當要讀取的事件標志位沒有被置位時,任務將進入阻塞等待狀態。要想使用該函數必 須 把FreeRTOS/source/event_groups.c 這個 C 文件添加到工程中。

1.?EventBits_t?xEventGroupWaitBits(?EventGroupHandle_t?xEventGroup,?? 2.??????????????????????????????????const?EventBits_t?uxBitsToWaitFor,?? 3.??????????????????????????????????const?BaseType_t?xClearOnExit,?? 4.??????????????????????????????????const?BaseType_t?xWaitForAllBits,?? 5.??????????????????????????????????TickType_t?xTicksToWait?)??

參數

xEventGroup 事件句柄。?

? uxBitsToWaitFor 一個按位或的值,指定需要等待事件組中的哪些位置1。如需要等待 bits 0 and/or bit 1 and/or bit 2則 uxBitsToWaitFor 配置為 0x07(0111b)。

xClearOnExit pdTRUE:xEventGroupWaitBits() 等待到滿足任務喚醒的事件時,系統將清除由形參 uxBitsToWaitFor 指定的事件標志位。pdFALSE:不會清除由形參 uxBitsToWaitFor 指定的事件標志位。

xWaitForAllBits pdTRUE :當形參 uxBitsToWaitFor 指定的位都置位的時候,xEventGroupWaitBits()才滿足任務喚醒的條件,這也是“邏輯與”等待事件,并且在沒有超時的情況下返回對應的事件標志位的值。pdFALSE:當形參 uxBitsToWaitFor 指定的位有其中任意一個置位的時候,這也是常說的“邏輯或”等待事件,在沒有超時的情況下 函數返回對應的事件標志位的值。xTicksToWait 最大超時時間,單位為系統節拍周期

返回值

返回事件中的哪些事件標志位被置位,返回值很可能并不是用戶指定的事件位,需要對返回值進行 判斷再處理 。

其應用類似某個全局變量,等待事件的任務在設定的時間內,監控該變量某些位的值;該值由其他任務或中斷修改。

九、 任務通知

FreeRTOS 從 V8.2.0 版本開始提供任務通知這個功能,可以在一定場合下替代 FreeRTOS 的信號量,隊列、事件組等,但是使用也有局限性。將宏定義 configUSE_TASK_NOTIFICATIONS 設置為 1才能開啟開功能。但該功能并不常用。

十、 內存管理

10.1 內存管理的概念

FreeRTOS 內存管理模塊管理用于系統中內存資源,它是操作系統的核心模塊之一。主要包括內存的初始化、分配以及釋放。一般不同的平臺移植代碼,內存的動態申請和釋放接口需要替換。嵌入式實時操作系統中,一般不支持標準C庫中的 malloc()和 free(),其內存有限,隨著內存不斷被分配和釋放,整個系統內存區域會產生越來越多的碎片。

FreeRTOS提供了 5 種內存管理算法,源文件在Source\portable\MemMang 路徑下,使用的時候選擇其中一個。heap_1.c、heap_2.c 和 heap_4.c 這三種內存管理方案,內存堆實際上是一個很大的 數 組ucHeap。

heap_1.c內存管理方案簡單,它只能申請內存而不能進行內存釋放。有些嵌入式系統并不會經常動態申請與釋放內存,一般都是在系統啟動后就一直使用下去,永不刪除,適合這種方式。

heap_2.c 方案支持釋放申請的內存,但是它不能把相鄰的兩個小的內存塊合成一個大的內存塊,對于每次申請內存大小都比較固定的;但每次申請并不是固定內存大小的則會造成內存碎片。如下圖,隨著不斷的申請釋放,空閑空間會變成很多小片段。

heap_3.c 方案只是封裝了標準 C 庫中的 malloc()和 free()函數,由編譯器提供,需要通過編譯器或者啟動文件設置堆空間。

heap_4.c 方案是在heap_2.c 基礎上,對內存碎片進行了改進,能把相鄰的空閑的內存塊合并成一個更大的塊,這樣可以減少內存碎片。

heap_5.c 方案在實現動態內存分配時與 heap4.c 方案一樣,采用最佳匹配算法和合并算法,并且允許內存堆跨越多個非連續的內存區,也就是允許在不連續的內存堆中實現內存分配,比如做圖形顯示,可能芯片內部的 RAM 不足,額外擴展SDRAM,那這種內存管理方案則比較合適。

一般物聯網平臺使用的是heap_4.c。

10.2 內存管理接口

不管其內部的管理如何實現的,對上層應用層的接口都是一樣的。

1.?void?*pvPortMalloc(?size_t?xSize?);?//內存申請函數??? 2.?void?vPortFree(?void?*pv?);??????????//內存釋放函數??? 3.?void?vPortInitialiseBlocks(?void?);?//初始化內存堆函數??? 4.?size_t?xPortGetFreeHeapSize(?void?);????//獲取當前未分配的內存堆大小??? 5.?size_t?xPortGetMinimumEverFreeHeapSize(?void?);?//獲取未分配的內存堆歷史最小值??

一般主要是使用內存申請和釋放兩個接口,用法和注意事項同malloc/free一樣,成對使用。內存釋放后盡量將指針設為NULL。

十一、 通用接口

一些常用接口進行說明。

11.1 臨界段

進入和退出臨界段的宏在 task.h 中定義,進入和退出臨界段的宏分中斷保護版本和非中斷版本,但最終都是通過開/關中斷來實現。主要用于對全局變量的控制,系統使用非常多,但實際項目中沒使用,因為全局變量的異常訪問時小概率問題,只是測試沒發現,理論上是存在問題的。

1.?/*?在中斷場合*/??{??? 2.?????uint32_t?ulReturn;??? 3.????? 4.?????ulReturn?=?taskENTER_CRITICAL_FROM_ISR();?/*?進入臨界段,臨界段可以嵌套?*/??? 5.????? 6.?????/*?臨界段代碼?*/?????? 7.???????? 8.?????taskEXIT_CRITICAL_FROM_ISR(?ulReturn?);??}???/*?退出臨界段?*/ 1.??/*?在非中斷場合?*/??{??? 2.??????? 3.?????taskENTER_CRITICAL();?????/*?進入臨界段?*/? 4.? 5.?????/*?臨界段代碼?*/???? 6.????? 7.?????taskEXIT_CRITICAL();??}???/*?退出臨界段*/??

11.2 任務阻塞延時

vTaskDelay ()阻塞延時,任務調用該延時函數后會被剝離 CPU 使用權,進入阻塞狀態,直到延時結束。但是該函數不能用在中斷服務和定時回調函數。延時單位是tick。

11.3 獲取系統時鐘計數值

1.?TickType_t?xTaskGetTickCount(?void?)?? 2.?TickType_t?xTaskGetTickCountFromISR(?void?)??

注意該接口分任務版和中斷版,該接口獲取的是tick計數值,需要結合系統時鐘頻率轉換成時間。

11.4 中斷回調函數

和其它平臺不同,中斷回調中釋放中斷標記即可,freeRTOS中,中斷觸發后,可能某些阻塞的任務獲取了相關信號,需要立刻執行,因此中斷服務發送消息后,需要主動查詢阻塞任務的情況,執行任務切換動作。

1.?static?uint32_t?ulExampleInterruptHandler(?void?)?? 2.?{?? 3.?????BaseType_t?xHigherPriorityTaskWoken;?? 4.? 5.?????xQueueSendToBackFromISR?(xQueueRx,&cChar,&xHigherPriorityTaskWoken);?? 6.?????portYIELD_FROM_ISR(xHigherPriorityTaskWoken);?? 7.?}??

推薦閱讀:

? ??專輯|Linux文章匯總

? ??專輯|程序人生

? ??專輯|C語言

嵌入式Linux

微信掃描二維碼,關注我的公眾號?

總結

以上是生活随笔為你收集整理的FreeRTOS及其应用,万字长文,基础入门的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

成人黄色大片在线观看 | 亚洲伦理中文字幕 | 久久不卡国产精品一区二区 | 91传媒91久久久| 在线观看视频一区二区三区 | 中文字幕乱码一区二区 | 成人黄在线 | 国产午夜精品一区二区三区嫩草 | 亚洲男人天堂a | 另类老妇性bbwbbw高清 | 欧美日韩激情视频8区 | 欧美少妇xxx | av在线日韩| 91爱爱网址 | 色悠悠久久综合 | 99热在线国产 | 在线观看网站你懂的 | 四虎影视成人永久免费观看视频 | 日韩在线观看 | 日本一区二区高清不卡 | 91网在线看 | www.久久婷婷 | 天天人人 | 日韩在线一二三区 | 成人免费观看av | 亚洲春色综合另类校园电影 | 在线激情电影 | 激情婷婷久久 | 国产理论影院 | 97超碰国产精品女人人人爽 | 日韩在线视频播放 | 五月婷综合网 | 久久高清毛片 | 99re8这里有精品热视频免费 | 色综合久久中文综合久久牛 | 在线观看视频在线 | 亚洲永久精品在线观看 | 婷婷五月色综合 | 99视频免费观看 | 香蕉视频网站在线观看 | 午夜精品福利一区二区三区蜜桃 | 久久久久日本精品一区二区三区 | 色在线最新 | 亚洲第一区在线观看 | 久久国产精品久久国产精品 | 色综合久久88色综合天天 | 色资源网免费观看视频 | 99久久精品国产免费看不卡 | 正在播放久久 | 看v片| 日韩在线免费电影 | 国产高清网站 | 99免费| 成人资源站 | а天堂中文最新一区二区三区 | 亚洲黄色成人av | 99视频精品全部免费 在线 | 伊甸园永久入口www 99热 精品在线 | 天天婷婷| 在线欧美小视频 | 丝袜av网站 | 亚洲无线视频 | 超碰在线97国产 | 日韩一区在线免费观看 | 国产精品久久片 | 毛片.com| 91豆花在线观看 | 久久久精品欧美 | 日韩首页| 蜜桃麻豆www久久囤产精品 | 麻豆传媒在线视频 | 亚洲理论在线观看电影 | 500部大龄熟乱视频使用方法 | 蜜臀aⅴ精品一区二区三区 久久视屏网 | 国产精品美女毛片真酒店 | 免费成人在线网站 | 国产丝袜网站 | 亚洲精品乱码久久久久v最新版 | 久久久影视 | 91桃花视频 | 在线视频麻豆 | 免费国产在线视频 | 久久中文字幕在线视频 | 在线中文字幕播放 | 黄色小网站在线观看 | 97偷拍视频 | 国产一区二区在线精品 | 九九在线播放 | 99久久久成人国产精品 | 久草视频在线看 | 久久久高清免费视频 | 久操久 | 久久一区二区三区日韩 | 亚洲最大的av网站 | 免费av在线| 成年人免费看片 | 久久精品资源 | 91精品91| 免费黄a| 成 人 黄 色 视频 免费观看 | 手机成人av在线 | 欧美三人交 | 在线播放 日韩专区 | 日批视频在线 | 中文字幕乱在线伦视频中文字幕乱码在线 | 久久天天躁 | 国产一区二区电影在线观看 | 久久激情五月婷婷 | 国产96在线| 成人性生活大片 | 免费成人黄色片 | 99久久影视 | 在线观看福利网站 | 黄污在线观看 | 国产精品一区二区三区电影 | 亚洲国产成人精品在线 | 天天操天天干天天操天天干 | 亚洲男男gaygayxxxgv | 天天综合天天做天天综合 | 中文免费在线观看 | 99精品在线免费在线观看 | 在线观看国产日韩欧美 | 99热在线观看| 亚洲综合成人专区片 | 国产香蕉av | 欧美日韩精品电影 | 国产麻豆精品久久一二三 | 激情五月婷婷激情 | 在线看中文字幕 | 视频一区亚洲 | 国产香蕉久久精品综合网 | 日韩欧美在线国产 | 九色精品在线 | 2018精品视频| 亚洲精品国产综合99久久夜夜嗨 | 91大神dom调教在线观看 | 国产精品一区二区三区久久久 | 国产成人久久精品77777 | 狠狠干综合 | 欧美性生活一级片 | 开心激情综合网 | 超碰在线公开 | 色在线国产 | 久久观看最新视频 | 91亚洲精品乱码久久久久久蜜桃 | 国产在线视频导航 | 99视频在线免费观看 | 日韩一二区在线 | 国产视频18 | 国产91综合一区在线观看 | 欧美午夜一区二区福利视频 | 久久免费视频国产 | 久草香蕉在线视频 | 人人干狠狠操 | 国产精品久久久久久久久久 | 成人动漫视频在线 | 7799av | 日日夜夜骑 | 免费特级黄色片 | 97碰在线视频 | 婷婷在线网站 | 日本动漫做毛片一区二区 | 在线观看免费黄色 | 九色91av| 日韩欧美高清免费 | 欧美精品免费在线观看 | 欧美二区在线播放 | 欧美精品亚洲精品 | 成人一级在线观看 | av在线电影网站 | 国产一区网址 | 国产成人精品午夜在线播放 | 国产精品毛片一区视频播不卡 | 精品国产乱码久久久久久浪潮 | 欧美一级黄色视屏 | 欧美精品在线一区二区 | 国产亚洲精品久久久久久网站 | 亚洲国产网站 | 手机成人av在线 | www久久99 | a久久免费视频 | 日韩最新在线 | 欧美日韩二区在线 | 91精品国产麻豆国产自产影视 | 免费久久99精品国产婷婷六月 | 黄色亚洲片| 精品一区二区免费在线观看 | 久久人人爽人人爽人人 | 久久久91精品国产一区二区精品 | 美女网站在线免费观看 | 天天干夜夜操视频 | 久久免费在线观看视频 | 欧美另类美少妇69xxxx | 久久热亚洲 | 韩国av不卡 | 欧美精品网站 | 日产乱码一二三区别免费 | 日韩视频1区 | 久热国产视频 | 久久亚洲专区 | 欧美成人播放 | 久久伊人热| 天天天干天天射天天天操 | 亚洲精品一区二区久 | 五月婷婷综合久久 | 高清精品久久 | www.精选视频.com | 最新中文字幕在线资源 | 蜜臀一区二区三区精品免费视频 | 亚洲成人精品 | 啪啪激情网 | 国产日产在线观看 | 国产日产欧美在线观看 | 欧美一区二区三区在线观看 | 国产99久久久欧美黑人 | 国产精品国产三级国产不产一地 | 日本中文字幕在线电影 | 久久草在线免费 | 狠狠的日日| 婷婷色网视频在线播放 | 九九国产视频 | 97成人超碰| 国产在线一区观看 | 国产一级做a爱片久久毛片a | 天天爱天天射天天干天天 | 在线观看国产一区二区 | 久久婷婷激情 | 久久精品一区二 | 天堂av在线免费 | 99热在| 国产日本在线播放 | 国产成人在线免费观看 | 日韩一区二区三区不卡 | 在线成人观看 | 久久久99精品免费观看乱色 | 欧美一级看片 | 欧美极品在线播放 | 国产无遮挡猛进猛出免费软件 | 中文字幕在线视频免费播放 | 欧美一级片在线免费观看 | 国产96av| 午夜美女网站 | 国产精品久久久久永久免费观看 | 欧美一级视频在线观看 | 亚洲精品视频在线播放 | 中文字幕一区二区三区乱码在线 | 国产乱视频 | 日本三级不卡视频 | 九九亚洲视频 | 成人h视频在线播放 | 国产精品久久久久久久久久久久 | 国产精品久久久久影院日本 | 久久久精品国产一区二区 | 黄a在线观看 | 亚洲午夜大片 | 九九交易行官网 | 国产亚洲欧美在线视频 | 欧美aa级 | 五月开心六月伊人色婷婷 | 最近中文国产在线视频 | 狠狠躁夜夜av | 欧美精品二 | 91亚洲欧美激情 | 欧美激情奇米色 | 日日躁夜夜躁xxxxaaaa | 91福利视频一区 | 天天操天天干天天干 | 久久综合免费视频 | 精品国产一区二区三区四区vr | 黄色特一级片 | 手机看片国产日韩 | 国产一区在线免费观看视频 | 96亚洲精品久久 | 国产探花视频在线播放 | 国产精品va在线观看入 | 欧美一区二区三区四区夜夜大片 | 日本久久久影视 | 国产精品精品久久久久久 | 91九色视频在线播放 | 国产精品久久久久久久久久直播 | 日韩午夜网站 | 人人爽人人舔 | 在线观看911视频 | 99在线热播精品免费 | 特级毛片网 | 碰超在线观看 | 免费av网站在线看 | 91黄色影视 | 青青草国产成人99久久 | 日韩中文免费视频 | www在线免费观看 | 国产精品精品国产色婷婷 | 日本精品小视频 | 一区二区三区在线不卡 | av三级在线播放 | 欧美一区二区三区在线观看 | 久久天堂精品视频 | 深爱激情综合网 | 婷婷综合国产 | 色99网| 2024国产精品视频 | 国产黄色片网站 | 激情综合中文娱乐网 | 日日干干 | 亚洲最新av| 特级毛片在线观看 | 国产v在线观看 | 久久免费国产视频 | 亚洲女欲精品久久久久久久18 | 亚洲情婷婷 | 91夜夜夜| 亚洲精品福利视频 | 成人av网站在线观看 | 玖玖在线播放 | 黄在线免费观看 | 免费99视频 | 一二区电影 | 国产精品岛国久久久久久久久红粉 | 国产三级视频在线 | 久久久精品二区 | 国产精品久久久久影院日本 | 伊人婷婷久久 | 婷婷久久五月天 | www.五月天激情 | 亚洲三级黄 | 中文在线字幕免 | 就要色综合 | 久久婷婷视频 | 亚洲欧美视频 | 国产区精品区 | 久久夜色精品国产亚洲aⅴ 91chinesexxx | 国产一级片免费播放 | 日韩三级视频在线观看 | 四虎在线免费 | 91视频麻豆 | 国产69久久久欧美一级 | 国产成人精品国内自产拍免费看 | 丁香六月久久综合狠狠色 | 99色在线播放 | 91精品国产三级a在线观看 | 国产玖玖在线 | 丰满少妇在线观看 | 日韩三级av | 国产永久免费高清在线观看视频 | 国产精品免费麻豆入口 | 美女网站视频免费都是黄 | 91av片| 国产免费大片 | 91网免费观看 | 成人黄视频 | 精品中文字幕在线 | 摸bbb搡bbb搡bbbb | 久久久 精品 | 亚洲男男gaygay无套同网址 | 911久久香蕉国产线看观看 | 国产日韩欧美自拍 | 日韩精品一区二区三区高清免费 | 亚洲精品乱码久久久久久按摩 | 久久黄色小说视频 | 在线播放一区 | 久久国产热 | 亚洲精品视频偷拍 | 亚洲午夜精品久久久 | 欧美日韩视频在线观看一区二区 | 久草视频免费播放 | 日韩有色 | 中文在线a在线 | 91精品久久久久久久99蜜桃 | 亚洲精品伦理在线 | 超碰在线人人爱 | 久草在线官网 | 国产精品乱码在线 | av在线播放国产 | 久久视频国产 | 欧美精品午夜 | 成人黄色大片在线免费观看 | www.香蕉 | 亚洲狠狠| 亚洲精品在线观看中文字幕 | 久久躁日日躁aaaaxxxx | 91精品国| 日韩中字在线 | 久草在线播放视频 | 亚洲资源视频 | 国产在线成人 | 久草久草久草久草 | 亚洲九九爱 | 日韩专区在线 | 国产字幕在线看 | 国产一区二区日本 | 国产精品中文字幕在线 | 六月丁香激情综合色啪小说 | 国产美女久久 | 国产片免费在线观看视频 | 成人四虎影院 | 91精品欧美一区二区三区 | 色先锋资源网 | www.日韩免费 | 99视频免费观看 | 色网免费观看 | 一区二区中文字幕在线观看 | 欧美日韩精品网站 | 天天综合网 天天综合色 | 超碰在线94| 91av视频在线观看免费 | 激情久久综合网 | 91伊人影院| 欧美激情精品久久久久久免费印度 | 日日噜噜噜噜夜夜爽亚洲精品 | 国产一区二区高清不卡 | 性日韩欧美在线视频 | 女人18毛片90分钟 | 国产精品一区二 | 国产中文字幕在线看 | 国产裸体视频网站 | 在线免费高清一区二区三区 | 日韩在线观看三区 | 一区二区三区四区五区在线 | zzijzzij亚洲日本少妇熟睡 | 久久y| 国产精品免费久久久久 | 免费看的黄色的网站 | 国产精品69av | 久久ww| 久久久久久久久久久久99 | 国产精品嫩草55av | 伊人伊成久久人综合网站 | 91av在线精品 | av片一区二区 | 波多野结衣一区三区 | 91精品国产一区二区三区 | 国产精品毛片一区二区三区 | 国产精品尤物 | 中文字幕在线视频免费播放 | 亚欧洲精品视频在线观看 | 91精品欧美一区二区三区 | 久久精品爱爱视频 | 韩国三级在线一区 | 国产精品亚洲片夜色在线 | 久久另类视频 | 激情久久综合 | 国产不卡网站 | 91久久爱热色涩涩 | a在线视频v视频 | 精品久久一 | 久久亚洲欧美日韩精品专区 | 91精品久久久久久久99蜜桃 | 婷婷免费在线视频 | 亚洲精品五月 | 韩国一区视频 | 操操日日 | 在线观看成人网 | 欧美天堂视频在线 | 九九热在线播放 | 国产区在线视频 | 亚洲狠狠干 | 美女国产在线 | 日本中文字幕视频 | 精品国产观看 | 国产欧美最新羞羞视频在线观看 | 日本久久成人中文字幕电影 | 怡红院久久 | 天天色天天艹 | 91丨九色丨国产女 | 色综合久久88色综合天天免费 | 麻豆久久久 | 国产成人一区二区三区免费看 | 日韩三级不卡 | 国产一级片直播 | 亚洲婷婷在线视频 | 亚洲美女视频在线观看 | 五月婷婷香蕉 | av中文字幕网址 | 国产精品久久一 | 中文字幕国内精品 | 天天干夜夜想 | 久久久久综合网 | 亚洲黄色成人网 | 91传媒免费观看 | 国产一区二区三区高清播放 | 黄色福利网 | 国产高清黄 | 国产精品视频久久久 | 91av观看| 日韩欧美一区二区三区在线观看 | 18久久久 | 亚洲精品无 | 久草视频看看 | 久久公开免费视频 | 久久免费在线 | 99人成在线观看视频 | 91天天视频 | 日韩成人精品一区二区三区 | bayu135国产精品视频 | 婷婷国产v亚洲v欧美久久 | 美女网站视频免费黄 | 在线草 | 青青视频一区 | 国产一区视频在线观看免费 | 色噜噜日韩精品一区二区三区视频 | av三级av | 国产精品免费视频久久久 | 国产视频观看 | 欧美最猛性xxxxx免费 | 亚洲精品伦理在线 | 欧美日韩a视频 | 91精品啪在线观看国产 | 伊人天天操| 激情欧美xxxx | 五月天婷婷丁香花 | 亚洲专区欧美专区 | 欧美一级视频免费 | 免费看片黄色 | 91超国产| 国产精品综合久久久 | mm1313亚洲精品国产 | 国产伦精品一区二区三区无广告 | 国产成人综| 毛片基地黄久久久久久天堂 | 国产伦理久久精品久久久久_ | 中文字幕在线观看91 | 91视频三区| 98超碰在线 | 国产高清视频免费观看 | 日韩欧美视频一区二区 | 久久一区二区三区超碰国产精品 | 日韩电影精品 | 国产一级片直播 | 久久老司机精品视频 | 狠狠色伊人亚洲综合成人 | 精品亚洲va在线va天堂资源站 | 国产精品午夜免费福利视频 | 在线观看免费高清视频大全追剧 | 免费日韩三级 | 亚洲国产中文字幕在线视频综合 | 国产精品国产毛片 | 日产av在线播放 | 六月丁香六月婷婷 | 成人黄色电影在线播放 | 免费av黄色 | 9在线观看免费高清完整版 玖玖爱免费视频 | 韩国三级一区 | 操操操日日 | 91网页版免费观看 | 999久久国产精品免费观看网站 | 久久伊99综合婷婷久久伊 | 波多野结衣小视频 | 免费观看第二部31集 | 一 级 黄 色 片免费看的 | 91九色国产蝌蚪 | 午夜影院先 | 久久综合九色综合欧美就去吻 | 在线一二三四区 | 国产黄色片免费观看 | 日本精品一二区 | 欧美一区免费观看 | 97国产超碰在线 | 国产精品成人国产乱 | 色网站黄 | 国产精品久久久久久五月尺 | 日韩欧美综合在线视频 | 亚洲精品中文在线 | 视频国产精品 | 米奇狠狠狠888 | 久久久麻豆| 日韩在线电影观看 | 国产女人18毛片水真多18精品 | 亚洲a在线观看 | 亚洲国产综合在线 | 一级黄色片毛片 | 久草网站在线观看 | 色福利网 | 亚洲视频h| 成人在线观看免费视频 | 午夜视频播放 | 久久精品视频国产 | 婷婷丁香激情网 | 国产高清永久免费 | 草久视频在线 | www免费看 | 日日骑| 久久精品国产久精国产 | 韩国精品一区二区三区六区色诱 | 国产最新精品视频 | 久久久久久久av麻豆果冻 | 四川bbb搡bbb爽爽视频 | 国产精品原创视频 | 91视频久久久 | 欧美一级艳片视频免费观看 | 国产在线中文字幕 | 偷拍精品一区二区三区 | 国产在线一区二区 | 天天色棕合合合合合合 | 久久蜜臀av| 黄色国产高清 | 91精品人成在线观看 | 黄色性av | 成人资源在线 | 在线亚州 | 97超碰国产精品女人人人爽 | 久久免费视频这里只有精品 | 人人精久| 美女av免费看 | 日韩精品短视频 | 超碰97网站 | 欧美99精品 | 国产亚洲一级高清 | 国产精品电影在线 | 日日夜日日干 | 正在播放国产一区 | 久久精品一级片 | 国产精品久久一区二区三区不卡 | 欧美一区二区三区激情视频 | 最近中文字幕视频完整版 | 国产高清免费 | 国产精品午夜8888 | 欧美a影视| 97色在线 | 九九精品久久 | 欧美一区二区三区在线播放 | 国产69精品久久99不卡的观看体验 | 亚洲免费视频观看 | 日韩在线视频二区 | 九九色视频 | 99热这里只有精品在线观看 | 日韩精品视频免费看 | 91综合久久一区二区 | 丁香婷婷电影 | 亚洲一级片在线看 | 视频1区2区 | 亚洲精品美女久久久久网站 | 欧美综合在线视频 | 亚洲成人午夜av | 日韩精品视频在线观看免费 | 成人黄色免费在线观看 | 亚洲天堂网站 | 蜜臀av免费一区二区三区 | 在线免费色 | 4hu视频| 久久97超碰| 国产精品视频不卡 | 日韩一级成人av | 国产原创在线视频 | 成片视频在线观看 | 444av| 婷婷在线观看视频 | 欧产日产国产69 | www.久久久.com| 日韩精品免费专区 | 久视频在线播放 | 亚洲五月六月 | 天堂网在线视频 | 午夜 久久 tv | 精品视频免费在线 | www.久久久.cum | 久久97久久97精品免视看 | 亚洲做受高潮欧美裸体 | 国产一区在线视频播放 | 亚洲欧洲av | 六月激情丁香 | 天天操天天操天天操天天 | 中国美女一级看片 | 国产精品视频地址 | 麻豆一精品传二传媒短视频 | 麻豆视屏 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 美女网站色在线观看 | 国精产品999国精产品岳 | 久久综合婷婷国产二区高清 | 综合精品久久 | 久久久精品网 | 欧美一级片在线 | 久久人人97超碰精品888 | 国产精品久久久久久久7电影 | 国产中文字幕在线观看 | 黄色特级毛片 | av专区在线 | 91福利区一区二区三区 | 亚洲日本精品视频 | 中文字幕在线视频一区 | 激情伊人五月天久久综合 | av大全在线观看 | 最近能播放的中文字幕 | 亚洲午夜久久久久久久久久久 | 在线观看精品一区 | 九九欧美视频 | 夜夜躁日日躁狠狠久久88av | 人人插人人草 | 精品九九九 | 免费一级片视频 | 中文av影院 | 免费av在线网站 | 在线视频观看成人 | 久久精品美女 | 色婷婷综合久久久 | 亚洲成人av在线播放 | 国产99久久久精品 | 黄色三级在线 | 久草视频在线播放 | 欧美疯狂性受xxxxx另类 | 国产一区二区精品久久 | 日韩av中文字幕在线免费观看 | 久草在线免费资源 | 国产一区二区在线免费视频 | 久久久久99999 | 99r在线精品| 久久在线免费 | 91精品啪在线观看国产 | 黄色一及电影 | 亚洲精品免费在线观看视频 | 午夜精品福利一区二区三区蜜桃 | 久久露脸国产精品 | 国产精品一区二区免费在线观看 | 91九色porn在线资源 | 丁香五月亚洲综合在线 | 久99久在线| 日日操操 | 国语精品久久 | 久久久一本精品99久久精品66 | 天天躁天天狠天天透 | 日日干美女 | 久久精品欧美一区二区三区麻豆 | 欧美午夜性 | 亚洲一区二区三区在线看 | 91久久精品一区 | 99久久电影 | 日韩四虎| 中文字幕观看在线 | 国产一区成人在线 | 精品久久久久久久久久久久 | 久久夜色精品国产欧美乱极品 | 久草资源免费 | 国产日韩欧美在线看 | 99re8这里有精品热视频免费 | 九九热99视频 | 久久这里只有精品9 | 91成人精品一区在线播放69 | 丁香花中文在线免费观看 | 国产精品毛片完整版 | 欧美一级黄大片 | 久久久久国产精品一区二区 | 丁香六月激情 | 国产精品第54页 | 中文在线www | 在线观看中文字幕网站 | 九九热有精品 | 18国产精品白浆在线观看免费 | 日韩精品中文字幕在线观看 | 免费黄a | 欧美久久久一区二区三区 | 综合久久2023 | 久久色在线观看 | av网址最新| 久精品一区 | 国产v在线播放 | 亚洲精品小区久久久久久 | 人人插人人舔 | 中文字幕在线观看三区 | 91精品在线播放 | 日韩在线短视频 | 麻豆免费视频 | 麻豆精品传媒视频 | 国产精品1区2区在线观看 | 欧美日韩视频在线一区 | 欧美另类xxxx | 91成人久久 | 久久超碰在线 | 99热国产精品 | 国产婷婷视频在线 | 黄色亚洲大片免费在线观看 | 网站免费黄 | 日韩精品一区二区三区中文字幕 | 中文字幕91视频 | 久久免费黄色 | www亚洲视频 | 午夜精品久久久久久久久久 | 日韩在线视频免费播放 | 国产专区视频 | 精品久久亚洲 | 麻豆视频91 | 99久久999久久久精玫瑰 | 国产亚洲午夜高清国产拍精品 | 在线91精品 | 日日狠狠| 欧美久久影院 | 欧美韩国在线 | 欧美国产一区二区 | 91手机在线看片 | 国产一二区精品 | 欧美一区三区四区 | av午夜电影| 国产精品网红直播 | 日韩动态视频 | 精品久久久久久久 | 欧美极品少妇xxxx | 久草在线免费看视频 | 久久亚洲电影 | 国产伦精品一区二区三区无广告 | 成人91免费视频 | 日韩成人邪恶影片 | 综合婷婷| 久久香蕉国产精品麻豆粉嫩av | 久久在线播放 | 久久综合九色综合久99 | 四虎海外影库www4hu | 亚洲精品456在线播放第一页 | 日韩视频免费播放 | 天天色天天综合网 | 久久免费国产视频 | 国产日产欧美在线观看 | 黄色三级免费观看 | 六月婷婷网 | 人人草在线观看 | 久久国产麻豆 | 久久草草热国产精品直播 | 伊香蕉大综综综合久久啪 | 国产精品淫片 | 中文字幕在线精品 | 国产日本高清 | 国产成人精品国内自产拍免费看 | 成人性生交大片免费看中文网站 | 日本99热| 91污污视频在线观看 | 国产精品免费视频一区二区 | 丁香九月激情综合 | 久久九九精品 | 国产精品一级视频 | 色综合久久久久综合 | 欧美aaaxxxx做受视频 | 91精品老司机久久一区啪 | 女人魂免费观看 | 亚洲精品视频二区 | 手机成人在线电影 | 精品久久国产 | 91在线资源 | 成年人免费电影在线观看 | 日韩精品一区二区三区在线播放 | 国产精品激情在线观看 | 国产一区二区视频在线播放 | 中国一级片免费看 | 国产精品久久久久久高潮 | 亚洲高清在线观看视频 | 久久这里有精品 | 五月婷在线视频 | 久久亚洲区 | 成人av在线直播 | 久草电影免费在线观看 | 久久精品这里都是精品 | 99精品在线观看 | 亚洲第一区在线观看 | 天天激情在线 | 一区久久久 | 国内视频一区二区 | 国产在线视频不卡 | 中文字幕一区二区三区在线视频 | 精品91久久久久 | 国产又粗又硬又爽的视频 | 韩国av免费看 | 成人av影院在线观看 | 黄色免费网站 | 在线黄色av | 亚洲精品一区二区在线观看 | 久久精品国产精品亚洲 | 亚洲免费观看在线视频 | 91成人网在线 | 成人91视频 | 天天射天天色天天干 | 四虎在线观看精品视频 | 99视频精品免费视频 | 99免费精品视频 | 日韩精品免费一区 | 国产黄色片久久 | 麻豆视频免费版 | 在线黄色国产电影 | av天天澡天天爽天天av | 久草在线观看资源 | 午夜av一区 | 国产69精品久久99不卡的观看体验 | 婷婷在线视频观看 | 国产资源在线观看 | 亚洲h色精品 | 在线观看视频在线 | 五月婷在线 | 美女视频永久黄网站免费观看国产 | 成人av动漫在线 | www黄色大片 | 久久久久国产a免费观看rela | 亚洲免费专区 | 欧美精品国产综合久久 | 亚洲免费在线视频 | 亚洲 av网站 | 精品国产三级 | 日韩免费播放 | 国产精品99久久久精品 | 国产91全国探花系列在线播放 | 国产.精品.日韩.另类.中文.在线.播放 | 成年人在线观看视频免费 | 欧美日韩国产一区二区三区在线观看 | 国产99区| 久久亚洲区 | 在线黄色毛片 | 免费h视频 | 美女国内精品自产拍在线播放 | 香蕉一区 | 欧美一进一出抽搐大尺度视频 | 51精品国自产在线 | 欧美成人aa| 97福利视频| 国产精品地址 | 日韩经典一区二区三区 | 久久久久久久久久久免费 | 免费看黄色大全 | 国产精品一区二区无线 | 九九热精品国产 | 黄色av网站在线观看免费 | 日本黄色免费在线 | 美女黄濒| 1000部国产精品成人观看 | 亚洲视频在线观看 | 夜夜操狠狠干 | 国产精品1000 | 欧美午夜激情网 | 成人精品99 | 在线免费av观看 | 国产美女视频一区 | 日本免费一二三区 | 欧美成人高清 | 久久www免费视频 | 91黄站| 成人黄色小说视频 | japanese黑人亚洲人4k | 欧洲激情在线 | 日韩三级免费 | 天天操天天爱天天爽 | 欧美激情片在线观看 | 日韩av免费在线看 | 五月婷婷在线视频 | 精品黄色视 | www国产亚洲 | 久久99精品波多结衣一区 | 91视频在线免费看 | 国产精品久久一 | 天天爱综合 | 国产美女网站视频 | 99视频一区 | 在线观看视频免费播放 | 久久综合九色综合久久久精品综合 | 91亚洲精品国偷拍自产在线观看 | 日韩黄色在线电影 | wwxxxx日本 | 色狠狠干 | www.夜色321.com| 成人在线观看资源 | 国产高清视频在线观看 | 特级aaa毛片 | 天天天天天天天天操 | 欧美视频在线观看免费网址 | 在线观看亚洲电影 | 国产高清视频在线播放一区 | 精品久久久成人 | 国产精品大片免费观看 | 色噜噜日韩精品欧美一区二区 | 色视频在线免费观看 | 成人在线中文字幕 | 日日干 天天干 | 日韩精品久久一区二区三区 | 亚洲视频网站在线观看 | 亚洲视频999 | 日本最新高清不卡中文字幕 | 成人免费大片黄在线播放 | 欧美精品久久久久久久久久丰满 | 狠狠色丁香婷婷综合久小说久 | 在线观看视频福利 | 成年人在线看视频 | 99精品热视频 | 国产精品第二页 | 91精品久久久久久综合五月天 | 日韩一区二区免费在线观看 | 99亚洲精品在线 | 欧美日韩国产xxx | 久久久官网 | 国产一区二三区好的 | 综合久久精品 | 天天射色综合 | 亚洲精品综合在线观看 | 久久精品国产99 | 天天av资源 | 日韩一区二区三区观看 | 国产午夜精品视频 | 亚洲精品一区二区网址 | 毛片在线播放网址 | 欧美激情片在线观看 | 天天艹天天| 日韩在线视频在线观看 | 久久视频在线免费观看 | 91九色精品 | 狠狠色狠狠色综合系列 | 看污网站 |