FreeRTOS概念與任務(wù)概念

操作系統(tǒng)允許多個(gè)任務(wù)同時(shí)運(yùn)行,其任務(wù)調(diào)度器的責(zé)任就是:決定某一時(shí)刻究竟運(yùn)行那個(gè)任務(wù)。
有的OS調(diào)度方式:基于時(shí)間的任務(wù)調(diào)度,如Unix。但是,RTOS的任務(wù)調(diào)度器被設(shè)計(jì)為可預(yù)測(cè)的,這是實(shí)時(shí)系統(tǒng)所必須的,實(shí)時(shí)就要求os必須對(duì)某一個(gè)事件做出實(shí)時(shí)的響應(yīng)。所以實(shí)時(shí)系統(tǒng)的任務(wù)調(diào)度方法是非常重要的,如給任務(wù)分配優(yōu)先級(jí)。

  • 實(shí)時(shí):硬實(shí)時(shí)和軟實(shí)時(shí)。
    硬實(shí)時(shí):規(guī)定時(shí)間內(nèi)必須完成,不允許超時(shí)。
    軟實(shí)時(shí):沒有那么嚴(yán)格。

  • 任務(wù)
    把功能劃分為多個(gè)任務(wù),每個(gè)任務(wù)負(fù)責(zé)實(shí)現(xiàn)其中一部分,每個(gè)任務(wù)都是一個(gè)簡(jiǎn)單的程序,通常是死循環(huán)。

  • RTOS核心內(nèi)容
    實(shí)時(shí)內(nèi)核:可剝奪型內(nèi)核,內(nèi)核負(fù)責(zé)管理任務(wù),決定運(yùn)行哪個(gè)任務(wù),如某個(gè)任務(wù)告訴任務(wù)調(diào)度器表明自己準(zhǔn)備好,可以被調(diào)度執(zhí)行。

為什么選擇freeRTOS:

  1. 開源、免費(fèi)
  2. 很多半導(dǎo)體廠商的sdk使用freeRTOS
  3. 文件少,用C和匯編來寫,學(xué)習(xí)簡(jiǎn)單,可讀性極強(qiáng)。

一、FreeRTOS 系統(tǒng)配置和風(fēng)格

FreeRTOS的系統(tǒng)配置文件為:FreeRTOSConfig.h,可以完成FreeRTOS的裁剪和配置。

1.1 變量風(fēng)格

  1. 非stdint類型的變量使用前綴x,比如基本的Type_t和TickType_t類型,這些類型在移植層定義,定義成符合處理器架構(gòu)的最高效類型;
  2. size_t類型的變量使用前綴x
  3. 枚舉類型變量使用前綴e
  4. 指針類型變量在類型基礎(chǔ)上附加前綴p

1.2 函數(shù)

  1. 在文件作用域范圍的函數(shù)前綴為prv
  2. API函數(shù)的前綴為它們的返回類型,當(dāng)返回為空時(shí),前綴為v
  3. API函數(shù)名字起始部分為該函數(shù)所在的文件名。比如vTaskDelete函數(shù)定義在tasks.c,并且該函數(shù)返回空。

1.3 宏

  1. INCLUDE_ 開始的宏表示使能FreeRTOS中相應(yīng)的API函數(shù),F(xiàn)reeRTOS中的裁剪和配置就是通過這種用條件編譯的方法來實(shí)現(xiàn)的。條件編譯的好處就是節(jié)省空間,不需要的功能就不用編譯,減少占用ROM和RAM大小。
  2. 宏的名字起始部分為該宏定義所在的文件名的一部分。比如configUSE_PREEMPTION定義在FreeRTOSConfig.h文件中。

