版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、嵌入式實(shí)時(shí)系統(tǒng) -FreeRTOS,1、FreeRTOS簡(jiǎn)介,FreeRTOS是一個(gè)嵌入式系統(tǒng)使用的開(kāi)源實(shí)時(shí)系統(tǒng)。 FreeRTOS小巧,簡(jiǎn)單,易用。能支持許多不同硬件 架構(gòu)以及交叉編譯器。 此系統(tǒng)可以免費(fèi)進(jìn)行商業(yè)應(yīng)用,被大量公司與科研公司用于嵌入式產(chǎn)品的開(kāi)發(fā)。 支持的處理器架構(gòu):ARM7,ARM9,COLTEX-m3、AVR、PIC等。,1、FreeRTOS簡(jiǎn)介,嵌入式系統(tǒng): 一個(gè)專(zhuān)門(mén)設(shè)計(jì)用來(lái)做一些簡(jiǎn)單事情的計(jì)算機(jī)系統(tǒng),如電視遙控器,車(chē)載GPS,電子手表,或者起搏器這類(lèi)。嵌入式系統(tǒng)比通用計(jì)算機(jī)系統(tǒng)更小更慢,通常也更便宜。 如:低端:一個(gè)運(yùn)行速度為25MHz的8位CPU, 幾KB的內(nèi)存。 高端
2、:一個(gè)運(yùn)行速度為750MHz的32位 CPU,一個(gè)GB左右的內(nèi)存,和幾個(gè)GB的閃存。,1、FreeRTOS簡(jiǎn)介,實(shí)時(shí)(RT) 軟實(shí)時(shí):按照任務(wù)的優(yōu)先級(jí),盡可能快地完成操作即可 。 硬實(shí)時(shí):硬實(shí)時(shí)要求在規(guī)定的時(shí)間內(nèi)必須完成操作 。,1、FreeRTOS簡(jiǎn)介,系統(tǒng)基本架構(gòu) 其代碼可以分解為三個(gè)主要區(qū)塊: 任務(wù) 通訊 硬件接口 任務(wù):大約50%的FreeRTOS的核心代碼,1、FreeRTOS簡(jiǎn)介,通訊:大約40%的FreeRTOS核心代碼是用來(lái)處理通訊的。任務(wù)和中斷使用隊(duì)列互相發(fā)送數(shù)據(jù),并且使用信號(hào)燈和互斥來(lái)發(fā)送臨界資源的使用情況。 硬件接口:大約有6%的FreeRTOS的核心代碼,在硬件無(wú)關(guān)的F
3、reeRTOS內(nèi)核與硬件相關(guān)的代碼間扮演著墊片的角色。,2、任務(wù)簡(jiǎn)介,2.1任務(wù)函數(shù) 任務(wù)是由C語(yǔ)言函數(shù)實(shí)現(xiàn)的。任務(wù)函數(shù)其必須返回void, 而且?guī)в幸粋€(gè)void指針參數(shù)。其函數(shù)原型參見(jiàn)程序清單1。 void ATaskFunction( void *pvParameters ); 程序清單1 任務(wù)函數(shù)原型,2.1任務(wù)函數(shù),注意事項(xiàng): FreeRTOS 任務(wù)不允許以任何方式從實(shí)現(xiàn)函數(shù)中返回它們絕不能有一條”return”語(yǔ)句,也不能執(zhí)行到函數(shù)末尾。如果一個(gè)任務(wù)不再需要,可以顯式地將其刪除 (void vTaskDelete( xTaskHandlepxTaskToDelete );)。,2.1
4、任務(wù)函數(shù),創(chuàng)建任務(wù): 創(chuàng)建任務(wù)使用FreeRTOS的API函數(shù)xTaskCreate()。 程序清單2,2.1任務(wù)函數(shù),參數(shù)介紹 : pvTaskCode 一個(gè)指向任務(wù)的實(shí)現(xiàn)函數(shù)的指針(效果上僅僅是函數(shù) 名)。 pcName 具有描述性的任務(wù)名。這個(gè)參數(shù)不會(huì)被FreeRTOS使用。其只是單 純地用于輔助調(diào)試。usStackDepth 當(dāng)任務(wù)創(chuàng)建時(shí),內(nèi)核會(huì)分為每個(gè)任務(wù)分配屬于任務(wù)自己的唯一狀態(tài)。 usStackDepth值用于告訴內(nèi)核為它分配多大的??臻g。 這個(gè)值指定的是??臻g可以保存多少個(gè)字(word),而不是多少個(gè)字 節(jié)(byte)。比如說(shuō),如果是32位寬的??臻g,傳入的usStackDep
5、th 值為100,則將會(huì)分配400字節(jié)的??臻g(100 * 4bytes)。 。,參數(shù): pvParameters 任務(wù)函數(shù)接受一個(gè)指向void的指針(void*)。 pvParameters的值即是傳遞到任務(wù)中的值。 uxPriority 指定任務(wù)執(zhí)行的優(yōu)先級(jí)。優(yōu)先級(jí)的取值范圍可以從最低優(yōu)先級(jí)0到最高優(yōu)先級(jí)(configMAX_PRIORITIES 1)。 configMAX_PRIORITIES 是一個(gè)由用戶定義的常量。 pxCreatedTask 用于傳出任務(wù)的句柄。這個(gè)句柄將在API調(diào)用中對(duì)該創(chuàng)建出來(lái)的任務(wù)進(jìn)行引用,比如改變?nèi)蝿?wù)優(yōu)先級(jí),或者刪除任務(wù)。如果應(yīng)用程序中不會(huì)用到這個(gè)任務(wù)的句柄
6、,則pxCreatedTask可以 被設(shè)為NULL,返回值 有兩個(gè)可能的返回值: 1.pdTRUE 表明任務(wù)創(chuàng)建成功。 2.errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY 由于內(nèi)存堆空間不足,F(xiàn)reeRTOS無(wú)法分配足夠的空間來(lái)保存任務(wù)結(jié)構(gòu)數(shù)據(jù)和任務(wù)棧,因此無(wú)法創(chuàng)建任務(wù)。 第五章將提供更多有關(guān)內(nèi)存管理方面的信息。,2.1任務(wù)函數(shù),例1. 創(chuàng)建任務(wù) 本例演示了創(chuàng)建并啟動(dòng)兩個(gè)任務(wù)的必要步驟。 兩個(gè)任務(wù)內(nèi)容: 周期性地打印輸出字符串。 兩者在創(chuàng)建時(shí)指定了相同的優(yōu)先級(jí)。,任務(wù)一:周期性輸出: Task 1 is runningrn,任務(wù)二:周期性輸出: Task 2 is
7、runningrn,main()函數(shù):簡(jiǎn)單地創(chuàng)建這兩個(gè)任務(wù),然后啟動(dòng)調(diào)度器,運(yùn)行結(jié)果: 圖一,2.1任務(wù)函數(shù),任務(wù)分配分析: 圖2中看到兩個(gè)任務(wù)在同時(shí)運(yùn)行,事實(shí)上這兩個(gè)任務(wù)由于優(yōu)先級(jí)相同,而且在一個(gè)處理器上運(yùn)行,其實(shí)是在交替運(yùn)行。 真實(shí)的執(zhí)行流程所圖3所示,2.1任務(wù)函數(shù) 圖二,2.1任務(wù)函數(shù),上例中main()函數(shù)在啟動(dòng)調(diào)度器之前先完成兩個(gè)任務(wù) 的創(chuàng)建。當(dāng)然也可以從一個(gè)任務(wù)中創(chuàng)建另一個(gè)任務(wù)。 我們可以先在main()中創(chuàng)建任務(wù)1,然后在任務(wù)1中創(chuàng)建任務(wù)2這樣需要在任務(wù)一中添加以下語(yǔ)句: xTaskCreate( vTask2, Task 2, 1000, NULL, 1, NULL );,2
8、.1任務(wù)函數(shù),關(guān)于使用xTaskCreate()時(shí)任務(wù)函數(shù)的參數(shù)問(wèn)題 例1中的兩個(gè)任務(wù)幾乎完全相同,唯一的區(qū)別就是打印輸出的字符串。這種重復(fù)性可以通過(guò)創(chuàng)建同一個(gè)任務(wù)代碼的兩個(gè)實(shí)例來(lái)去除。 這時(shí)任務(wù)參數(shù)就可以用來(lái)傳遞各自打印輸出的字符串。,我們?nèi)匀徽{(diào)用兩次xTaskCreate(),但其pvParameters(第四個(gè)) 參數(shù)變?yōu)榱藘蓚€(gè)不同的指針,兩個(gè)指針?lè)謩e指向各自需要打印輸出的文本。,2.2任務(wù)調(diào)度,任務(wù)的調(diào)度方法: 通過(guò)對(duì)任務(wù)設(shè)置優(yōu)先級(jí)進(jìn)行優(yōu)先級(jí)搶占式調(diào)度。 每個(gè)任務(wù)都賦予了一個(gè)優(yōu)先級(jí)。 每個(gè)任務(wù)都可以存在于一個(gè)或多個(gè)狀態(tài)。 在任何時(shí)候都只有一個(gè)任務(wù)可以處于運(yùn)行狀態(tài)。 調(diào)度器總是在所有處于
9、就緒態(tài)的任務(wù)中選擇具有最高優(yōu)先級(jí)的任務(wù)來(lái)執(zhí)行。,2.2任務(wù)調(diào)度,優(yōu)先級(jí): xTaskCreate() API函數(shù)的參數(shù)uxPriority(即第五個(gè)參數(shù))為創(chuàng)建的任務(wù)賦予了一個(gè)初始優(yōu)先級(jí)。 常量configMAX_PRIORITIES在(FreeRTOSConfig.h文件中)的值,即是系統(tǒng)最多可具有的優(yōu)先級(jí)數(shù)目。0到(configMAX_PRIORITES 1) 函數(shù)優(yōu)先級(jí)可以調(diào)用vTaskPrioritySet() API函數(shù)進(jìn)行修改。,2.2任務(wù)調(diào)度,關(guān)于優(yōu)先級(jí)為零的任務(wù)介紹: 當(dāng)創(chuàng)建的任務(wù)都處于阻塞態(tài)時(shí)(很多時(shí)候都會(huì)有這種情況出現(xiàn)),這種狀態(tài)下所有的任務(wù)都不可運(yùn)行,但處理器總是需要代碼
10、來(lái)執(zhí)行所以至少要有一個(gè)任務(wù)處于運(yùn)行態(tài)。 為了保證這一點(diǎn),當(dāng)調(diào)用vTaskStartScheduler()時(shí),調(diào)度器會(huì)自動(dòng)創(chuàng)建一個(gè)空閑任務(wù)(非常短小的循環(huán))。 空閑任務(wù)擁有最低優(yōu)先級(jí)(優(yōu)先級(jí)0),這樣不會(huì)妨礙具有更高優(yōu)先級(jí)的應(yīng)用任務(wù)進(jìn)入運(yùn)行態(tài)。,2.2任務(wù)調(diào)度,圖中任務(wù)一(Task1)任務(wù)二(Task2)都設(shè)置有定時(shí)阻塞,任務(wù)二的優(yōu)先級(jí)高于任務(wù)一的優(yōu)先級(jí),在兩個(gè)任務(wù)都被阻塞的時(shí)候,空閑任務(wù)(idle)開(kāi)始執(zhí)行。 圖三,2.2任務(wù)調(diào)度,空閑任務(wù)鉤子函數(shù): 通過(guò)空閑任務(wù)鉤子函數(shù)(或稱(chēng)回調(diào),hook, or call-back),可以直接在空閑任務(wù)中添加應(yīng)用程序相關(guān)的功能。空閑任務(wù)鉤子函數(shù)會(huì)被空閑任務(wù)
11、每循環(huán)一次就自動(dòng)調(diào)用一次。 空閑任務(wù)鉤子函數(shù)有很多用途,如在沒(méi)有任何應(yīng)用功能需要處理的時(shí)候,將系統(tǒng)配置到省電模式。,2.2任務(wù)調(diào)度,定義一個(gè)空閑任務(wù)鉤子函數(shù): void vApplicationIdleHook( void ); FreeRTOSConfig.h中的配置常configUSE_IDLE_HOOK必須定義為1,這樣空閑任務(wù)鉤子函數(shù)才會(huì)被調(diào)用。,2.2任務(wù)調(diào)度,空閑任務(wù)鉤子函數(shù)必須遵從以下規(guī)則: 1. 絕不能阻塞或掛起。空閑任務(wù)的目的就是希望在所有任務(wù)阻塞時(shí)仍能有任務(wù)運(yùn)行,一旦鉤子函數(shù)阻塞或掛起,將不再有任務(wù)運(yùn)行。 2. 如果應(yīng)用程序用到了vTaskDelete() 函數(shù),則空閑鉤子
12、函數(shù)必須能夠盡快返回。 因?yàn)樵谌蝿?wù)被刪除后(vTaskDelete()),空閑任務(wù)負(fù)責(zé)回收內(nèi)核資源。如果空閑任務(wù)一直運(yùn)行在鉤子函數(shù)中,則無(wú)法進(jìn)行回收工作。,2.2任務(wù)調(diào)度,任務(wù)優(yōu)先級(jí)的改變 API函數(shù)vTaskPriofitySet()可以用于在調(diào)度器啟動(dòng)后改變?nèi)魏稳蝿?wù)的優(yōu)先級(jí)。 void vTaskPrioritySet( xTaskHandle pxTask, unsigned portBASE_TYPE uxNewPriority ); 參數(shù): pxTask 被修改優(yōu)先級(jí)的任務(wù)句柄(即目標(biāo)任務(wù)) uxNewPriority 目標(biāo)任務(wù)將被設(shè)置到哪個(gè)優(yōu)先級(jí)上。 如果設(shè)置的值超過(guò)了最大可用優(yōu)先
13、級(jí)(configMAX_PRIORITIES 1),則會(huì)被自動(dòng)封頂為最大值。,2.2任務(wù)調(diào)度,根據(jù)優(yōu)先級(jí)的具體調(diào)度方法: 調(diào)度器保證總是在所有可運(yùn)行的任務(wù)中選擇具有最高優(yōu)先級(jí)的任務(wù),并使其進(jìn)入運(yùn) 行態(tài)。 如果被選中的優(yōu)先級(jí)上具有不止一個(gè)任務(wù),調(diào)度器會(huì)讓這些任務(wù)輪流執(zhí)行(如圖二)。,2.2任務(wù)調(diào)度,時(shí)間片的概念 圖二中的兩個(gè)任務(wù)優(yōu)先級(jí)相同,所以每個(gè)任務(wù)都執(zhí)行一個(gè)”時(shí)間片”,任務(wù)在時(shí)間片起始時(shí)刻進(jìn)入運(yùn)行態(tài),在時(shí)間片結(jié)束時(shí)刻又退出運(yùn)行態(tài)。圖2中t1與t2之間的時(shí)段就等于一個(gè)時(shí)間片。 要能夠選擇下一個(gè)運(yùn)行的任務(wù),調(diào)度器需要在每個(gè)時(shí)間片的結(jié)束時(shí)刻運(yùn)行自己本身。一個(gè)稱(chēng)為心跳(tick)中斷的周期性中斷用于
14、此目的。時(shí)間片的長(zhǎng)度是可以設(shè)定的。,2.2任務(wù)調(diào)度,此圖中的任務(wù)一與任務(wù)二與圖2中的是一樣的,此圖中標(biāo)出了調(diào)度器在時(shí)間片之間的調(diào)度過(guò)程。 圖4,2.2任務(wù)調(diào)度,任務(wù)狀態(tài) 在簡(jiǎn)要介紹了優(yōu)先級(jí)調(diào)度后,我們需要了解與調(diào)度相關(guān)的各種任務(wù)的狀態(tài)。 1、運(yùn)行態(tài). 運(yùn)行中的任務(wù)狀態(tài)。 2、阻塞狀態(tài) 如果一個(gè)任務(wù)正在等待某個(gè)事件,則稱(chēng)這個(gè)任務(wù)處于”阻塞態(tài)(blocked)”。 掛起狀態(tài)。 3、“掛起(suspended)”處于掛起狀態(tài)的任務(wù)對(duì)調(diào)度器而言是不可見(jiàn)的。讓一個(gè)任務(wù)進(jìn)入掛起狀態(tài)的唯一辦法就是調(diào)用vTaskSuspend() API函數(shù)。 4、就緒狀態(tài) 如果任務(wù)處于非運(yùn)行狀態(tài),但既沒(méi)有阻塞也沒(méi)有掛起,則
15、這個(gè)任務(wù)處于就緒(ready,準(zhǔn)備或就緒)狀態(tài)。,2.2任務(wù)調(diào)度,完整的狀態(tài)轉(zhuǎn)移圖 圖5,3、隊(duì)列,獨(dú)立的任務(wù)之間很可能會(huì)通過(guò)相互通信以提供有用的系統(tǒng)功能。 FreeRTOS中所有的通信與同步機(jī)制都是基于隊(duì)列實(shí)現(xiàn)的。 特性: 1、數(shù)據(jù)存儲(chǔ) 2、隊(duì)列可以保存有限個(gè)具有確定長(zhǎng)度的數(shù)據(jù)單元 3、可被多任務(wù)存取 4、隊(duì)列是具有自己獨(dú)立權(quán)限的內(nèi)核對(duì)象,并不屬于或賦予任何任務(wù)。所有任務(wù)都可以向同一隊(duì)列寫(xiě)入和讀出。,3、隊(duì)列,5、讀隊(duì)列時(shí)阻塞 當(dāng)某個(gè)任務(wù)試圖讀一個(gè)隊(duì)列時(shí),其可以指定一個(gè)阻塞超時(shí)時(shí)間。在這段時(shí)間中,如 果隊(duì)列為空,該任務(wù)將保持阻塞狀態(tài)以等待隊(duì)列數(shù)據(jù)有效。 6、寫(xiě)隊(duì)列時(shí)阻塞 同讀隊(duì)列一樣,任務(wù)也
16、可以在寫(xiě)隊(duì)列時(shí)指定一個(gè)阻塞超時(shí)時(shí)間。這個(gè)時(shí)間是當(dāng)被寫(xiě) 隊(duì)列已滿時(shí),任務(wù)進(jìn)入阻塞態(tài)以等待隊(duì)列空間有效的最長(zhǎng)時(shí)間。,3、隊(duì)列,創(chuàng)建隊(duì)列: xQueueHandle xQueueCreate( unsigned portBASE_TYPE uxQueueLength, unsigned portBASE_TYPE uxItemSize ); 參數(shù): uxQueueLength 隊(duì)列能夠存儲(chǔ)的最大單元數(shù)目,即隊(duì)列深度。 uxItemSize 隊(duì)列中數(shù)據(jù)單元的長(zhǎng)度,以字節(jié)為單位。 返回值:NULL表示沒(méi)有足夠的堆空間分配給隊(duì)列而導(dǎo)致創(chuàng)建失敗。 非NULL值表示隊(duì)列創(chuàng)建成功。此返回值應(yīng)當(dāng)保存下來(lái),以作為
17、操作此隊(duì)列的句柄。,3、隊(duì)列,向列中寫(xiě)數(shù)據(jù) xQueueSendToBack() 與xQueueSendToFront() API函數(shù) portBASE_TYPE xQueueSendToFront( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait ); /將數(shù)據(jù)發(fā)送到隊(duì)列尾部,3、隊(duì)列,參數(shù)說(shuō)明 xQueue 目標(biāo)隊(duì)列的句柄。這個(gè)句柄即是調(diào)用xQueueCreate()創(chuàng)建該隊(duì)列時(shí)的返回值。 pvItemToQueue 發(fā)送數(shù)據(jù)的指針。其指向?qū)⒁獜?fù)制到目標(biāo)隊(duì)列中的數(shù)據(jù)單元。 xTicksTo
18、Wait 阻塞超時(shí)時(shí)間。如果在發(fā)送時(shí)隊(duì)列已滿,這個(gè)時(shí)間即是任務(wù)處于阻塞態(tài)等待隊(duì)列空間有效的最長(zhǎng)等待時(shí)間。,3、隊(duì)列,返回值 有兩個(gè)可能的返回值: 1.pdPASS 數(shù)據(jù)被成功發(fā)送到隊(duì)列中。 2.errQUEUE_FULL 如果由于隊(duì)列已滿而無(wú)法將數(shù)據(jù)寫(xiě)入,則將返回。,3、隊(duì)列,ortBASE _TYPE xQueueSendToBack( xQueueHandle xQueue, const void * pvItemToQueue, portTickType xTicksToWait ); /將數(shù)據(jù)發(fā)送到隊(duì)列首部 其參數(shù)和返回值與前者相似,這里不再介紹。,3、隊(duì)列,xQueueReceive
19、()與xQueuePeek() API函數(shù) xQueueReceive()用于從隊(duì)列中接收(讀?。?shù)據(jù)單元。接收到的單元同時(shí)會(huì)從隊(duì)列 中刪除。 xQueuePeek()也是從從隊(duì)列中接收數(shù)據(jù)單元,不同的是并不從隊(duì)列中刪出接收到 的單元。,3、隊(duì)列,portBASE_TYPE xQueueReceive( xQueueHandle xQueue, const void * pvBuffer, portTickType xTicksToWait ); 參數(shù):,xQueue 被讀隊(duì)列的句柄。這個(gè)句柄即是調(diào)用xQueueCreate()創(chuàng)建該隊(duì)列 時(shí)的返回值。 pvBuffer 接收緩存指針。其指向一
20、段內(nèi)存區(qū)域,用于接收從隊(duì)列中拷貝來(lái) 的數(shù)據(jù)。 xTicksToWait 阻塞超時(shí)時(shí)間。如果在接收時(shí)隊(duì)列為空,則這個(gè)時(shí)間是任務(wù)處于 阻塞狀態(tài)以等待隊(duì)列數(shù)據(jù)有效的最長(zhǎng)等待時(shí)間。把它設(shè)為0,并且隊(duì)列為空,則xQueueRecieve()與xQueuePeek()均會(huì)立即返回。 如果把xTicksToWait 設(shè)置為portMAX_DELAY,并且在 FreeRTOSConig.h中設(shè)定INCLUDE_vTaskSuspend 為1,那么 阻塞等待將沒(méi)有超時(shí)限制。,3、隊(duì)列,返回值 有兩個(gè)可能的返回值: 1.pdPASS 只有一種情況會(huì)返回pdPASS,那就是成功地從隊(duì)列中讀到數(shù)據(jù)。 2.errQUE
21、UE_FULL 如果在讀取時(shí)由于隊(duì)列已空而沒(méi)有讀到任何數(shù)據(jù),則將返回 errQUEUE_FULL。 如果設(shè)定了阻塞超時(shí)時(shí)間(xTicksToWait非0),在函數(shù)返回之前 任務(wù)將被轉(zhuǎn)移到阻塞態(tài)以等待隊(duì)列數(shù)據(jù)有效。但直到超時(shí)也沒(méi)有 其它任務(wù)或是中斷服務(wù)例程往隊(duì)列中寫(xiě)入數(shù)據(jù),函數(shù)則會(huì)返回 errQUEUE_FULL。 xQueuePeek()的參數(shù)與返回值與xQueueReceive()類(lèi)似,這里不再重復(fù)。,3、隊(duì)列,uxQueueMessagesWaiting()用于查詢隊(duì)列中當(dāng)前有效數(shù)據(jù)單元個(gè)數(shù) 函數(shù)原型: unsigned portBASE_TYPE uxQueueMessagesWaiti
22、ng( xQueueHandle xQueue ); 參數(shù) xQueue 被查詢隊(duì)列的句柄。這個(gè)句柄即是調(diào)用xQueueCreate()創(chuàng)建該隊(duì)列時(shí) 的返回值。 返回值 當(dāng)前隊(duì)列中保存的數(shù)據(jù)單元個(gè)數(shù)。返回0表明隊(duì)列為空。,3、隊(duì)列,以上五個(gè)函數(shù)均不能在中斷服務(wù)中使用,系統(tǒng)會(huì)提供以上函數(shù)專(zhuān)門(mén)的中斷版本(后面將會(huì)講到)。,3、隊(duì)列,隊(duì)列使用例程 例2: 本例示范創(chuàng)建一個(gè)隊(duì)列,由多個(gè)任務(wù)往隊(duì)列中寫(xiě)數(shù)據(jù),以及從隊(duì)列中把數(shù)據(jù)讀出。 其中往隊(duì)列中寫(xiě)數(shù)據(jù)的任務(wù)沒(méi)有設(shè)定阻塞超時(shí)時(shí)間,而讀隊(duì)列的任務(wù)設(shè)定了超時(shí)時(shí)間。,3、隊(duì)列,寫(xiě)隊(duì)列任務(wù)函數(shù)。主函數(shù)將調(diào)用此函數(shù)分別寫(xiě)入100、200.,3、隊(duì)列,寫(xiě)隊(duì)列任務(wù)在每次
23、循環(huán)中都調(diào)用taskYIELD()。taskYIELD()通知調(diào)度器立即進(jìn)行任務(wù)切換,而不必等到當(dāng)前任務(wù)的時(shí)間片耗盡。,3、隊(duì)列,讀隊(duì)列任務(wù)函數(shù),函數(shù)中設(shè)置了延遲時(shí)間。,3、隊(duì)列,3、隊(duì)列,main函數(shù):其在啟動(dòng)調(diào)度器之前創(chuàng)建了一個(gè)隊(duì)列和三個(gè)任務(wù)。盡管對(duì)任務(wù)的優(yōu)先級(jí)的設(shè)計(jì)使得隊(duì)列實(shí)際上在任何時(shí)候都不可能多于一個(gè)數(shù)據(jù)單元,本例代碼還是創(chuàng)建了一個(gè)可以保存最多5個(gè)long 型值的隊(duì)列。,3、隊(duì)列,3、隊(duì)列,寫(xiě)隊(duì)列任務(wù)在每次循環(huán)中都調(diào)用taskYIELD()。taskYIELD()通知調(diào)度器立即進(jìn)行任務(wù)切換,而不必等到當(dāng)前任務(wù)的時(shí)間片耗盡。本例中兩個(gè)寫(xiě)隊(duì)列任務(wù)(寫(xiě)入100和200)是具有相同的任務(wù)優(yōu)先
24、級(jí)(均為1),所以一旦其中一個(gè)任務(wù)調(diào)用了taskYIELD(),另一個(gè)任務(wù)將會(huì)得到執(zhí)行。反映到輸出上就是兩個(gè)人物交替輸出。 圖6,3、隊(duì)列,調(diào)用過(guò)程如下 圖7,3、隊(duì)列,使用隊(duì)列傳遞復(fù)合數(shù)據(jù)類(lèi)型,3、隊(duì)列,對(duì)大型數(shù)據(jù)單元的傳遞,4、中斷,4.1延遲中斷處理 當(dāng)中斷發(fā)生時(shí),程序?qū)⑦M(jìn)入中斷服務(wù)程序中行,如果中斷服務(wù)程序運(yùn)行時(shí)間很長(zhǎng),甚至包括遲將大大降低系統(tǒng)的實(shí)時(shí)性。這時(shí),我們可以將中斷服務(wù)程序作為觸發(fā)者,觸發(fā)其他函數(shù)來(lái)執(zhí)行需要執(zhí)行的任務(wù)。這樣中斷服務(wù)程序可以很簡(jiǎn)短,大大增強(qiáng)了實(shí)時(shí)性。而真正需要做的事情則放在被觸發(fā)的函數(shù)中執(zhí)行。 我們可以使用二值信號(hào)量完成中斷服務(wù)程序與被觸發(fā)函數(shù)的這種觸發(fā)關(guān)系。,4
25、.1延遲中斷處理,延遲中斷處理如下圖所示:圖8,4.1延遲中斷處理,延遲處理任務(wù)(即被中斷服務(wù)程序觸發(fā)的函數(shù))對(duì)一個(gè)信號(hào)量進(jìn)行帶阻塞性質(zhì)的”take”調(diào)用,意思是進(jìn)入阻塞態(tài)以等待事件發(fā)生。當(dāng)事件發(fā)生后,ISR 對(duì)同一個(gè)信號(hào)量進(jìn)行”give”操作,使得延遲處理任務(wù)解除阻塞,從而事件在延遲處理任務(wù)中得到相應(yīng)的處理。,4.1延遲中斷處理,在此情形下,信號(hào)量可以看作是一個(gè)深度為1的隊(duì)列。這個(gè)隊(duì)列由于最多只能保存一個(gè)數(shù)據(jù)單元,所以其不為空則為滿(所謂”二值”)。 延遲處理任務(wù)調(diào)用xSemaphoreTake()時(shí),等效于帶阻塞時(shí)間地讀取隊(duì)列,如果隊(duì)列為空的話任務(wù)則進(jìn)入阻塞態(tài)。當(dāng)事件發(fā)生后,ISR(中斷服
26、務(wù)例程) 簡(jiǎn)單地通過(guò)調(diào)用xSemaphoreGiveFromISR()放置一個(gè)令牌(信號(hào)量)到隊(duì)列中,使得隊(duì)列成為滿狀態(tài)。這使得延遲處理任務(wù)切出阻塞態(tài),進(jìn)入運(yùn)行態(tài)。 當(dāng)任務(wù)完成處理后,再次讀取隊(duì)列,發(fā)現(xiàn)隊(duì)列為空,又進(jìn)入阻塞態(tài),等待下一次事件發(fā)生。,4.1延遲中斷處理,以上過(guò)程如下圖所示:圖9,4.1延遲中斷處理,4.1延遲中斷處理,vSemaphoreCreateBinary() API函數(shù) 在使用信號(hào)量之前,必須先創(chuàng)建它。創(chuàng)建二值信號(hào)量使用 vSemaphoreCreateBinary()API函數(shù)。 void vSemaphoreCreateBinary( xSemaphoreHandle
27、 xSemaphore ); 參數(shù): xSemaphore 創(chuàng)建的信號(hào)量 需要說(shuō)明的是vSemaphoreCreateBinary()在實(shí)現(xiàn)上是一個(gè)宏,所以 信號(hào)量變量應(yīng)當(dāng)直接傳入,而不是傳址。本章中包含本函數(shù)調(diào)用的示 例可用于參考進(jìn)行復(fù)制,4.1延遲中斷處理,xSemaphoreTake() API 函數(shù) 延遲任務(wù)處理函數(shù),調(diào)用此函數(shù)獲取信號(hào)量。 只有當(dāng)信號(hào)量有效的時(shí)候才可以被獲取。除互斥信號(hào)量(Recursive Semaphore)外,所有類(lèi)型的信號(hào)量都可以調(diào)用函數(shù)xSemaphoreTake()來(lái)獲取。 但xSemaphoreTake()不能在中斷服務(wù)例程中調(diào)用。,4.1延遲中斷處理,
28、portBASE_TYPE xSemaphoreTake( xSemaphoreHandle xSemaphore, portTickType xTicksToWait ); 參數(shù): xSemaphore 需要獲取的信號(hào)量 xTicksToWait 阻塞超時(shí)時(shí)間。任務(wù)進(jìn)入阻塞態(tài)以等待信號(hào)量有效的最長(zhǎng)時(shí)間。 如果xTicksToWait為0,則xSemaphoreTake()在信號(hào)量無(wú)效時(shí)會(huì) 立即返回。,4.1延遲中斷處理,返回值 有兩個(gè)可能的返回值: 1.pdPASS 只有一種情況會(huì)返回pdPASS,那就是成功獲得信號(hào)量。 2.pdFALSE 未能獲得信號(hào)量。,4.1延遲中斷處理,xSemap
29、horeGiveFromISR() API 函數(shù) 中斷服務(wù)程序調(diào)用此函數(shù)給出信號(hào)量。 所有信號(hào)量(除互斥信號(hào)量)都可以通過(guò)調(diào)用xSemaphoreGiveFromISR()給出。 xSemaphoreGiveFromISR()是xSemaphoreGive()的特殊形式,專(zhuān)門(mén)用于中斷服務(wù)例程中。,4.1延遲中斷處理,portBASE_TYPE xSemaphoreGiveFromISR( xSemaphoreHandle xSemaphore, portBASE_TYPE *pxHigherPriorityTaskWoken ); 參數(shù): xSemaphore 給出的信號(hào)量 pxHigherP
30、riorityTaskWoken 對(duì)某個(gè)信號(hào)量而言,可能有不止一個(gè)任務(wù)處于阻塞態(tài)在等待其有效。調(diào)用xSemaphoreGiveFromISR()會(huì)讓信號(hào)量變?yōu)橛行?,所以?huì)讓其中一個(gè)等待任務(wù)切出阻塞態(tài)。,4.1延遲中斷處理,返回值 有兩個(gè)可能的返回值: 1.pdPASS xSemaphoreGiveFromISR()調(diào)用成功。 2.pdFAIL 如果信號(hào)量已經(jīng)有效,無(wú)法給出,則返回pdFAIL。,4.1延遲中斷處理,例三 本例在中斷服務(wù)例程中使用一個(gè)二值信號(hào)量讓延遲處理任務(wù)從阻塞態(tài)中切換出來(lái)。 下面的一個(gè)簡(jiǎn)單的周期性任務(wù)用于每隔500毫秒產(chǎn)生一個(gè)軟件中斷。此任務(wù)在產(chǎn)生中斷之前和之后都會(huì)打印輸出一
31、個(gè)字符串。,4.1延遲中斷處理,4.1延遲中斷處理,下面的任務(wù)展現(xiàn)的是延遲處理任務(wù)的具體實(shí)現(xiàn)此任務(wù)通過(guò)使用二值信號(hào)量與軟件中斷進(jìn)行同步。 這個(gè)任務(wù)也在每次循環(huán)中打印輸出一個(gè)信息,這樣做的目的同樣是可以在程序的執(zhí)行輸出結(jié)果中直觀地看出任務(wù)與中斷的執(zhí)行流程。,4.1延遲中斷處理,4.1延遲中斷處理,下個(gè)任務(wù)展現(xiàn)的是中斷服務(wù)例程,這才是真正的中斷處理程序。 這段代碼做的事情非常少,僅僅是給出一個(gè)信號(hào)量,以讓延遲處理任務(wù)解除阻塞。,4.1延遲中斷處理,4.1延遲中斷處理,main()函數(shù)很簡(jiǎn)單,創(chuàng)建二值信號(hào)量及任務(wù),安裝中斷服務(wù)例程,然后啟動(dòng)調(diào)度器。,4.1延遲中斷處理,例3整個(gè)執(zhí)行流程可以描述如下:
32、 1. 中斷產(chǎn)生。 2. 中斷服務(wù)例程啟動(dòng),給出信號(hào)量以使延遲處理任務(wù)解除阻塞。 3. 當(dāng)中斷服務(wù)例程退出時(shí),延遲處理任務(wù)得到執(zhí)行。延遲處理任務(wù)做的第一件事便是獲取信號(hào)量。 4. 延遲處理任務(wù)完成中斷事件處理后,試圖再次獲取信號(hào)量如果此時(shí)信號(hào)量無(wú)效,任務(wù)將切入阻塞待等待事件發(fā)生。,4.1延遲中斷處理,輸出結(jié)果參見(jiàn)下圖。和期望的一樣,延遲處理任務(wù)在中斷產(chǎn)生后立即執(zhí)行。所以延遲處理任務(wù)的輸出信息將周期任務(wù)的兩條輸出信息分開(kāi)。 圖10,4.1延遲中斷處理,執(zhí)行流程: 圖11,4.2計(jì)數(shù)信號(hào)量,在中斷以相對(duì)較慢的頻率發(fā)生的情況下,二值信號(hào)量是足夠而完美的。 如果在延遲處理任務(wù)完成上一個(gè)中斷事件的處理之
33、前,新的中斷事件又發(fā)生了,等效于將新的事件鎖存在二值信號(hào)量中,使得延遲處理任務(wù)在處理完上一個(gè)事件之后,立即就可以處理新的事件。 但一個(gè)二值信號(hào)量最多只可以鎖存一個(gè)中斷事件。在鎖存的事件還未被處理之前,如果又有中斷事件發(fā)生,這時(shí)的信號(hào)量已滿,那么后續(xù)發(fā)生的中斷事件將會(huì)丟失。,4.2計(jì)數(shù)信號(hào)量,如果用計(jì)數(shù)信號(hào)量代替二值信號(hào)量,那么,以上那種丟中斷的情形將可以避免。 就如同我們可以把二值信號(hào)量看作是只有一個(gè)數(shù)據(jù)單元的隊(duì)列一樣,計(jì)數(shù)信號(hào)量可以看作是深度大于1的隊(duì)列。 計(jì)數(shù)信號(hào)量有以下兩種典型用法: 1、事件計(jì)數(shù) 2、資源管理,4.2計(jì)數(shù)信號(hào)量,1事件計(jì)數(shù) 在這種用法中,每次事件發(fā)生時(shí),中斷服務(wù)例程都會(huì)
34、“給出(Give)”信號(hào)量信號(hào)量在每次被給出時(shí)其計(jì)數(shù)值加 1。延遲處理任務(wù)每處理一個(gè)任務(wù)都會(huì)”獲取(Take)”一次信號(hào)量信號(hào)量在每次被獲取時(shí)其計(jì)數(shù)值減 1。信號(hào)量的計(jì)數(shù)值其實(shí)就是已發(fā)生事件的數(shù)目與已處理事件的數(shù)目之間的差值。 用于事件計(jì)數(shù)的計(jì)數(shù)信號(hào)量,在被創(chuàng)建時(shí)其計(jì)數(shù)值被初始化為 0。,4.2計(jì)數(shù)信號(hào)量,2資源管理 在這種用法中,信號(hào)量的計(jì)數(shù)值用于表示可用資源的數(shù)目。 一個(gè)任務(wù)要獲取資源的控制權(quán),其必須先獲得信號(hào)量使信號(hào)量的計(jì)數(shù)值減 1。當(dāng)計(jì)數(shù)值減至 0,則表示沒(méi)有可用資源。當(dāng)任務(wù)利用資源完成工作后,將給出(歸還)信號(hào)量使信號(hào)量的計(jì)數(shù)值加 1。,4.2計(jì)數(shù)信號(hào)量,xSemaphoreCrea
35、teCounting() API函數(shù) 信號(hào)量在使用前必須先被創(chuàng)建。使用xSemaphoreCreateCounting() API 函數(shù)來(lái)創(chuàng)建一個(gè)計(jì)數(shù)信號(hào)量。,4.2計(jì)數(shù)信號(hào)量,參數(shù): uxMaxCount : 最大計(jì)數(shù)值。如果把計(jì)數(shù)信號(hào)量類(lèi)比于隊(duì)列的話,uxMaxCount值就是隊(duì)列的最大深度。 當(dāng)此信號(hào)量用于對(duì)事件計(jì)數(shù)或鎖存事件的話,uxMaxCount就是可鎖存事件的最大數(shù)目。 當(dāng)此信號(hào)量用于對(duì)一組資源的訪問(wèn)進(jìn)行管理話,uxMaxCount應(yīng)當(dāng)設(shè)置為所有可用資源的總數(shù)。,4.2計(jì)數(shù)信號(hào)量,uxInitialCount: 信號(hào)量的初始計(jì)數(shù)值。 當(dāng)此信號(hào)量用于事件計(jì)數(shù)的話,uxInitial
36、Count應(yīng)當(dāng)設(shè)置為0因?yàn)楫?dāng)信號(hào)量被創(chuàng)建時(shí),還沒(méi)有事件發(fā)生。 當(dāng)此信號(hào)量用于資源管理的話,uxInitialCount 應(yīng)當(dāng)?shù)扔趗xMaxCount因?yàn)楫?dāng)信號(hào)量被創(chuàng)建時(shí),所有的資源都是可用的。,4.2計(jì)數(shù)信號(hào)量,返回值: 如果返回NULL值,表示堆上內(nèi)存空間不足,所以FreeRTOS無(wú)法為信號(hào)量結(jié)構(gòu)分配內(nèi)存導(dǎo)致信號(hào)量創(chuàng)建失敗。第五章有提供更多的內(nèi)存管理方面的信息。 如果返回非NULL值,則表示信號(hào)量創(chuàng)建成功。此值應(yīng)當(dāng)被保存起來(lái)作為這個(gè)的信號(hào)量的句柄。,4.2計(jì)數(shù)信號(hào)量,例4:利用計(jì)數(shù)信號(hào)量對(duì)任務(wù)和中斷進(jìn)行同步例4用計(jì)數(shù)信號(hào)量代替二值信號(hào)量對(duì)例3的實(shí)現(xiàn)進(jìn)行了改進(jìn)。修改main()函數(shù)調(diào)用xSem
37、aphoreCreateCounting()替代xSemaphoreCreateBinary()的調(diào)用。新的API調(diào)用如程序清單49所示:,4.2計(jì)數(shù)信號(hào)量,為了模擬多個(gè)事件以高頻率發(fā)生,修改了中斷服務(wù)例程,在每次中斷多次”給出(Give)”信號(hào)量。每個(gè)事件都鎖存到信號(hào)量的計(jì)數(shù)值中。修改后的中斷服務(wù)例程如下。,4.2計(jì)數(shù)信號(hào)量,4.2計(jì)數(shù)信號(hào)量,其它函數(shù)都復(fù)用例3中的代碼,保持不變。下圖展示了例4的輸出結(jié)果。 圖12,4.2計(jì)數(shù)信號(hào)量,從圖中可以看到,每次中斷發(fā)生后,延遲處理任務(wù)處理了中斷生成的全部三個(gè)事件模擬出來(lái)的。這些事件被鎖存到信號(hào)量的計(jì)數(shù)值中,以使得延遲處理任務(wù)可以對(duì)它們依序進(jìn)行處理。
38、,4.3在中斷服務(wù)例程中使用隊(duì)列,xQueueSendToFrontFromISR(); xQueueSendToBackFromISR(); xQueueReceiveFromISR(); 分別是: xQueueSendToFront(), xQueueSendToBack() xQueueReceive()的中斷安全版本,專(zhuān)門(mén)用于中斷服務(wù)例程中。信號(hào)量用于事件通信。而隊(duì)列不僅可以用于事件通信,還可以用來(lái)傳遞數(shù)據(jù)。,4.3在中斷服務(wù)例程中使用隊(duì)列,寫(xiě)隊(duì)列函數(shù)原型: portBASE_TYPE xQueueSendToFrontFromISR( xQueueHandle xQueue, voi
39、d *pvItemToQueue portBASE_TYPE *pxHigherPriorityTaskWoken ); portBASE_TYPE xQueueSendToBackFromISR( xQueueHandle xQueue, void *pvItemToQueue portBASE_TYPE *pxHigherPriorityTaskWoken );,4.3在中斷服務(wù)例程中使用隊(duì)列,參數(shù): xQueue 目標(biāo)隊(duì)列的句柄。這個(gè)句柄即是調(diào)xQueueCreate() 創(chuàng)建該隊(duì)列時(shí)的返回值。 pvItemToQueue 發(fā)送數(shù)據(jù)的指針。其指向?qū)⒁獜?fù)制到目 標(biāo)隊(duì)列中的數(shù)據(jù)單元。 由于在
40、創(chuàng)建隊(duì)列時(shí)設(shè)置了隊(duì)列中數(shù)據(jù)單元的長(zhǎng)度,所以 會(huì)從該指針指向的空間復(fù)制對(duì)應(yīng)長(zhǎng)度的數(shù)據(jù)到隊(duì)列的 存儲(chǔ)區(qū)域。,4.3在中斷服務(wù)例程中使用隊(duì)列,參數(shù): pxHigherPriorityTaskWoken ?,4.3在中斷服務(wù)例程中使用隊(duì)列,返回值 有兩個(gè)可能的返回值: 1.pdPASS 返回pdPASS只會(huì)有一種情況,那就是數(shù)據(jù)被成功發(fā)送 到隊(duì)列中。 2.errQUEUE_FULL 如果由于隊(duì)列已滿而無(wú)法將數(shù)據(jù)寫(xiě)入,則將返回 errQUEUE_FULL。,4.3在中斷服務(wù)例程中使用隊(duì)列,例5. 利用隊(duì)列在中斷服務(wù)中發(fā)送或接收數(shù)據(jù) 本例演示在同一個(gè)中斷服務(wù)中使用xQueueSendToBackFromI
41、SR()和xQueueReceiveFromISR()。 和之前一樣,采用軟件中斷以方便實(shí)現(xiàn)。 首先創(chuàng)建一個(gè)周期任務(wù)用于每200毫秒往隊(duì)列中發(fā)送五個(gè)數(shù)值,五個(gè)數(shù)值都發(fā)送完后便產(chǎn)生一個(gè)軟件中斷。周期任務(wù)的實(shí)現(xiàn)代碼如下:,4.3在中斷服務(wù)例程中使用隊(duì)列,4.3在中斷服務(wù)例程中使用隊(duì)列,4.3在中斷服務(wù)例程中使用隊(duì)列,中斷服務(wù)例程 中斷服務(wù)例程重復(fù)調(diào)用xQueueReceiveFromISR(),直到被周期任務(wù)寫(xiě)到隊(duì)列的數(shù)值都被讀出,以將隊(duì)列讀空。每個(gè)接收到的數(shù)值的低兩位用于一個(gè)字符串?dāng)?shù)組的索引,被索引到的字符串的指針將通過(guò)調(diào)用xQueueSendFromISR()發(fā)送到另一個(gè)隊(duì)列中。中 斷服務(wù)例程
42、的實(shí)現(xiàn)代碼如下:,4.3在中斷服務(wù)例程中使用隊(duì)列,4.3在中斷服務(wù)例程中使用隊(duì)列,4.3在中斷服務(wù)例程中使用隊(duì)列,還有另一個(gè)任務(wù)將接收從中斷服務(wù)例程發(fā)出的字符串指針。此任務(wù)在讀隊(duì)列時(shí)被阻塞,直到隊(duì)列中有消息到來(lái),并將接收到的字符串打印輸出。其實(shí)現(xiàn)代碼如下:,main()main()函數(shù)創(chuàng)建隊(duì)列和任務(wù),然后啟動(dòng)調(diào)度器。如下:,4.3在中斷服務(wù)例程中使用隊(duì)列,例5的運(yùn)行輸出參見(jiàn)下圖13。從圖中可以看到,中斷服務(wù)例程接收到所有五個(gè)數(shù)值,并以五個(gè)字符串作為響應(yīng)。更多解釋請(qǐng)參考圖14. 圖13,4.3在中斷服務(wù)例程中使用隊(duì)列圖14,4.4中斷嵌套,5、共享資源的處理,多任務(wù)系統(tǒng)中存在一種潛在的風(fēng)險(xiǎn)。當(dāng)一
43、個(gè)任務(wù)在使用某個(gè)資源的過(guò)程中,即還沒(méi)有完全結(jié)束對(duì)資源的訪問(wèn)時(shí),便被切出運(yùn)行態(tài),使得資源處于非一致,不完整的狀態(tài)。 如果這個(gè)時(shí)候有另一個(gè)任務(wù)或者中斷來(lái)訪問(wèn)這個(gè)資源,則會(huì)導(dǎo)致數(shù)據(jù)損壞或是其它相似的錯(cuò)誤。,5、共享資源的處理,1、考慮如下情形,有兩個(gè)任務(wù)都試圖往一個(gè)LCD中寫(xiě)數(shù)據(jù): 任務(wù)A運(yùn)行,并往LCD寫(xiě)字符串”Hello world”。 任務(wù)A被任務(wù)B搶占,但此時(shí)字符串才輸出到”Hello w”。 任務(wù)B往LCD寫(xiě)”Abort, Retry, Fail?”,然后進(jìn)入阻塞態(tài)。 任務(wù)A從被搶占處繼續(xù)執(zhí)行,完成剩余的字符輸出“orld”。 現(xiàn)在LCD顯示的是被破壞了的字符串”Hello wAbort,
44、 Retry, Fail?orld”。,5、共享資源的處理,2、函數(shù)重入 如果一個(gè)函數(shù)可以安全地被多個(gè)任務(wù)調(diào)用,或是在任務(wù)與中斷中均可調(diào)用,則這個(gè)函數(shù)是可重入的。 每個(gè)任務(wù)都單獨(dú)維護(hù)自己的??臻g及其自身在的內(nèi)存寄存器組中的值。如果一個(gè)函數(shù)除了訪問(wèn)自己??臻g上分配的數(shù)據(jù)或是內(nèi)核寄存器中的數(shù)據(jù)外,不會(huì)訪問(wèn)其它任何數(shù)據(jù),則這個(gè)函數(shù)就是可重入的。,5、共享資源的處理,可重入函數(shù),不可重入函數(shù):,5、共享資源的處理,互斥 訪問(wèn)一個(gè)被多任務(wù)共享,或是被任務(wù)與中斷共享的資源時(shí),需要采用”互斥”技術(shù)以保證數(shù)據(jù)在任何時(shí)候都保持一致性。這樣做的目的是要確保任務(wù)從開(kāi)始訪問(wèn)資源就具有排它性,直至這個(gè)資源又恢復(fù)到完整狀
45、態(tài)。FreeRTOS提供了以下多種特性用以實(shí)現(xiàn)互斥。,5.1臨界區(qū),臨界區(qū): 基本臨界區(qū) 基本臨界區(qū)是指宏taskENTER_CRITICAL()與taskEXIT_CRITICAL()之間的代碼區(qū)間。 vPrintString()函數(shù)是打印輸出函數(shù),其涉及到資源共享,這里我們嘗試用多種方法寫(xiě)vPrintString()函數(shù)。,5.1臨界區(qū),使用一個(gè)臨界區(qū)對(duì)標(biāo)準(zhǔn)輸出進(jìn)行保護(hù):,5.1臨界區(qū),臨界區(qū)是提供互斥功能的一種非常原始的實(shí)現(xiàn)方法。臨界區(qū)的工作僅僅是簡(jiǎn)單地把中斷全部關(guān)掉,或是關(guān)掉優(yōu)先級(jí)在configMAX_SYSCAL_INTERRUPT_PRIORITY及以下的中斷依賴(lài)于具體使用的Fre
46、eRTOS移植。臨界區(qū)必須只具有很短的時(shí)間,否則會(huì)反過(guò)來(lái)影響中斷響應(yīng)時(shí)間。,5.2掛起(鎖定)調(diào)度器:,掛起(鎖定)調(diào)度器: 也可以通過(guò)掛起調(diào)度器來(lái)創(chuàng)建臨界區(qū)。 基本臨界區(qū)保護(hù)一段代碼區(qū)間不被其它任務(wù)或中斷打斷。 由掛起調(diào)度器實(shí)現(xiàn)的臨界區(qū)只可以保護(hù)一段代碼區(qū)間不被其它任務(wù)打斷,這種方式下,中斷是使能的。,5.2掛起(鎖定)調(diào)度器:,void vTaskSuspendAll( void ); 通過(guò)調(diào)用vTaskSuspendAll()來(lái)掛起調(diào)度器。掛起調(diào)度器可以停止上下文切換而不用關(guān)中斷。如果某個(gè)中斷在調(diào)度器掛起過(guò)程中要求進(jìn)行上下文切換,則個(gè)這請(qǐng)求也會(huì)被 掛起,直到調(diào)度器被喚醒后才會(huì)得到執(zhí)行。,
47、5.2掛起(鎖定)調(diào)度器:,返回值 在調(diào)度器掛起過(guò)程中,上下文切換請(qǐng)求也會(huì)被掛起,直到調(diào)度器被喚醒后才會(huì)得到執(zhí)行。如果一個(gè)掛起的上下文切換請(qǐng)求在xTaskResumeAll()返回前得到執(zhí)行,則函數(shù)返回pdTRUE。在其它情況下,xTaskResumeAll()返回pdFALSE。,5.2掛起(鎖定)調(diào)度器:,通過(guò)掛起調(diào)度器的方式來(lái)保護(hù)終端輸出。,5.3互斥量,互斥量(MUTEX) 互斥量是一種特殊的二值信號(hào)量,用于控制在兩個(gè)或多個(gè)任務(wù)間訪問(wèn)共享資源。 在用于互斥的場(chǎng)合,互斥量從概念上可看作是與共享資源關(guān)聯(lián)的令牌。一個(gè)任務(wù)想要合法地訪問(wèn)資源,其必須先成功地得到(Take)該資源對(duì)應(yīng)的令牌(成為
48、令牌持有者)。 當(dāng)令牌持有者完成資源使用,其必須馬上歸還(Give)令牌。,5.3互斥量,互斥量與二值信號(hào)量之間具有很多相同的特性。兩者間最大的區(qū)別在于信號(hào)量在被獲得之后所發(fā)生的事情: 用于互斥的信號(hào)量必須歸還。 用于同步的信號(hào)量通常是完成同步之后便丟棄,不再歸還。,5.3互斥量,創(chuàng)建信號(hào)量xSemaphoreCreateMutex() API函數(shù) xSemaphoreHandle xSemaphoreCreateMutex( void ); 返回值 如果返回NULL表示互斥量創(chuàng)建失敗。原因是內(nèi)存堆空間不足導(dǎo)致FreeRTOS無(wú)法為互斥量分配結(jié)構(gòu)數(shù)據(jù)空間。第五章提供更多關(guān)于內(nèi)存管理方面的信息。
49、 返回非NULL值表示互斥量創(chuàng)建成功。返回值應(yīng)當(dāng)保存起來(lái)作為該互斥量的句柄。,5.3互斥量使用信號(hào)量重寫(xiě)vPrintString():,5.3互斥量,5.4優(yōu)先級(jí)反轉(zhuǎn),優(yōu)先級(jí)反轉(zhuǎn): 在這種互斥情況下,高優(yōu)先級(jí)的任務(wù)必須等待低優(yōu)先級(jí)的任務(wù)放棄對(duì)互斥量的持有權(quán)。 高優(yōu)先級(jí)任務(wù)被低優(yōu)先級(jí)任務(wù)阻塞推遲的行為被稱(chēng)為”優(yōu)先級(jí)反轉(zhuǎn)”。這是一種不合理的行為方式,如果把這種行為再進(jìn)一步放大,當(dāng)高優(yōu)先級(jí)任務(wù)正等待信號(hào)量的時(shí)候,一個(gè)介于兩個(gè)任務(wù)優(yōu)先級(jí)之間的中等優(yōu)先級(jí)任務(wù)開(kāi)始執(zhí)行這就會(huì)導(dǎo)致一個(gè)高優(yōu)先級(jí)任務(wù)在等待一個(gè)低優(yōu)先級(jí)任務(wù),而低優(yōu)先級(jí)任務(wù)卻無(wú)法執(zhí)行!,5.4優(yōu)先級(jí)反轉(zhuǎn)圖15,5.4優(yōu)先級(jí)反轉(zhuǎn),優(yōu)先級(jí)繼承 Free
50、RTOS中一個(gè)”優(yōu)先級(jí)繼承”機(jī)制作為優(yōu)先級(jí)反轉(zhuǎn)的一種解決方案。優(yōu)先級(jí)繼承是最小化優(yōu)先級(jí)反轉(zhuǎn)負(fù)面影響的一種方案,但其并不能修正優(yōu)先級(jí)反轉(zhuǎn)帶來(lái)的問(wèn)題,僅僅是減小優(yōu)先級(jí)反轉(zhuǎn)的影響。所以如果可以避免的話,并不建議系統(tǒng)實(shí)現(xiàn)對(duì)優(yōu)先級(jí)繼承有所依賴(lài)。 優(yōu)先級(jí)繼承暫時(shí)地將互斥量持有者的優(yōu)先級(jí)提升至所有等待此互斥量的任務(wù)所具有的最高優(yōu)先級(jí)。持有互斥量的低優(yōu)先級(jí)任務(wù)”繼承”了等待互斥量的任務(wù)的優(yōu)先級(jí)。,5.4優(yōu)先級(jí)反轉(zhuǎn) 圖16,5.5死鎖,死鎖: 死鎖是利用互斥量提供互斥功能的另一個(gè)潛在缺陷。Deadlock有時(shí)候會(huì)被更戲劇性地稱(chēng)為”deadly embrace(抱死)”。 當(dāng)兩個(gè)任務(wù)都在等待被對(duì)方持有的資源時(shí),兩
51、個(gè)任務(wù)都無(wú)法再繼續(xù)執(zhí)行,這種情況就被稱(chēng)為死鎖。 避免死鎖的最好方法就是在設(shè)計(jì)階段就考慮到這種潛在風(fēng)險(xiǎn),以避免不必要的麻煩。,5.6守護(hù)任務(wù),守護(hù)任務(wù) 守護(hù)任務(wù)提供了一種干凈利落的方法來(lái)實(shí)現(xiàn)互斥功能,而不用擔(dān)心會(huì)發(fā)生優(yōu)先級(jí)反轉(zhuǎn)和死鎖。 守護(hù)任務(wù)是對(duì)某個(gè)資源具有唯一所有權(quán)的任務(wù)。只有守護(hù)任務(wù)才可以直接訪問(wèn)其守護(hù)的資源其它任務(wù)要訪問(wèn)該資源只能間接地通過(guò)守護(hù)任務(wù)提供的服務(wù)。,5.6守護(hù)任務(wù),采用守護(hù)任務(wù)重寫(xiě)vPrintString() vPrintString(),6、內(nèi)存管理,每當(dāng)任務(wù),隊(duì)列或是信號(hào)量被創(chuàng)建時(shí),內(nèi)核需要進(jìn)行動(dòng)態(tài)內(nèi)存分配。雖然可以調(diào)用標(biāo)準(zhǔn)的malloc()與free()庫(kù)函數(shù),但必須承擔(dān)以下若干問(wèn)題: 1. 這兩個(gè)函數(shù)在小型嵌入式系統(tǒng)中可能不可用。 2. 這兩個(gè)函數(shù)的具體實(shí)現(xiàn)可能會(huì)相對(duì)較大,會(huì)占用較多寶貴的代碼空間。 3. 這兩個(gè)函數(shù)通常不具備線程安全特性。,6、內(nèi)存管理,4. 這兩個(gè)函數(shù)具有不確定性。每次調(diào)用時(shí)的時(shí)間開(kāi)銷(xiāo)都可能不同。 5. 這兩個(gè)函數(shù)會(huì)產(chǎn)生內(nèi)存碎片。 6. 這兩個(gè)函數(shù)會(huì)使得鏈接器配置得復(fù)雜。,6、內(nèi)存管理,不同的嵌入式系統(tǒng)具有不同的內(nèi)存配置和時(shí)間要求。所以單一的內(nèi)存分配算法只可能適合部分應(yīng)用程序。 因此,F(xiàn)reeRTOS將內(nèi)存分配作為可移植層面(相對(duì)于基本的內(nèi)核代碼部分而言)。這使得不同的應(yīng)用
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 罕見(jiàn)腫瘤的個(gè)體化治療綜合治療模式構(gòu)建與個(gè)體化方案-2
- 2026江西贛州有色冶金研究所有限公司招聘11人備考題庫(kù)及一套參考答案詳解
- 餐廳股東之間財(cái)務(wù)制度
- 2026四川雅安市漢源縣審計(jì)局招聘編外專(zhuān)業(yè)技術(shù)人員2人備考題庫(kù)含答案詳解
- 五種財(cái)務(wù)制度
- 衛(wèi)健財(cái)務(wù)制度
- 釀酒企業(yè)財(cái)務(wù)制度
- 藥業(yè)財(cái)務(wù)制度及報(bào)銷(xiāo)流程
- 云南東北商會(huì)財(cái)務(wù)制度
- 單店合伙財(cái)務(wù)制度
- 糧食行業(yè)競(jìng)爭(zhēng)對(duì)手分析報(bào)告
- 北京通州產(chǎn)業(yè)服務(wù)有限公司招聘參考題庫(kù)必考題
- 兒科MDT臨床技能情景模擬培訓(xùn)體系
- 【高三上】2026屆12月八省聯(lián)考(T8聯(lián)考)語(yǔ)文試題含答案
- (人教版)必修第一冊(cè)高一物理上學(xué)期期末復(fù)習(xí)訓(xùn)練 專(zhuān)題02 連接體、傳送帶、板塊問(wèn)題(原卷版)
- 護(hù)理不良事件根本原因分析
- 社會(huì)心理學(xué)考試題及答案
- 醫(yī)療器械經(jīng)營(yíng)企業(yè)質(zhì)量管理體系文件(2025版)(全套)
- 出鐵廠鐵溝澆注施工方案
- 2025年中小學(xué)教師正高級(jí)職稱(chēng)評(píng)聘答辯試題(附答案)
- 現(xiàn)代企業(yè)管理體系架構(gòu)及運(yùn)作模式
評(píng)論
0/150
提交評(píng)論