版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
是否要在系統(tǒng)中使用RTOS,雖然要的也僅僅是一個(gè)實(shí)時(shí)內(nèi)核,當(dāng)然更重要的是免費(fèi)。之所以翻譯這篇文章倒不是因?yàn)镽TOS有多么優(yōu)秀,完全是因?yàn)檫@篇文章還不算太長。而且RTOS.net仿佛致力于這個(gè)內(nèi)核在國內(nèi)的推廣,也做了不少中文了。如果RTOS.net不棄的話,我倒是情愿放到這個(gè)上與大家共享。Zou WEB瀏覽器,并且期望每個(gè)應(yīng)用程序任何時(shí)候都能硬實(shí)時(shí)功能必須在給定的時(shí)間限制之內(nèi)完成——如果無法做到即意味著整個(gè)系統(tǒng),在RTOS中,每個(gè)執(zhí)行線程都被稱為”任務(wù)”。在嵌入式社區(qū)中,對(duì)此并沒有一 而且?guī)в幸粋€(gè)void指針參數(shù)。其函數(shù)原型參見程序1。voidATaskFunction(void*pvParameters程序1任務(wù)函數(shù)原個(gè)死循環(huán)中,也不會(huì)退出。一個(gè)典型的任務(wù)結(jié)構(gòu)如程序2所示。RTOS任務(wù)不允許以任何方式從實(shí)現(xiàn)函數(shù)中返回——它們絕不能有一除。這也在程序2展現(xiàn)。voidATaskFunction(void*pvParameters{/*可以像普通函數(shù)一樣定義變量。用這個(gè)函數(shù)創(chuàng)建的每個(gè)任務(wù)實(shí)例都有一個(gè)屬于自己的iVarialbleExample變例將會(huì)共享這個(gè)變量。*/intiVariableExample=/*for(;;{}的是當(dāng)前任務(wù)*/vTaskDelete(NULL}程序2典型的任務(wù)函數(shù)結(jié)1任務(wù)從非運(yùn)行態(tài)轉(zhuǎn)移到運(yùn)行態(tài)被稱為”切換入或切入(switchedin或交換入(swappedin)”。相反,任務(wù)從運(yùn)行態(tài)轉(zhuǎn)移到非運(yùn)行態(tài)被稱為”切換出或切出(switched因?yàn)樗鼈兪嵌嗳蝿?wù)系統(tǒng)中最基本的組件。本所有示例程序都會(huì)用到portBASE_TYPExTaskCreate(pdTASK_CODEconstsignedportCHAR*constpcName,unsignedportSHORTusStackDepth,void*pvParameters,unsignedportBASE_TYPEuxPriority,xTaskHandle*pxCreatedTask);程序3xTaskCreate()API函數(shù)原表 參數(shù)參數(shù) 描 任務(wù)只是永不退出的C函數(shù),實(shí)現(xiàn)常通常是一個(gè)死循環(huán)。參數(shù)pvTaskCode只一個(gè)指向任務(wù)的實(shí)現(xiàn)函數(shù)的指針(效果上僅僅是函數(shù) config_MAX_TASK_NAME_LEN來定 以棧寬度的結(jié)果千萬過一個(gè)size_t類型變量所能表達(dá)的最大configMINIMAL_STACK_SIZE來決定空閑任務(wù)任用的??臻g大小。在RTOS為微控制器架構(gòu)提供的Demo應(yīng)用程序中,賦予此常量的值是對(duì)所有任務(wù)的最小建議值。理的值,然后利用RTOS提供的特性來確證分配的空間既不欠pvParameters任務(wù)函數(shù)接受一個(gè)指向void的指針(void*)。pvParameters的值即 最高優(yōu)先級(jí)(configMAX_PRIORITIES–1)。有上限(除了受限于采用的數(shù)據(jù)類型和系統(tǒng)的有效內(nèi)存空間),但最uxPriority的值 pxCreatedTaskAPI調(diào)用中對(duì)被設(shè)為NULL。返回 有兩個(gè)可能的返回值 1.voidvTask1(void*pvParameters{constchar*p kName="Task1isrunning\r\n";volatileunsignedlongul;for(;;{/*Printoutthenameofthistask.vPrintString( kName/*for(ul=0;ul<mainDELAY_LOOP_COUNT;ul++{}}}程序4例1中的第一個(gè)任務(wù)實(shí)現(xiàn)代voidvTask2(void*pvParameters{constchar*p kName="Task2isrunning\r\n";volatileunsignedlongul;for(;;{/*Printoutthenameofthistask.vPrintString( kName/*for(ul=0;ul<mainDELAY_LOOP_COUNT;ul++{}}}程序5例1中的第二個(gè)任務(wù)實(shí)現(xiàn)代intmain(void{務(wù)創(chuàng)建成功。*/xTaskCreate /*"Task /* /* /* /*此任務(wù)運(yùn)行在優(yōu)先級(jí)1上NULL /*/*Createtheothertaskinexactlythesamewayandatthesamepriority.xTaskCreate(vTask2,"Task2",1000,NULL,1,NULL/*for(;;}程序6啟動(dòng)例1中的任21運(yùn)行在同一個(gè)處理器上,所以會(huì)共享處理器時(shí)間。真實(shí)的執(zhí)行流程所圖3所示。在運(yùn)行的任務(wù)——比如t1t2之間運(yùn)行的是任務(wù)1。312。如果我們需要這樣做,則任務(wù)1代碼就應(yīng)當(dāng)修改成程序7所示的樣子。這樣,voidvTask1(void*pvParameters{constchar*p kName="Task1isrunning\r\n";volatileunsignedlongul;/*xTaskCreate(vTask2,"Task2",1000,NULL,1,NULLfor(;;{/*Printoutthenameofthistask.vPrintString( kName/*Delayforaperiod.for(ul=0;ul<mainDELAY_LOOP_COUNT;ul++{/*Thisloopisjustaverycrudedelayimplementation.Thereisnothingtodoinhere.Laterexampleswillrecethiscrudeloopwithaproperdelay/sleepfunction.*/}}}2.程序8包含了例2中用到的唯一一個(gè)任務(wù)函數(shù)代碼(vTaskFunction)。這一個(gè)制轉(zhuǎn)化為char*以得到任務(wù)需要打印輸出的字符串。voidvTaskFunction(void*pvParameters{char*p volatileunsignedlongul; kName=(char*)/*Aspermosttasks,thistaskisimplementedinaninfiniteloop.for(;;{/*Printoutthenameofthistask.vPrintString( kName/*Delayforaperiod.for(ul=0;ul<mainDELAY_LOOP_COUNT;ul++{/*Thisloopisjustaverycrudedelayimplementation.Thereisnothingtodoinhere.Laterexerciseswillrecethiscrudeloopwithaproperdelay/sleepfunction.*/}}}程序8例2中用于創(chuàng)建兩個(gè)任務(wù)實(shí)例的任務(wù)函 RTOS調(diào)度器的控制下獨(dú)運(yùn)行。9所示。staticconstchar*pcTextForTask1=“Task1isrunning\r\n”;staticconstchar*pcTextForTask2=“Task2isrunning\t\n”;intmain(void){/*Createoneofthetwotasks.xTaskCreate /*指向任務(wù)函數(shù)的指針"Task /*任務(wù)名 /*棧深度(void*)pcTextForTask1/*通過任務(wù)參數(shù)傳入需要打印輸出的文本 /*此任務(wù)運(yùn)行在優(yōu)先級(jí)1上NULL /*不會(huì)用到此任務(wù)的句柄/*同樣的方法創(chuàng)建另一個(gè)任務(wù)。至此,由相同的任務(wù)代碼(vTaskFunction)創(chuàng)建了多個(gè)任務(wù),僅僅是傳入的參數(shù)不同。同一個(gè)任務(wù)創(chuàng)建了兩個(gè)實(shí)例。*/xTaskCreate(vTaskFunction,"Task2",1000,(void*)pcTextForTask2,1,NULL/*Starttheschedulersoourtasksstartexecuting./*Ifalliswellthenmain()willneverreachhereastheschedulerwillnowberunningthetasks.Ifmain()doesreachherethenitislikelythattherewasinsufficientheapmemoryavailablefortheidletasktobecreated.CHAPTER5providesmoreinformationonmemorymanagement.for(;;}程序9例2中的main()函數(shù)實(shí)現(xiàn)代個(gè)侁先級(jí)可以在調(diào)度器啟動(dòng)后調(diào)用vTaskPrioritySet()API函數(shù)進(jìn)行修改。應(yīng)用程序在文件RTOSConfig.hconfigMAX_PRIORITIES的值,即是最多可具有的優(yōu)先級(jí)數(shù)目。RTOS本身并沒對(duì)于如何為任務(wù)指定優(yōu)先級(jí),RTOS并沒有強(qiáng)加任何限制。任意數(shù)量的任務(wù)可圍從0到(configMAX_PRIORITES–1)。要能夠選擇下一個(gè)運(yùn)行的任務(wù),調(diào)度器需要在每個(gè)時(shí)間片的結(jié)束時(shí)刻運(yùn)行自己本身。一個(gè)稱為心跳(tck,有些地方被稱為時(shí)鐘滴答,本文中一律稱為時(shí)鐘心跳)中斷的TOConfig.hconfigTIC_RT_HZconfigTICK_RATE_HZ100(HZ)10ms??梢詫?進(jìn)行擴(kuò)展,將調(diào)度器本身的執(zhí)行時(shí)間在整個(gè)執(zhí)行流程中體現(xiàn)出來。請(qǐng)參見圖4。43.代碼參見程序10。這兩個(gè)任務(wù)的實(shí)現(xiàn)函數(shù)沒有任何改動(dòng),還是通過空循環(huán)產(chǎn)生延staticconstchar*pcTextForTask1=“Task1isrunning\r\n”;staticconstchar*pcTextForTask2=“Task2isintmain(void{xTaskCreate(vTaskFunction,"Task1",1000,(void*)pcTextForTask1,1,NULL/*第二個(gè)任務(wù)創(chuàng)建在優(yōu)先級(jí)2xTaskCreate(vTaskFunction,"Task2",1000,(void*)pcTextForTask2,2,NULL/*Starttheschedulersothetasksstartexecuting.return}程序10兩個(gè)任務(wù)創(chuàng)建在不同的優(yōu)先級(jí)5212”26動(dòng)任務(wù)只會(huì)在發(fā)生后觸發(fā)工作(處理),而在沒有發(fā)生時(shí)是不能進(jìn)入運(yùn)行態(tài)的。說某個(gè)任務(wù)可以進(jìn)入阻塞態(tài)以延遲10ms。遞歸信號(hào)量,本文一律稱為互斥信號(hào)量,因?yàn)槠渲饕糜趯?shí)現(xiàn)互斥)和互斥量都可以用來實(shí)現(xiàn)同步。第二章和第三章涵蓋了有關(guān)這些的詳細(xì)內(nèi)容。把一個(gè)掛起狀態(tài)的任務(wù)喚醒的唯一途徑就是調(diào)用 vTaskResume()或vTaskResumeFromISR()API函數(shù)。大多數(shù)應(yīng)用程序中都不會(huì)用到掛起狀態(tài)。y,準(zhǔn)備或就緒)狀態(tài)。處于就緒態(tài)的任務(wù)能夠被運(yùn)行,但只是”準(zhǔn)備rad)”運(yùn)行,而當(dāng)前尚未運(yùn)行。僅僅是在就緒狀態(tài)和運(yùn)行狀態(tài)之間轉(zhuǎn)移——774.進(jìn)行糾正。vTaskDelay()的函數(shù)原型見程序11,而新的任務(wù)實(shí)現(xiàn)見程序12。voidvTaskDelay(portTickTypexTicksToDelay程序11vTaskDelay()API函數(shù)原表 參數(shù)參數(shù) 描xTicksToDelay延遲多少個(gè)心跳周期。調(diào)用該延遲函數(shù)的任務(wù)將進(jìn)入阻塞態(tài),經(jīng)vTaskDelay(100時(shí),心跳計(jì)數(shù)值10,000,則該任務(wù)將保持在阻塞態(tài),直到心跳計(jì)數(shù)計(jì)到voidvTaskFunction(void*pvParameters{char /*Thestringtoprintoutispassedinviatheparameter.Castthistoacharacterpointer.*/ kName=(char*)/*Aspermosttasks,thistaskisimplementedinaninfiniteloop.for(;;{/*Printoutthenameofthistask.vPrintString( kName期。*/vTaskDelay(250/portTICK_RATE_MS}}例4的運(yùn)行輸出結(jié)果參見圖8。9所示的執(zhí)行流程可以解釋為什么此時(shí)不同優(yōu)先級(jí)的兩個(gè)任務(wù)竟然都可以得到個(gè)任務(wù)處于就緒態(tài))。本章第7節(jié)會(huì)對(duì)空閑任務(wù)進(jìn)行更詳細(xì)的描述。4vaskDelayUnil()vaskDelay()vaskelay()的參數(shù)用來指定任務(wù)在調(diào)用vaskDelay()到切出阻塞態(tài)整個(gè)過程包含多少個(gè)心跳周期。任務(wù)保持在阻塞態(tài)的時(shí)間量由vaskDelay()刻vaskDelay()vaskelayUnil()的參數(shù)就是用來指定任務(wù)離開阻塞態(tài)進(jìn)入就緒態(tài)那一刻的精確心跳計(jì)數(shù)值。IvaskelayUnil()可以用于實(shí)現(xiàn)一個(gè)固定執(zhí)行周期的需求(當(dāng)你需要讓你的任務(wù)以固定頻率周期性執(zhí)行的時(shí)候)。由于調(diào)用此函數(shù)的任務(wù)解除阻塞的時(shí)間是絕對(duì)時(shí)刻,比起相對(duì)于調(diào)用時(shí)刻的相對(duì)時(shí)間更精確(vaskelay()可以實(shí)現(xiàn)更精確的周期性)。程序13vTaskDelayUntil()API函數(shù)原參數(shù)參數(shù) 描 被用作一個(gè)參考點(diǎn)來計(jì)算該任務(wù)下一次離開阻塞態(tài)的時(shí)pxPreviousWakeTime指向的變量值會(huì)在API函數(shù)14展示了這個(gè)參數(shù)的使用方法。 任務(wù)以固定頻率周期性執(zhí)行——這個(gè)頻率就是由xTimeIncrement的單位是心跳周期,可以使用常量voidvTaskFunction(void*pvParameters{char*p /*Thestringtoprintoutispassedinviatheparameter.Castthistoacharacterpointer.*/ kName=(char*)中自動(dòng)更新。xLastWakeTime=/*Aspermosttasks,thistaskisimplementedinaninfiniteloop.for(;;{/*Printoutthenameofthistask.vPrintString( kNamevTaskDelayUntil()中自動(dòng)更新,因此不需要應(yīng)用程序進(jìn)行顯示更新。*/vTaskDelayUntil(&xLastWakeTime,(250/portTICK_RATE_MS)}}程序14使用vTaskDelayUntil()實(shí)現(xiàn)示例任6.續(xù)處理,continuousprocessing)”任務(wù),因?yàn)樗鼈兛偸怯惺虑橐?,雖然在本例中的它們做的事情沒什么意義。持續(xù)處理任務(wù)的源代碼參見程序15。2上,高于另外兩個(gè)任務(wù)的優(yōu)先級(jí)。這個(gè)任務(wù)雖然也是voidvContinuousProcessingTask(void*pvParameters{char /*打印輸出的字符串由任務(wù)參數(shù)傳入,強(qiáng)制轉(zhuǎn)換為char* kName=(char*)/*Aspermosttasks,thistaskisimplementedinaninfiniteloop.for(;;{vPrintString( kName}}程序15例6中持續(xù)處理任務(wù)的實(shí)現(xiàn)代void k(void*pvParameters{portTickTypexLastWakeTime=/*Aspermosttasks,thistaskisimplementedinaninfinitefor(;;{/*Printoutthenameofthistask.vPrintString("Periodictaskisrunning\r\n"/*Thetaskshouldexecuteevery10millisecondsexactly.vTaskDelayUntil(&xLastWakeTime,(10/portTICK_RATE_MS)}}程序16例6中周期任務(wù)的實(shí)現(xiàn)代11展示了612是對(duì)看到的行為方式對(duì)應(yīng)的執(zhí)行流程的116126空閑任務(wù)擁有最低優(yōu)先級(jí)(0)以保證其不會(huì)妨礙具有更高優(yōu)先級(jí)的應(yīng)用任務(wù)通過空閑任務(wù)鉤子函數(shù)(或稱回調(diào),hook,orcall-back),可以直接在空閑任務(wù)中添測(cè)試處系統(tǒng)處理裕量(空閑任務(wù)只會(huì)在所有其它任務(wù)都不運(yùn)行時(shí)才有機(jī)會(huì)執(zhí)行,所以測(cè)量出空閑任務(wù)占用的處理時(shí)間就可以清楚的知道系統(tǒng)有多少富余的處理時(shí)間)。voidvApplicationIdleHook(void程序17空閑任務(wù)鉤子函數(shù)原7.4vTaskDelayAPI函數(shù),會(huì)產(chǎn)生大量的空閑時(shí)間——在來使用這些空間時(shí)間。具體源代碼參見程序18。/*Declareavariablethatwillbeincrementedbythehookfunction.unsignedlongulIdleCycleCount=voidvApplicationIdleHook(void{/*Thishookfunctiondoesnothingbutincrementacounter.}程序18一個(gè)非常簡單的空閑鉤子函ulIdleCycleCountvoidvTaskFunction(void*pvParameters{char /*Thestringtoprintoutispassedinviatheparameter.Castthistoacharacterpointer.*/ kName=(char*)/*Aspermosttasks,thistaskisimplementedinaninfiniteloop.for(;;{的值。 /*Delayforaperiodfor250milliseconds.vTaskDelay(250/portTICK_RATE_MS}}應(yīng)用任務(wù)的每次循環(huán)過程中被調(diào)用了(非常)接近4.5million次。137vTaskPrioritySet(APIvoidvTaskPrioritySet(xTaskHandlepxTask,unsignedportBASE_TYPEuxNewPriority程序20vTaskPrioritySet()API函數(shù)原表 參數(shù)參數(shù) 描 被修改優(yōu)先級(jí)的任務(wù)句柄(即目標(biāo)任務(wù))——參考xTaskCreate()任務(wù)可以通過傳入NULL值來修改自己的優(yōu)先級(jí)。uxNewPriority目標(biāo)任務(wù)將被設(shè)置到哪個(gè)優(yōu)先級(jí)上。如果設(shè)置的值超過了最大可用優(yōu)先級(jí)(configMAX_PRIORITIES–1),則會(huì)被自動(dòng)封頂為最大值。常量configMAX_PRIORITIES是在RTOSConfig.h頭文件中設(shè)置uxTaskPriorityGet(APIunsignedportBASE_TYPEuxTaskPriorityGet(xTaskHandlepxTask程序21uxTaskPriorityGet()API函數(shù)原參數(shù)參數(shù) 描 被查詢?nèi)蝿?wù)的句柄(目標(biāo)任務(wù))——參考xTaskCreateAPI任務(wù)可以通過傳入NULL值來查詢自己的優(yōu)先級(jí)。返回值8.vTaskPrioritySet()API函數(shù)來改變兩個(gè)任務(wù)的相對(duì)優(yōu)先級(jí),以達(dá)到任務(wù)1(程序22)創(chuàng)建在最高優(yōu)先級(jí),以保證其可以最先運(yùn)行。任務(wù)1首先2一旦擁有最高優(yōu)先級(jí)便啟動(dòng)執(zhí)行(進(jìn)入運(yùn)行態(tài))。由于任何時(shí)候只可能有一個(gè)任務(wù)處于運(yùn)行態(tài),所以當(dāng)任務(wù)2運(yùn)行時(shí),任務(wù)1處于就緒態(tài)。voidvTask1(void*pvParameters{unsignedportBASE_TYPE查詢本任務(wù)當(dāng)前運(yùn)行的優(yōu)先級(jí)–傳遞一個(gè)NULL值表示說“返回的優(yōu)先級(jí)”。uxPriority=uxTaskPriorityGet(NULL);for(;;){/*Printoutthenameofthistask.vPrintString("Task1isrunning\r\n"/*把任務(wù)2的優(yōu)先級(jí)設(shè)置到高于任務(wù)1的優(yōu)先級(jí),會(huì)使得任務(wù)2立即得到執(zhí)行(因?yàn)槿蝿?wù)2現(xiàn)在是所有任務(wù)如何得到這個(gè)句柄。*/vPrintString("AbouttoraisetheTask2priority\r\n");vTaskPrioritySet(xTask2Handle,(uxPriority+1));行過了,并且將其自身的優(yōu)先級(jí)設(shè)置回比任務(wù)1更低的優(yōu)先級(jí)。*/}}程序22例8中任務(wù)1的實(shí)現(xiàn)代voidvTask2(void*pvParameters{unsignedportBASE_TYPE查詢本任務(wù)當(dāng)前運(yùn)行的優(yōu)先級(jí)–傳遞一個(gè)NULL值表示說“返回的優(yōu)先級(jí)”。uxPriority=uxTaskPriorityGet(NULL);for(;;){本身。vPrintString("Task2isrunning\r\n"于任務(wù)1使得任務(wù)1立即得到執(zhí)行–任務(wù)1搶占本任務(wù)。*/vPrintString("AbouttolowertheTask2priority\r\n");vTaskPrioritySet(NULL,(uxPriority-2));}}程序23例8中的任務(wù)2實(shí)現(xiàn)代任務(wù)在查詢和修改自己的優(yōu)先級(jí)時(shí),并沒有使用一個(gè)有效的句柄——使用NULL/*變量用于保存任務(wù)2的句柄。xTaskHandleintmain(void{xTaskCreate(vTask1,"Task1",1000,NULL,2,NULL/*Thetaskiscreatedatpriority ^./*任務(wù)2創(chuàng)建在優(yōu)先級(jí)1此優(yōu)先級(jí)低于任務(wù)1。任務(wù)參數(shù)沒有用到,設(shè)為NULL。但任務(wù)2的任務(wù)句柄會(huì)被用到,故將xTask2Handle的地址傳入。*/xTaskCreate(vTask2,"Task2",1000,NULL,1,&xTask2Handle/*Thetaskhandleisthelast ^^^^^^^^^^^^^/*Starttheschedulersothetasksstartexecuting./*Ifalliswellthenmain()willneverreachhereastheschedulerwillnowberunningthetasks.Ifmain()doesreachherethenitislikelythattherewasinsufficientheapmemoryavailablefortheidletasktobecreated.CHAPTER5providesmoreinformationonmemorymanagement.for(;;}程序24例8中main()函數(shù)實(shí)現(xiàn)代148158vTaskDeleteAPI是使用vTaskDelete()API函數(shù)的任務(wù)千萬不能把空閑任務(wù)的執(zhí)行時(shí)間。voidvTaskDelete(xTaskHandlepxTaskToDelete程序25vTaskDelete()API函數(shù)原表 參數(shù)參數(shù) 描 被刪除任務(wù)的句柄(目標(biāo)任務(wù))xTaskCreateAPI函數(shù)的參數(shù)pxCreatedTask以了解如何得到任務(wù)句柄方面的信息。9.2具有最高優(yōu)先級(jí),所以會(huì)立即得到執(zhí)行。main()函數(shù)的源代碼參見程序26,任務(wù)1的實(shí)現(xiàn)代碼參見程序27。2的實(shí)現(xiàn)源代碼見程序28。刪除的任務(wù)2分配的內(nèi)存??臻e任務(wù)。又再一次創(chuàng)建任務(wù)2,如此往復(fù)。intmain(void{/*任務(wù)1創(chuàng)建在優(yōu)先級(jí)1xTaskCreate(vTask1,"Task1",1000,NULL,1,NULL/*Thetaskiscreatedatpriority ^./*Starttheschedulersothetasksstartexecuting./*main()shouldneverreachhereastheschedulerhasbeenstarted.for(;;}程序26例9中的main()函數(shù)實(shí)voidvTask1(void*pvParameters{constportTickTypexDelay100ms=100/portTICK_RATE_MS;for(;;){/*Printoutthenameofthistask.vPrintString("Task1isrunning\r\n"/*創(chuàng)建任務(wù)2xTaskCreate(vTask2,"Task2",1000,NULL,2,&xTask2Handle/*Thetaskhandleisthelast ^^^^^^^^^^^^^執(zhí)行,延遲100ms*/vTaskDelay(xDelay100ms}}程序27例9中任務(wù)1的實(shí)現(xiàn)代voidvTask2(void*pvParameters{vPrintString("Task2isrunningandabouttodeleteitself\r\n");vTaskDelete(xTask2Handle);}程序28例9中的任務(wù)2實(shí)現(xiàn)代169179– RTOS在什么時(shí)候以及以什么方式選擇一個(gè)什么常用于觸發(fā)同步行為,比如某個(gè)的數(shù)據(jù)到達(dá)了。18務(wù)就會(huì)被搶占——如圖中t3,t5t9時(shí)刻。任務(wù)3是一個(gè)驅(qū)動(dòng)任務(wù)。其工作在一個(gè)相對(duì)較低的優(yōu)先級(jí),但優(yōu)先級(jí)高于空閑任務(wù)。其大部份時(shí)間都在阻塞態(tài)等待其關(guān)心的。每當(dāng)發(fā)生時(shí)其就3在所有可運(yùn)行任務(wù)中優(yōu)先級(jí)最高。發(fā)生個(gè)任務(wù)進(jìn)入阻塞態(tài),使得任務(wù)3成為具有最高優(yōu)先級(jí)的就緒態(tài)任務(wù)。2期望在t1,t6t9時(shí)刻執(zhí)行。32t7時(shí)刻返回阻塞態(tài)。同時(shí),以搶占系統(tǒng)中的任何其它任務(wù)。在圖中看到,任務(wù)1的只是發(fā)生在在t10后,任務(wù)2才得以機(jī)會(huì)繼續(xù)完成處理。單調(diào)速率調(diào)度(RateMonotonicSchedulingRMS)是一種常用的優(yōu)先級(jí)分配技術(shù)。本書專注于搶占式調(diào)度。RTOS RTOS的應(yīng)用程序由一組獨(dú)立的任務(wù)構(gòu)成——每個(gè)任務(wù)都是具有獨(dú)立權(quán)限的小程序。這些獨(dú)立的任務(wù)之間很可能會(huì)通過相互通信以提供有用的系統(tǒng)功能RTOS19xQueueCreateAPI隊(duì)列由為xQueueHandle的變量進(jìn)行。xQueueCreate()用于創(chuàng)建一個(gè)隊(duì)列,并返回一個(gè)xQueueHandle句柄以便于對(duì)其創(chuàng)建的隊(duì)列進(jìn)行。xQueueCreate()將返回NULL。第五章會(huì)有關(guān)于內(nèi)存堆管理的信息。xQueueHandlexQueueCreate(unsignedportBASE_TYPE程序29xQueueCreate()API函數(shù)原表 參數(shù)參數(shù) 描 返回 ()尾;而xQueueSendToFront()用于將數(shù)據(jù)發(fā)送到隊(duì)列首。但切記不要在中斷服務(wù)例程中調(diào)用xQueueSendToFront()或xQueueSendToBack()。系統(tǒng)提供中斷安全版本的xQueueSendToFrontFromISR()與 constvoid*pvItemToQueue,portTickTypexTicksToWait);程序30ThexQueueSendToFront()API函數(shù)原 constvoid*pvItemToQueue,程序31ThexQueueSendToBack()API函數(shù)原參數(shù)參數(shù) 描 如果 設(shè)為0,并且隊(duì)列已滿,與如果把xTicksToWait設(shè)置為portMAX_DELAY,并且在RTOSConig.hINCLUDE_vTaskSuspend1,那返回 有兩個(gè)可能的返回值pdPASS只會(huì)有一種情況,那就是數(shù)據(jù)被成功發(fā)送到隊(duì)列任務(wù)將被轉(zhuǎn)移到阻塞態(tài)以等待隊(duì)列空間有效—在超時(shí)到來前能夠?qū)?shù)據(jù)成功寫入到隊(duì)列,函數(shù)則會(huì)返回pdPASS?;豦rrQUEUE_FULL。的替代API函數(shù)xQueueReceiveFromISR()將會(huì)在第三章中講述。 constvoid*pvBuffer,portTickTypexTicksToWait);20xQueueReceiveAPIportBASE_TYPExQueuePeek(xQueueHandleconstvoid*pvBuffer,portTickTypexTicksToWait);程序32xQueuePeek()API函數(shù)原表 參數(shù)參數(shù) 描 如果把xTicksToWait設(shè)置為portMAX_DELAY,并且在RTOSConig.hINCLUDE_vTaskSuspend1,那么返回 有兩個(gè)可能的返回值隊(duì)列中成功數(shù)據(jù),函數(shù)則會(huì)返回pdPASS。如果在時(shí)由于隊(duì)列已空而沒有讀到任何數(shù)據(jù),則將返回其它任務(wù)或是中斷服務(wù)例程往隊(duì)列中寫入數(shù)據(jù),函數(shù)則會(huì)返回uxQueueMessagesWaiting(API使用其中斷安全版本uxQueueMessagesWaitingFromISR()。程序33uxQueueMessagesWaiting()API函數(shù)原參數(shù)參數(shù) 描 返回值010.long型數(shù)據(jù)單元。往隊(duì)列中寫數(shù)據(jù)的任務(wù)沒有設(shè)定阻塞超時(shí)時(shí)程序34展現(xiàn)了寫隊(duì)列任務(wù)的代碼實(shí)現(xiàn)。這個(gè)任務(wù)被創(chuàng)建了兩個(gè)實(shí)例,一個(gè)不staticvoidvSenderTask(void*pvParameters{longlValueToSend;portBASE_TYPExStatus;值。隊(duì)列創(chuàng)建時(shí)指定其數(shù)據(jù)單元為long型,所以把參數(shù)強(qiáng)制轉(zhuǎn)換為數(shù)據(jù)單元要求的類型*/lValueToSend=(long)pvParameters;for(;;{xStatus=xQueueSendToBack(xQueue,&lValueToSend,0);if(xStatus!=pdPASS){vPrintString("Couldnotsendtothequeue.\r\n"}/*taskYIELD()通知調(diào)度器現(xiàn)在就切換到其它任務(wù),而不必等到本任務(wù)的時(shí)間片耗盡*/}}程序34例10中的寫隊(duì)列任務(wù)實(shí)現(xiàn)代數(shù)據(jù)無效但等待時(shí)間超過100毫秒,此任務(wù)將會(huì)解除阻塞。在本例中,將不會(huì)出100毫秒超時(shí),因?yàn)橛袃蓚€(gè)任務(wù)在不停地往隊(duì)列中寫數(shù)據(jù)。staticvoidvReceiverTask(void*pvParameters{/*變量,用于保存從隊(duì)列中接收到的數(shù)據(jù)。longlReceivedValue;portBASE_TYPExStatus;constportTickTypexTicksToWait=100//*for(;;{if(uxQueueMessagesWaiting(xQueue)!=0{vPrintString("Queueshouldhavebeenempty!\r\n"}xStatus=xQueueReceive(xQueue,&lReceivedValue,xTicksToWait);if(xStatus==pdPASS){/*}{vPrintString("Couldnotreceivefromthequeue.\r\n"}}}程序35例10中的讀隊(duì)列任務(wù)實(shí)現(xiàn)代元,本例代碼還是創(chuàng)建了一個(gè)可以保存最多5個(gè)long型值的隊(duì)列。/*一個(gè)類型為xQueueHandle的變量.其用于保存隊(duì)列句柄,以便三個(gè)任務(wù)都可以此隊(duì)列intmain(void){xQueue=xQueueCreate(5,sizeof(long));if(xQueue!=NULL){100,而另一個(gè)任務(wù)實(shí)例不停地往隊(duì)列發(fā)送200。兩個(gè)任務(wù)的優(yōu)先級(jí)都設(shè)為1。*/xTaskCreatevSenderTaskSender11000void*1001NULLxTaskCreatevSenderTaskSender21000void*2001,NULL/*創(chuàng)建一個(gè)讀隊(duì)列任務(wù)實(shí)例。其優(yōu)先級(jí)設(shè)為2xTaskCreate(vReceiverTask,"Receiver",1000,NULL,2,NULL/*}{}任務(wù)無法創(chuàng)建。第五章有講述關(guān)于內(nèi)存管理方面的信息*/for(;;}程序36例10中的main()函數(shù)實(shí)現(xiàn)代21102210
xData的結(jié)構(gòu)體數(shù)據(jù)單元。結(jié)構(gòu)體成員包括了一個(gè)數(shù)成員用于讓控制任務(wù)知道這個(gè)數(shù)據(jù)是用來干什么的—從圖中的描述可以看體的iMeaning成員用于讓控制任務(wù)知道這個(gè)數(shù)據(jù)是用來干什么的—從圖中iValue成員可以讓中11./例1與例10務(wù)的優(yōu)先級(jí)低于寫隊(duì)列任務(wù)的優(yōu)先級(jí)。并且本例中的隊(duì)列用于在任務(wù)間傳遞結(jié)構(gòu)體數(shù)據(jù),而非簡單的長整型數(shù)據(jù)。/*typedef{unsignedcharucValue;unsignedcharucSource;}/*兩個(gè)xData類型的變量,通過隊(duì)列進(jìn)行傳遞。staticconstxDataxStructsToSend[2]{{100,mainSENDER_1},/*UsedbySender1.{200,mainSENDER_2}/*UsedbySender2.程序37定義隊(duì)列傳遞的數(shù)據(jù)結(jié)構(gòu),并此類型的兩個(gè)變量在本例中使用在10中讀隊(duì)列任務(wù)具有最高優(yōu)先級(jí),所以隊(duì)列不會(huì)擁有一個(gè)以上的數(shù)據(jù)單元。程序38是寫隊(duì)列任務(wù)的實(shí)現(xiàn)代碼。寫隊(duì)列任務(wù)指定了100毫秒的阻塞超時(shí)時(shí)效,或是等待超過了100毫秒隊(duì)列空間尚無效,其將解除阻塞。在本例中,將不100毫秒超時(shí)的情況,因?yàn)樽x隊(duì)列任務(wù)在不停地從隊(duì)列中讀出數(shù)據(jù)從而騰出隊(duì)staticvoidvSenderTask(void*pvParameters{constportTickTypexTicksToWait=100//*Aspermosttasks,thistaskisimplementedwithinaninfiniteloop.for(;;{/*SendtothestaticvoidvReceiverTask(void*pvParameters{/*結(jié)構(gòu)體變量以保存從隊(duì)列中讀出的數(shù)據(jù)單元portBASE_TYPExStatus;/*Thistaskisalsodefinedwithinaninfiniteloop.for(;;{/*讀隊(duì)列任務(wù)的優(yōu)先級(jí)最低,所以其只可能在寫隊(duì)列任務(wù)阻塞時(shí)得到執(zhí)行。而寫隊(duì)列任務(wù)只會(huì)在隊(duì)列寫深度–本例中隊(duì)列深度為3*/if(uxQueueMessagesWaiting(xQueue)!=3{vPrintString("Queueshouldhavebeenfull!\r\n"}/*Receivefromthe故而不會(huì)因隊(duì)列空而阻塞*/xStatus=xQueueReceive(xQueue,&xReceivedStructure,0);if(xStatus==pdPASS){{}{}}{vPrintString("Couldnotreceivefromthequeue.\r\n"}}}程序39例11中讀隊(duì)列任務(wù)的實(shí)現(xiàn)代碼主函數(shù)main()與上一例比起來只作了微小的改動(dòng)。創(chuàng)建的隊(duì)列數(shù)可以保存三個(gè)xData類型的數(shù)據(jù)單元,并且交換了寫隊(duì)列任務(wù)與讀隊(duì)列任務(wù)的優(yōu)先級(jí)。本例main()函數(shù)實(shí)現(xiàn)代碼參見程序40。intmain(void{/*創(chuàng)建隊(duì)列用于保存最多3個(gè)xData*/xQueuexQueueCreate3,sizeofxDataif(xQueue!=NULL){/*為寫隊(duì)列任務(wù)創(chuàng)建2設(shè)為2,高于讀隊(duì)列任務(wù)的優(yōu)先級(jí)*/xTaskCreate(vReceiverTask,"Receiver",1000,NULL,1,NULL/*}{/*}任務(wù)無法創(chuàng)建。第五章將提供關(guān)于內(nèi)存管理方面的信息*/for(;;}程序40例11的main()函數(shù)實(shí)現(xiàn)代碼2411對(duì)圖25的更詳細(xì)解釋請(qǐng)參見表12。25111125時(shí)時(shí) 描 t611也t7讀隊(duì)列任務(wù)從隊(duì)列數(shù)據(jù),并把讀出的數(shù)據(jù)單元從隊(duì)列中移出。一旦隊(duì)列空2立即解除阻塞,并且因?yàn)槠渚哂懈邇?yōu)先級(jí),所以搶占讀隊(duì)列任務(wù)。寫隊(duì)列任務(wù)2又往隊(duì)列中寫入數(shù)據(jù),填充到剛剛被讀隊(duì)列任務(wù)騰12并未被切換出去,繼續(xù)執(zhí)行。t822轉(zhuǎn)入阻t9讀隊(duì)列任務(wù)從隊(duì)列數(shù)據(jù),并把讀出的數(shù)據(jù)單元從隊(duì)列中移出。一旦隊(duì)列空1又往隊(duì)列中寫入數(shù)據(jù),填充到剛剛被讀隊(duì)列任務(wù)騰寫隊(duì)列任務(wù)2尚還處理阻塞態(tài),所以寫隊(duì)列任務(wù)1并未被切換出去,繼續(xù)執(zhí)嵌入式實(shí)時(shí)系統(tǒng)需要對(duì)整個(gè)系統(tǒng)環(huán)境產(chǎn)生的作出反應(yīng)。舉個(gè)例子,以太網(wǎng)什么時(shí)候采用中斷方式?中斷服務(wù)例程(ISR)ISR外的任務(wù)量有多大?通常情況下,ISR應(yīng)當(dāng)越短越好。設(shè)計(jì)人員采用的策略可以得到實(shí)現(xiàn),而實(shí)現(xiàn)方式不僅簡單,而且具有可性。本章期望能清晰地告訴讀者以下事情 同步。這樣就可以讓中斷處理量大的工作在同步任務(wù)中完成,中斷服務(wù)例程(ISR)ISRISR中完成一樣。這種方案在圖26中展現(xiàn)。26待發(fā)生。當(dāng)發(fā)生后,ISR對(duì)同一個(gè)信號(hào)量進(jìn)行”give”操作,使得延遲處理任務(wù)解除阻塞,從而在延遲處理任務(wù)中得到相應(yīng)的處理。譯者注譯者注:PParsserenPass;VVerhoog,即英語Increment。P(S)/V(S)操作是信號(hào)量的兩個(gè)原子操作,SSemaphore,相當(dāng)于一個(gè)標(biāo)志,可以代表一個(gè)資源,一個(gè)等等,初始值視應(yīng)用場(chǎng)合而定。P(S)/V(S)P(S IFS0THENSS=S–1V(S) S=S+IFS0THEN最多只能保存一個(gè)數(shù)據(jù)單元,所以其不為空則為滿(所謂”二值”)。延遲處理任務(wù)調(diào)用xSemaphoreTake()時(shí),等效于帶阻塞時(shí)間地隊(duì)列,如果隊(duì)列為空的話任務(wù)則進(jìn)入阻塞態(tài)。當(dāng)發(fā)生后,ISR簡單地通過調(diào)用xSemaphoreGiveFromISR()放置一個(gè)令進(jìn)入阻塞態(tài),等待下一次發(fā)生。整個(gè)流程在圖27中有所展現(xiàn)。如27所示,中斷給出信號(hào)量,甚至是在信號(hào)量第一次被獲取之前就給出;而任RTOS中各種信號(hào)量的句柄都在xSemaphoreHandle類型的變量中。程序41vSemaphoreCreateBinary()API函數(shù)原參數(shù)參數(shù) 描 需要說明的是vSemaphoreCreateBinary()在實(shí)現(xiàn)上是一個(gè)宏,所以2API實(shí)際上是由一組宏實(shí)現(xiàn)的,而不是函數(shù)。本書中提及到這些宏的地方都簡單地以函數(shù)27xSemaphoreTake()API除互斥信號(hào)量(RecursiveSemaphore,直譯為遞歸信號(hào)量,按通常的說法譯為互斥信號(hào)量)外,所有類型的信號(hào)量都可以調(diào)用函數(shù)xSemaphoreTake()來獲取。但程序42xSemaphoreTake()API函數(shù)原參數(shù)參數(shù) 描 portTICK_RATE_MS可以用來把心跳時(shí)間單位轉(zhuǎn)換如果把xTicksToWait 設(shè)置為portMAX_DELAY,并且在RTOSConig.h中設(shè)定INCLUDE_vTaskSuspend為1,那么阻返回 有兩個(gè)可能的返回值如果設(shè)定了阻塞超時(shí)時(shí)間(xTicksToWait非0,在函數(shù)返回之前任務(wù)為有效,亦可被成功獲取,返回pdPASS。如果設(shè)定了阻塞超時(shí)時(shí)間(xTicksToWait非0,在函數(shù)返回之前任變?yōu)橛行?,所以不?huì)獲得信號(hào)量,返回pdFALSE。xSemaphoreGiveFromISRAPI除互斥信號(hào)量外 RTOS支持的其它類型的信號(hào)量都可以通過調(diào)用程序43xSemaphoreGiveFromISR()API函數(shù)原參數(shù)參數(shù) 描 pxHigherPriorityTaskWoken等待其有效。調(diào)用xSemaphoreGiveFromISR()會(huì)讓信號(hào)量變?yōu)橛行?,所以?huì)讓其中一個(gè)等待任務(wù)切出阻塞態(tài)。如果調(diào)用xSemaphoreGiveFromISR()使得一個(gè)任是被中斷的任務(wù))xSemaphoreGiveFromISR()會(huì)在函數(shù)內(nèi)部將*pxHigherPriorityTaskWoken設(shè)為如果xemphrGivrmI()將此值設(shè)為pdR,則在中斷退出前應(yīng)當(dāng)進(jìn)行一次上下文切換。這樣才能保證中斷直接返回到就緒態(tài)任務(wù)中優(yōu)先級(jí)最高的任務(wù)中。返回 有兩個(gè)可能的返回值.500毫秒產(chǎn)生一個(gè)軟件中斷。之所以采用軟件中件中斷要方便得多。程序44即是這個(gè)周期任務(wù)的實(shí)現(xiàn)代碼。需要說明的是,此任staticvoid k(void*pvParameters{for(;;{/*此任務(wù)通過每500毫秒產(chǎn)生一個(gè)軟件中斷來”模擬”中斷vTaskDelay(500/portTICK_RATE_MSvPrintString(PeriodictaskAbouttogenerateaninterrupt.\r\n"asm{int0x82}/*這條語句產(chǎn)生中斷*/vPrintString("Periodictask-Interruptgenerated.\r\n\r\n\r\n"}}程序44例12中用于周期性產(chǎn)生軟件中斷的周期任務(wù)實(shí)現(xiàn)代程序45展現(xiàn)的是延遲處理任務(wù)的具體實(shí)現(xiàn)——此任務(wù)通過使用二值信號(hào)量與staticvoidvHandlerTask(void*pvParameters{/*Aspermosttasks,thistaskisimplementedwithinaninfiniteloop.for(;;{/*使用信號(hào)量等待一個(gè)。信號(hào)量在調(diào)度器啟動(dòng)之前,也即此任務(wù)執(zhí)行之前就已被創(chuàng)建。任務(wù)被無超時(shí)阻塞,所以此函數(shù)調(diào)用也只會(huì)在成功獲取信號(hào)量之后才會(huì)返回。此處也沒有必要檢測(cè)返回值*/xSemaphoreTake(xBinarySemaphore,portMAX_DELAY);vPrintString("Handlertask-Processingevent.\r\n"}}程序45例12中延遲處理任務(wù)的實(shí)現(xiàn)代碼(此任務(wù)與中斷同步程序46展現(xiàn)的是中斷服務(wù)例程,這才是真正的中斷處理程序。這段代碼做的DOS平臺(tái)的移植,與其它平臺(tái)的移植可能會(huì)有所不同。對(duì)于實(shí)際使用的平臺(tái),請(qǐng)參考對(duì)應(yīng)移植的demo應(yīng)用示例,以找到正確的語法要求。static{
farvExampleInterruptHandler(voidstaticportBASE_TYPExHigherPriorityTaskWoken;xHigherPriorityTaskWoken=pdFALSE;/*'Give'thesemaphoretounblockthetask.if(xHigherPriorityTaskWoken==pdTRUE{級(jí)–強(qiáng)制進(jìn)行一次任務(wù)切換,以確保中斷直接返回到解出阻塞的任務(wù)(優(yōu)選級(jí)更高)。說明:在實(shí)際使用中,ISR中強(qiáng)制上下文切換的宏依賴于具體移植。此處調(diào)用的是基于OpenDOS}}程序46例12中軟件中斷的中斷服務(wù)例體實(shí)現(xiàn)參見程序47。intmain(void{/*/*if(xBinarySemaphore!=NULL{中斷退出后會(huì)被立即執(zhí)行。在本例中,為延遲處理任務(wù)賦予優(yōu)先級(jí)3*/xTaskCreate(vHandlerTask,"Handler",1000,NULL,3,NULLxTaskCreate( k,"Periodic",1000,NULL,1,NULL/*Starttheschedulersothecreatedtasksstartexecuting.}很可能是由于系統(tǒng)內(nèi)存不足而無法創(chuàng)建空閑任務(wù)。第五章會(huì)提供關(guān)于內(nèi)存管理的信息*/for(;;}程序47例12中的main()函數(shù)實(shí)現(xiàn)代所以延遲處理任務(wù)的輸出信息將周期任務(wù)的兩條輸出信息分開。29對(duì)執(zhí)行流程作出28122912鎖存在二值信號(hào)量中,使得延遲處理任務(wù)在處理完上一個(gè)之后,立即就可以處情形將在圖30中進(jìn)行展現(xiàn)。30圖31使用計(jì)數(shù)信號(hào)量對(duì)“計(jì)數(shù)在這種用法中,每次發(fā)生時(shí),中斷服務(wù)例程都會(huì)“給出(Give)”信號(hào)量——信號(hào)量在每次被給出時(shí)其計(jì)數(shù)值加1。延遲處理任務(wù)每處理一個(gè)任務(wù)都會(huì)”獲取(Take)”一次的數(shù)目與已處理的數(shù)目之間的差值。這種機(jī)制可以參考圖31。加1。RTOS中所有種類的信號(hào)量句柄都由為xSemaphoreHandle類型的變unsignedportBASE_TYPEuxInitialCount程序48xSemaphoreCreateCounting()API函數(shù)原表 參數(shù)參數(shù) 描 最大計(jì)數(shù)值。如果把計(jì)數(shù)信號(hào)量類比于隊(duì)列的話,uxMaxCount值當(dāng)此信號(hào)量用于對(duì)計(jì)數(shù)或鎖存的話,uxMaxCount就是可當(dāng)此信號(hào)量用于對(duì)一組資源的進(jìn)行管理的話,uxMaxCount應(yīng) 當(dāng)此信號(hào)量用于資源管理的話,uxInitialCount應(yīng)當(dāng)?shù)扔?.13用計(jì)數(shù)信號(hào)量代替二值信號(hào)量對(duì)12main()函數(shù)的API調(diào)用如程序49所示:xCountingSemaphore=xSemaphoreCreateCounting(10,0程序49使用xSemaphoreCreateCounting()創(chuàng)建一個(gè)計(jì)數(shù)信號(hào)為了模擬多個(gè)以高頻率發(fā)生,修改了中斷服務(wù)例程,在每次中斷多次”給出50所示。static{
farvExampleInterruptHandler(voidstaticportBASE_TYPExHigherPriorityTaskWoken;xHigherPriorityTaskWoken=pdFALSE;/*多次給出信號(hào)量。第一次給出時(shí)使得延遲處理任務(wù)解除阻塞。后續(xù)給出用于演示利用被信號(hào)量鎖存,以便延遲處理任何依序?qū)@些中斷進(jìn)行處理而不會(huì)丟中斷。用這種方式來模擬處理器產(chǎn)生多個(gè)中斷,盡管這些只是在單次中斷中模擬出來的*/xSemaphoreGiveFromISR(xCountingSemaphore,&xHigherPriorityTaskWoken);xSemaphoreGiveFromISR(xCountingSemaphore,&xHigherPriorityTaskWoken);xSemaphoreGiveFromISR(xCountingSemaphore,&xHigherPriorityTaskWoken);if(xHigherPriorityTaskWoken==pdTRUE{級(jí)–強(qiáng)制進(jìn)行一次任務(wù)切換,以確保中斷直接返回到解出阻塞的任務(wù)(優(yōu)選級(jí)更高)。說明:在實(shí)際使用中,ISR中強(qiáng)制上下文切換的宏依賴于具體移植。此處調(diào)用的是基于OpenDOS}}程序50例13中的中斷服務(wù)例程實(shí)現(xiàn)代32展示了13的輸出結(jié)果。從圖中可以看到,每次中斷發(fā)生后,延遲處理任3213()完全等同于void程序51xQueueSendToFrontFromISR()API函數(shù)原voidportBASE_TYPE程序52xQueueSendToBackFromISR()API函數(shù)原參數(shù)參數(shù) 描 目標(biāo)隊(duì)列的句柄。這個(gè)句柄即是調(diào)用 會(huì)從該指針指向的空間對(duì)應(yīng)長度的數(shù)據(jù)到隊(duì)列 待其數(shù)據(jù)有效。調(diào)用xQueueSendToFrontFromISR()xQueueSendToBackFromISR()會(huì)使得隊(duì)列數(shù)據(jù)變?yōu)閜dTRUE。返回 有兩個(gè)可能的返回值如果由于隊(duì)列已滿而無法將數(shù)據(jù)寫入,則將返回RTOSdemoUART驅(qū)動(dòng),其通過隊(duì)UART驅(qū)動(dòng)的這種實(shí)現(xiàn)方式只是單純了為在中斷服務(wù)中直接解析接收到的字符,然后通過隊(duì)列將解析后經(jīng)得到令發(fā).xQueueSendToBackFromISR()200毫秒往隊(duì)列中發(fā)送五個(gè)數(shù)值,五個(gè)數(shù)值都發(fā)送完后便產(chǎn)生一個(gè)軟件中斷。周期任務(wù)的實(shí)現(xiàn)代碼參見程序53。staticvoidvIntegerGenerator(void*pvParameters{portTickTypexLastExecutionTime;unsignedportLONGulValueToSend=0;inti;/*vTaskDelayUntilxLastExecutionTime=xTaskGetTickCount();for(;;){毫秒執(zhí)行一次vTaskDelayUntil(&xLastExecutionTime,200/portTICK_RATE_MS以此任務(wù)可以確保將所有的數(shù)值都發(fā)送到隊(duì)列。因此不需要指定阻塞超時(shí)時(shí)間*/for(i=0;i<5;i++{xQueueSendToBack(xIntegerQueue,&ulValueToSend,0);}/*產(chǎn)生中斷,以讓中斷服務(wù)例程隊(duì)列vPrintString("Generatortask-Abouttogenerateaninterrupt.\r\n");asm{int0x82}/*Thislinegeneratestheinterrupt.*/vPrintString("Generatortask-Interruptgenerated.\r\n\r\n\r\n"}}程序53例14中的寫隊(duì)列任務(wù)實(shí)現(xiàn)代斷服務(wù)例程的實(shí)現(xiàn)代碼參數(shù)程序54。static{
farvExampleInterruptHandler(voidstaticportBASE_TYPExHigherPriorityTaskWoken;staticunsignedlongulReceivedNumber;/*這些字符串被為staticconst,以保證它們不會(huì)被定位到ISR的??臻g中,即使ISR沒有運(yùn)行它們也是存在的*/staticconstchar*pcStrings[]{"String0\r\n","String1\r\n","String2\r\n","String3\r\n"xHigherPriorityTaskWoken=/*while(xQueueReceiveFromISR(&xHigherPriorityTaskWoken)!=errQUEUE_EMPTY{ulReceivedNumber&=0x03;&pcStrings[ulReceivedNumber],&xHigherPriorityTaskWoken);}if(xHigherPriorityTaskWoken==pdTRUE{的示例程序,以決定正確的語法和符號(hào)。*/}}程序54例14的中斷服務(wù)例程實(shí)現(xiàn)代staticvoidvStringPrinter(void*pvParameters{for(;;){/*Blockonthequeuetowaitfordatatoarrive.xQueueReceive(xStringQueue,&pcString,portMAX_DELAY/*Printoutthestringreceived.vPrintString(pcString}}intmain(void{成功*/xIntegerQueue=xQueueCreate(10,sizeof(unsignedlong));xStringQueue=xQueueCreate(10,sizeof(char*));/*/*創(chuàng)建任務(wù)用于往中斷服務(wù)例程中發(fā)送數(shù)值。此任務(wù)優(yōu)先級(jí)為1xTaskCreate(vIntegerGenerator,"IntGen",1000,NULL,1,NULL/*創(chuàng)建任務(wù)用于從中斷服務(wù)例程中接收字符串,并打印輸出。此任務(wù)優(yōu)先級(jí)為2xTaskCreate(vStringPrinter,"String",1000,NULL,2,NULL/*Starttheschedulersothecreatedtasksstartexecuting.很可能是由于系統(tǒng)內(nèi)存不足而無法創(chuàng)建空閑任務(wù)。第五章會(huì)提供關(guān)于內(nèi)存管理的信息*/for(;;}程序56例14中的main()函數(shù)實(shí)并以五個(gè)字符串作為響應(yīng)。解釋請(qǐng)參考圖3433143414的RTOS移植中允許中斷嵌套。中斷嵌套需要在RTOSConfig.h中定義表17詳細(xì)列出的一個(gè)或兩個(gè)常量。17常常 描 設(shè)置中斷安全版本RTOSAPI可以建立一個(gè)全面的中斷嵌套模型需要設(shè)置configMAX_SYSCALL_INTERRUPT_PRIRITY圖35所示的情形假定常量configMAX_SYSCALL_INTERRUPT_PRIRITY設(shè)置為3,35它們可以調(diào)用中斷安全版本的RTOSAPI函數(shù)4及以上的中斷不受臨界區(qū)影響,所以其不會(huì)被內(nèi)核的任何行為阻常需要嚴(yán)格時(shí)間精度的功能(如電機(jī)控制)會(huì)使用高于不需要調(diào)用任何RTOSAPICortexM3使用低優(yōu)先級(jí)號(hào)數(shù)值表示邏輯上的高優(yōu)先級(jí)中斷。這顯得不是那么直0(或是其它低優(yōu)先級(jí)號(hào)數(shù)值),因?yàn)檫@將會(huì)使得這個(gè)中斷在系統(tǒng)中擁有最高優(yōu)先級(jí)——如果這個(gè)優(yōu)先級(jí)高于configMAX_SYSCALL_INTERRUPT_PRIRITY,將很可能導(dǎo)致系統(tǒng)。STM32,ST的驅(qū)動(dòng)庫中將最低優(yōu)先級(jí)指定為15,而最高優(yōu)先級(jí)指定為0?,F(xiàn)在LCD顯示的是被破壞了的字符串”owAbort,Retry,Fail?orld”。/*TheCcodebeingcompiled.155:PORTA|=/*Theassemblycodeproduced. 481CLDRR0,[PC,#0x0070];Obtaintheaddressof 6801LDR ;ReadthevalueofPORTAinto 2201MOV ;Movetheabsoluteconstant1into A4311ORR ;ORR1(PORTA)withR2(constant C6001STR ;Storethenewvaluebackto程序57讀-改-寫過程示被中斷??紤]如下情形,兩個(gè)任務(wù)都試圖更新一個(gè)名為PORTA的內(nèi)存映射寄存器:器在任務(wù)A回寫到PORTA之前曾經(jīng)保存過的值。APORTAA獲得拷貝與更新回BPORTAAPORTA的回寫操作,覆蓋了任務(wù)BPORTA進(jìn)行的修改結(jié)果,效果上等同于破壞了PORTA寄存器的值。任都自的間其身在存存中值如果一個(gè)數(shù)除了自己??臻g上分配的數(shù)據(jù)或是內(nèi)核寄存器中的數(shù)據(jù)外,不會(huì)其它任何數(shù)8/*Aparameterispassedintothefunction.ThiswilleitherbepassedonthestackorinaCPUregister.Eitherwayissafeaseachtaskmaintainsitsownstackanditsownsetofregistervalues.*/longlAddOneHundered(longlVar1{/*Thisfunctionscopevariablewillalsobeallocatedtothestackoraregister,dependingoncompilerandoptimizationlevel.EachtaskorinterruptthatcallsthisfunctionwillhaveitsowncopyoflVar2.*/longlVar2=lVar1+/*MostlikelythereturnvaluewillbecedinaCPUregister,althoughittoocouldbecedonthestack.*/return}程序58可重入函數(shù)示/*InthiscaselVar1isaglobalvariablesoeverytaskthatthefunctionwillbeaccessingthesamesinglecopyofthevariable.*/longlVar1;longlNonsenseFunction(void{/*Thisvariableisstaticsoisnotallocatedonthestack.Eachtaskthatcallsthefunctionwillbeaccessingthesamesinglecopyofthevariable.*/staticlonglState=0;longlReturn;switch(lState{case0:lReturn=lVar1+10;lState=1;case1:lReturn=lVar1+20;lState=0;}}程序59不可重入函數(shù)示taskENTER_CRITICAL()taskEXIT_CRITICAL()之間的代碼區(qū)間,程序60是一段范例代碼。CriticalSections也被稱作CriticalRegions。/*為了保證對(duì)PORTA寄存器的不被中斷,將操作放入臨界區(qū)。進(jìn)入臨界區(qū)*//*在taskENTER_CRITICALtaskEXIT_CRITICAL()嵌套,但只是針對(duì)優(yōu)先級(jí)高于configMAX_SYSCALL_INTERRUPT_PRIORITY–而且這些中斷不允許RTOSAPI函數(shù)PORTA|=程序60使用臨界區(qū)對(duì)寄存器的進(jìn)行保字符串。這個(gè)標(biāo)準(zhǔn)輸出即是Open 護(hù)。如程序61所示。voidvPrintString(constportCHAR*pcString{{printf("%s",pcString);fflush(stdout);}if(kbhit(){}}程序61vPrintString()的一種可能的實(shí)現(xiàn)方configMAX_SYSCAL_INTERRUPT_PRIORITY及以下的中斷——依賴于具體使用的RTOS移植。搶占式上下文切換只可能在某個(gè)中斷中完成,所以調(diào)用taskENTER_CRITICAL()的任務(wù)可以在中斷關(guān)閉的時(shí)段一直保臨界區(qū)必須只具有很短的時(shí)間,否則會(huì)反過來影響中斷響應(yīng)時(shí)間。在每次調(diào)用個(gè)角度來看,對(duì)標(biāo)準(zhǔn)輸出的保護(hù)不應(yīng)當(dāng)采用臨界區(qū)(如程序61所示),因?yàn)閷懡K端在時(shí)間上會(huì)是一個(gè)相對(duì)較長的操作。DOS模擬器和Open 0時(shí)才會(huì)真正退出——taskENTER_CRITICAL()都配套調(diào)用taskEXIT_CRITICAL()之后。vTaskSuspendAllAPIvoidvTaskSuspendAll(void程序62vTaskSuspendAll()API函數(shù)原xTaskResumeAllAPIportBASE_TYPExTaskResumeAll(void程序63xTaskResumeAll()API函數(shù)原參數(shù)參數(shù) 描 被喚醒后才會(huì)得到執(zhí)行。如果一個(gè)掛起的上下文切換請(qǐng)求在xTaskResumeAll()返回前得到執(zhí)行,則函數(shù)返回pdTRUE。在其它情況下,xTaskResumeAll()返回pdFALSE。的vTaskSuspendAll()都配套調(diào)用了xTaskResumAll()之后。voidvPrintString(constportCHAR*pcString{/*Writethestringtostdout,suspendingtheschedulerasamethodofmutualexclusion.*/{printf("%s",pcString);fflush(stdout);}/*Allowanykeytostoptheapplicationrunning.Arealapplicationthatactuallyusedthekeyvalueshouldprotectaccesstothekeyboardinputtoo.*/if(kbhit()){}}程序64vPrintString()實(shí)現(xiàn)代詞MUTEX(互斥量)源于”MUTualEXclusion”。要合法地資源,其必須先成功地得到(Take)該資源對(duì)應(yīng)的令牌(成為令牌持有者)。允許共享資源。這種機(jī)制在圖36中展示。xSemaphoreCreateMutexAPI互斥量是一種信號(hào)量。RTOS中所有種類的信號(hào)量句柄都保存在類型互斥量在使用前必須先創(chuàng)建。創(chuàng)建一個(gè)互斥量類型的信號(hào)量需要使用程序65xSemaphoreCreateMutex()API函數(shù)原表 參數(shù)參數(shù) 描返回值如果返回NULL表示互斥量創(chuàng)建失敗。原因是內(nèi)存堆空間不足導(dǎo)致.實(shí)現(xiàn)代碼參見程序66。staticvoidprvNewPrintString(constportCHAR*pcString{pdTRUE后,才能共享資源(此處是指標(biāo)準(zhǔn)輸出)。*/xSemaphoreTake(xMutex,portMAX_DELAY{/*程序執(zhí)行到這里表示已經(jīng)成功持有互斥量?,F(xiàn)在可以自由標(biāo)準(zhǔn)輸出,因?yàn)槿我鈺r(shí)刻只會(huì)有一個(gè)任務(wù)能持有互斥量。*/printf("%s",pcString);fflush(stdout);/*互斥量必須歸還}xSemaphoreGive(xMutex/*Allowanykeytostoptheapplicationrunning.Arealapplicationthatactuallyusedthekeyvalueshouldprotectaccesstothekeyboardtoo.Arealapplicationisveryunlikelytohavemorethanonetaskprocessingkeypressesthough!*/if(kbhit(){}}程序66prvNewPrintString()實(shí)現(xiàn)代隨機(jī)延遲時(shí)間。任務(wù)的參數(shù)用于向任務(wù)的每個(gè)實(shí)例傳遞各自的輸出字符串。任務(wù)prvPrintTask()的實(shí)現(xiàn)代碼參見程序67。intmain(void{xMutex=srand(567/*Checkthesemaphorewascreatedsuccessfullybeforecreatingthetasks.if(xMutex!=NULL{/*Createtwoinstancesofthetasksthatwritetostdout.Thestringtheywriteispassedinasthetaskparameter.Thetasksarecreatedatdifferentprioritiessosomepre-emptionwilloccur.*/xTaskCreate(prvPrintTask,"Print1",1000,"Task1******************************************\r\n",1,NULL);xTaskCreate(prvPrintTask,"Print2",1000,"Task /*Starttheschedulersothecreatedtasksstartexecuting.}很可能是由于系統(tǒng)內(nèi)存不足而無法創(chuàng)建空閑任務(wù)。第五章會(huì)提供關(guān)于內(nèi)存管理的信息*/for(;;}程序68例15的main()函數(shù)實(shí)37153815于兩個(gè)任務(wù)優(yōu)先之間的中等優(yōu)先級(jí)任務(wù)開始執(zhí)行——這就會(huì)導(dǎo)致一個(gè)高優(yōu)先級(jí)任務(wù)在等待一個(gè)低優(yōu)先級(jí)任務(wù),而低優(yōu)先級(jí)任務(wù)卻無法執(zhí)行!這種的情形在圖39中進(jìn)行圖40優(yōu)先級(jí)反轉(zhuǎn)的一種情RTOS中互斥量與二值信號(hào)量十分相似——唯一的區(qū)別就是互斥量自動(dòng)提供優(yōu)先級(jí)繼承暫時(shí)地將互斥量持有者的優(yōu)先級(jí)提升至所有等待此互斥量的任務(wù)所具有的最高優(yōu)先級(jí)。持有互斥量的低優(yōu)先級(jí)任務(wù)”繼承”圖4040由于最好是優(yōu)先考慮避免優(yōu)先級(jí)反轉(zhuǎn),并且因?yàn)镽TOS本身是面向內(nèi)存有限死鎖是利用互斥量提供互斥功能的另一個(gè)潛在缺陷。Deadlock性地稱為”deadlyembrace(抱死)”量X被釋放。A持有的互斥量。死鎖于是發(fā)生,因?yàn)閮蓚€(gè)任務(wù)都不可能再執(zhí)行下護(hù)的資源——其它任務(wù)要該資源只能間接地通過守護(hù)任務(wù)提供的服務(wù)。守護(hù)任務(wù)使用了一個(gè)RTOS隊(duì)列來對(duì)終端實(shí)現(xiàn)串行化。該任務(wù)內(nèi)部實(shí)現(xiàn)息地到來。守護(hù)任務(wù)的
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年機(jī)房建設(shè)與運(yùn)維一體化施工合同書3篇
- 2025版事業(yè)單位聘用合同書(二零二五年度)服務(wù)期限與待遇約定3篇
- 2025年度藝術(shù)品代購代銷服務(wù)協(xié)議范本4篇
- 2025年項(xiàng)目部安全責(zé)任合同書編制指南3篇
- 2025年度個(gè)人購房裝修配套服務(wù)合同
- 2025年高新技術(shù)企業(yè)員工薪酬保障與晉升協(xié)議書3篇
- 2025年食材配送與智慧物流解決方案合作協(xié)議3篇
- 2025年度二手房買賣合同綠色裝修與改造服務(wù)合同4篇
- 2025年度美容院美容師市場(chǎng)調(diào)研與分析服務(wù)合同4篇
- 提前終止房地產(chǎn)買賣合同(2025版)2篇
- 《阻燃材料與技術(shù)》-顏龍 習(xí)題解答
- 2024-2030年中國食品飲料灌裝設(shè)備行業(yè)市場(chǎng)發(fā)展趨勢(shì)與前景展望戰(zhàn)略分析報(bào)告
- 建筑結(jié)構(gòu)課程設(shè)計(jì)成果
- 纖維增強(qiáng)復(fù)合材料 單向增強(qiáng)材料Ⅰ型-Ⅱ 型混合層間斷裂韌性的測(cè)定 編制說明
- 習(xí)近平法治思想概論教學(xué)課件緒論
- 寵物會(huì)展策劃設(shè)計(jì)方案
- 孤殘兒童護(hù)理員(四級(jí))試題
- 醫(yī)院急診醫(yī)學(xué)小講課課件:急診呼吸衰竭的處理
- 腸梗阻導(dǎo)管在臨床中的使用及護(hù)理課件
- 小學(xué)英語單詞匯總大全打印
- 衛(wèi)生健康系統(tǒng)安全生產(chǎn)隱患全面排查
評(píng)論
0/150
提交評(píng)論