1.4 misc

  1. 注釋:注釋單行不超過80列,特殊情況除外。不使用C++風(fēng)格的雙斜線(//)注釋,使用 /*.. */
  2. 源碼包中,RTOS核心代碼位于三個(gè)源文件中,分別是tasks.c、queue.c和list.c

1.5 移植FreeRTOS

  1. 將tasks.c、queue.c和list.c這三個(gè)內(nèi)核代碼加入工程,將port.c和heap_1.c這兩個(gè)與處理器相關(guān)代碼加入工程。
  2. FreeRTOS內(nèi)核是高度可定制的,使用配置文件FreeRTOSConfig.h進(jìn)行定制。每個(gè)FreeRTOS應(yīng)用都必須包含這個(gè)頭文件,用戶根據(jù)實(shí)際應(yīng)用來裁剪FreeRTOS內(nèi)核。這個(gè)配置文件是針對(duì)用戶程序的,而非內(nèi)核,因此配置文件一般放在應(yīng)用程序目錄下,不要放在RTOS內(nèi)核源碼目錄下。配置文件具體的參數(shù)可以參考:FreeRTOS系列第6篇---FreeRTOS內(nèi)核配置說明。 如: configUSE_PREEMPTION: 為1時(shí)RTOS使用搶占式調(diào)度器,為0時(shí)RTOS使用協(xié)作式調(diào)度器(時(shí)間片)。

二、 FreeRTOS任務(wù)基礎(chǔ)知識(shí)

FreeRTOS的核心就是任務(wù)管理,必須掌握任務(wù)的創(chuàng)建、刪除、掛起和恢復(fù)等操作。

2.1 多任務(wù)系統(tǒng)

未使用系統(tǒng)時(shí),都是在main中使用while(1)做一個(gè)大循環(huán)來完成所有的處理,即應(yīng)用程序是一個(gè)無(wú)限的循環(huán),循環(huán)中調(diào)用相應(yīng)的函數(shù)完成所需的處理。中斷服務(wù)函數(shù)作為前臺(tái)程序,大循環(huán)while(1)作為后臺(tái)程序。

前后臺(tái)系統(tǒng)

缺點(diǎn):實(shí)時(shí)性差,所有任務(wù)都是排隊(duì)等著輪流執(zhí)行,緊急的任務(wù)不能及時(shí)執(zhí)行,并且任務(wù)管理不方便。

多任務(wù)系統(tǒng):把一個(gè)大問題(應(yīng)用)“分而治之”,把大問題劃分成很多個(gè)小問題(小任務(wù)),逐步把小問題解決掉。這些小任務(wù)是并發(fā)處理的。那么哪個(gè)任務(wù)先執(zhí)行呢,可以通過任務(wù)調(diào)度器來完成。FreeRTOS是一個(gè)搶占式的實(shí)時(shí)多任務(wù)系統(tǒng)。
從圖中可以看出,中斷返回后會(huì)進(jìn)行一次任務(wù)調(diào)度。永遠(yuǎn)運(yùn)行的是就緒態(tài)優(yōu)先級(jí)最高的任務(wù)。

搶占式多任務(wù)系統(tǒng)

2.2 FreeRTOS任務(wù)與協(xié)程

FreeRTOS可以使用任務(wù)或協(xié)程(Co-Routine),但是任務(wù)和協(xié)程使用不同的API函數(shù),不能互傳數(shù)據(jù)。

FreeRTOS的一個(gè)實(shí)時(shí)應(yīng)用可以作為一個(gè)獨(dú)立的任務(wù),每個(gè)任務(wù)都有自己的運(yùn)行環(huán)境,不依賴于系統(tǒng)中其他的任務(wù)。FreeRTOS會(huì)重復(fù)的開啟、關(guān)閉每個(gè)任務(wù),職責(zé)是確保當(dāng)一個(gè)任務(wù)開始執(zhí)行時(shí),上下文環(huán)境(寄存器值、堆棧內(nèi)容)和任務(wù)上一次退出時(shí)相同。因此,每個(gè)任務(wù)都有堆棧。

  • 任務(wù)特性
    簡(jiǎn)單,沒有使用限制,支持搶占,支持優(yōu)先級(jí)
    每個(gè)任務(wù)都擁有堆棧導(dǎo)致RAM使用量增大。
    如果使用搶占的話,必須仔細(xì)考慮重入的問題。

協(xié)程:為了資源很少的MCU而做的。如今使用較少了。

2.2.1 任務(wù)狀態(tài)

運(yùn)行態(tài)、就緒態(tài)(可以運(yùn)行了)、阻塞態(tài)(等待某個(gè)外部事件)、掛起態(tài)
運(yùn)行態(tài):當(dāng)前運(yùn)行的
就緒態(tài):當(dāng)前已經(jīng)準(zhǔn)備好,告訴調(diào)度器可以被調(diào)度運(yùn)行了
阻塞態(tài):某個(gè)任務(wù)等待某個(gè)事件,必須等待事件發(fā)生才能被調(diào)度
掛起態(tài):暫時(shí)不運(yùn)行。


2.2.2 任務(wù)優(yōu)先級(jí)

每個(gè)任務(wù)都可以分配從0~(configMAX_PRIORITIES-1)的優(yōu)先級(jí),數(shù)字越大,優(yōu)先級(jí)越高,數(shù)字越低表示任務(wù)的優(yōu)先級(jí)越低,0的優(yōu)先級(jí)最低。
空閑任務(wù)是啟動(dòng)RTOS調(diào)度器時(shí)由內(nèi)核自動(dòng)創(chuàng)建的任務(wù),這樣可以確保至少有一個(gè)任務(wù)在運(yùn)行??臻e任務(wù)具有最低任務(wù)優(yōu)先級(jí)。
空閑任務(wù)鉤子是一個(gè)函數(shù),每一個(gè)空閑任務(wù)周期被調(diào)用一次。 通常,使用這個(gè)空閑鉤子函數(shù)設(shè)置CPU進(jìn)入低功耗模式。
FreeRTOS調(diào)度器確保:處于就緒態(tài)或運(yùn)行態(tài)的高優(yōu)先級(jí)任務(wù)獲取處理器使用權(quán),即就緒態(tài)的最高優(yōu)先級(jí)的任務(wù)才會(huì)運(yùn)行。

2.2.3 任務(wù)實(shí)現(xiàn)

任務(wù)實(shí)現(xiàn):即任務(wù)的具體工作內(nèi)容。
FreeRTOS中,可以使用xTaskCreate()或xTaskCreateStatic()來創(chuàng)建任務(wù),參數(shù)是pxTaskCode,就是這個(gè)任務(wù)的任務(wù)函數(shù)(就是完成本任務(wù)工作的函數(shù))
模板:

void vATaskFunction(void *pvParameters)
{
  for(;;){ 
        Specific code to implement the task; //任務(wù)應(yīng)用程序
        vTaskDelay();//用來引起任務(wù)調(diào)度的函數(shù),這最好要有。
}
/* 不能從任務(wù)函數(shù)中返回或者退出,如果使用則調(diào)用configASSERT(),如果一定要從任務(wù)函數(shù)中退出的話,一定要調(diào)用函數(shù) vTaskDelete(NULL);來刪除此任務(wù)。*/
  vTaskDelete(NULL);
}

example:
    //創(chuàng)建開始任務(wù)
    xTaskCreate((TaskFunction_t )start_task,            //任務(wù)函數(shù)
                (const char*    )"start_task",                    //任務(wù)名稱
                (uint16_t       )START_STK_SIZE,        //任務(wù)堆棧大小
                (void*          )NULL,                  //傳遞給任務(wù)函數(shù)的參數(shù)
                (UBaseType_t    )START_TASK_PRIO,       //任務(wù)優(yōu)先級(jí)
                (TaskHandle_t*  )&StartTask_Handler);   //任務(wù)句柄              
    vTaskStartScheduler();          //開啟任務(wù)調(diào)度
//開始任務(wù)任務(wù)函數(shù)
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL();           //進(jìn)入臨界區(qū)
    //創(chuàng)建LED0任務(wù)
    xTaskCreate((TaskFunction_t )led0_task,         
                (const char*    )"led0_task",       
                (uint16_t       )LED0_STK_SIZE, 
                (void*          )NULL,              
                (UBaseType_t    )LED0_TASK_PRIO,    
                (TaskHandle_t*  )&LED0Task_Handler);   
    //創(chuàng)建LED1任務(wù)
    xTaskCreate((TaskFunction_t )led1_task,     
                (const char*    )"led1_task",   
                (uint16_t       )LED1_STK_SIZE, 
                (void*          )NULL,
                (UBaseType_t    )LED1_TASK_PRIO,
                (TaskHandle_t*  )&LED1Task_Handler);         
    vTaskDelete(StartTask_Handler); //刪除開始任務(wù)
    taskEXIT_CRITICAL();            //退出臨界區(qū)
}

//LED0任務(wù)函數(shù) 
void led0_task(void *pvParameters)
{
    while(1)
    {
        LED0=~LED0;
        vTaskDelay(500);
    }
}   
//LED1任務(wù)函數(shù)
void led1_task(void *pvParameters)
{
    while(1)
    {
        LED1=0;
        vTaskDelay(200);
        LED1=1;
        vTaskDelay(800);
    }
}
  1. 任務(wù)函數(shù)的返回值一定是void類型。
  2. 任務(wù)函數(shù)一般不允許跳出循環(huán),如果想要退出,就是一定要調(diào)用vTaskDelete(NULL)刪除此任務(wù)。

2.2.4 任務(wù)控制塊

描述任務(wù)屬性的數(shù)據(jù)結(jié)構(gòu)叫做任務(wù)控制塊。
FreeRTOS的每個(gè)任務(wù)都有一些屬性需要存儲(chǔ),可以集合到一個(gè)結(jié)構(gòu)體來表示。TCB_t。在使用創(chuàng)建任務(wù)時(shí)自動(dòng)為任務(wù)分配一個(gè)任務(wù)控制塊。
如:
棧頂、列表、任務(wù)優(yōu)先級(jí)、任務(wù)名字。
PS:很大,如果有條件編譯,先不看,沒有條件編譯的是核心,也是重點(diǎn)理解的。

任務(wù)控制塊很大,很占內(nèi)存,一般在創(chuàng)建任務(wù)(vTaskCreate())的時(shí)候,如果使用的是動(dòng)態(tài)內(nèi)存申請(qǐng),那么函數(shù)為任務(wù)控制塊自動(dòng)調(diào)用創(chuàng)建,靜態(tài)的話需要自己手動(dòng)填寫。

2.2.5 任務(wù)堆棧

用來保存任務(wù)現(xiàn)場(chǎng)(CPU寄存器的值)。
FreeRTOS能夠恢復(fù)上一個(gè)任務(wù)的運(yùn)行是因?yàn)橛?,任?wù)堆棧。任務(wù)調(diào)度器切換任務(wù)時(shí),將當(dāng)前任務(wù)的現(xiàn)場(chǎng)(CPU寄存器值)保存在此任務(wù)堆棧中,等下次任務(wù)運(yùn)行時(shí),用堆棧中保存的值來恢復(fù)線程,然后從上次中斷的地方開始運(yùn)行。

創(chuàng)建任務(wù)時(shí),需要給任務(wù)指定堆棧。xTaskCreate()動(dòng)態(tài)創(chuàng)建時(shí)任務(wù)堆棧自動(dòng)創(chuàng)建,xTaskCreateStatic()靜態(tài)創(chuàng)建任務(wù)時(shí),需要程序員自己定義任務(wù)堆棧,然后將首地址作為函數(shù)的參數(shù)(puxStackBuffer)傳遞給函數(shù)。
PS: 要根據(jù)任務(wù)動(dòng)態(tài)的修改任務(wù)堆棧的大小。如任務(wù)堆棧分配小了,很容易卡死。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容