FreeRTOS簡(jiǎn)介
FreeRTOS,全稱(chēng)Free Real Time Operating System,即免費(fèi)的實(shí)時(shí)操作系統(tǒng)。相比于計(jì)算機(jī)中用到的Windows,MacOS,Linux等操作系統(tǒng),實(shí)時(shí)操作系統(tǒng)(RTOS)是一種輕量級(jí)的操作系統(tǒng),適用于嵌入式硬件中,用于解決單片機(jī)類(lèi)裸機(jī)輪詢(xún)方式在處理多個(gè)任務(wù)時(shí)的實(shí)時(shí)性不高的問(wèn)題。
目前的實(shí)時(shí)操作系統(tǒng)有好多種,除FreeRTOS外,還有μCOS、RT-Thread、RTX、Alios Things、Huawei LiteOS等。
什么是RTOS?
實(shí)時(shí)操作系統(tǒng)(RTOS)的主要特點(diǎn)是可以實(shí)現(xiàn)多任務(wù),與多任務(wù)系統(tǒng)相對(duì)的是裸機(jī)系統(tǒng)。
裸機(jī)系統(tǒng)
裸機(jī)系統(tǒng)就是最初我們學(xué)習(xí)單片機(jī)編程時(shí)接觸的那種編程方式,main函數(shù)中一個(gè)while大循環(huán)依次處理各個(gè)模塊的任務(wù),對(duì)于需要及時(shí)檢測(cè)的事件會(huì)使用中斷。這種使用大循環(huán)的程序運(yùn)行方式也叫輪詢(xún)系統(tǒng),加上中斷處理函數(shù)后又稱(chēng)前后臺(tái)系統(tǒng),中斷處理稱(chēng)作前臺(tái),無(wú)限循環(huán)稱(chēng)作后臺(tái)。
多任務(wù)系統(tǒng)
多任務(wù)系統(tǒng)是將各個(gè)處理模塊編寫(xiě)為單獨(dú)的任務(wù),每個(gè)任務(wù)本身是個(gè)無(wú)限循環(huán),程序運(yùn)行初期會(huì)創(chuàng)建各個(gè)子任務(wù),通過(guò)任務(wù)調(diào)度的方式,利用各任務(wù)的阻塞時(shí)刻不斷切換運(yùn)行各個(gè)任務(wù),達(dá)到一種看起來(lái)是多個(gè)任務(wù)在同時(shí)運(yùn)行的一種效果。并且,通過(guò)中斷標(biāo)志以及任務(wù)間通信的相關(guān)機(jī)制,可以實(shí)現(xiàn)任務(wù)之間的快速響應(yīng)。
FreeRTOS特點(diǎn)
使用免費(fèi)!
系統(tǒng)簡(jiǎn)單小巧、文件數(shù)量少、通常情況下內(nèi)核占用4~9k字節(jié)空間
搶占式內(nèi)核
代碼主要由C編寫(xiě),可移植性高,已實(shí)現(xiàn)在30多種架構(gòu)的芯片上移植
任務(wù)與任務(wù),任務(wù)與中斷間的通信方式包括:信號(hào)量、消息隊(duì)列、事件標(biāo)志組、任務(wù)通知
具有優(yōu)先級(jí)繼承特性的互斥信號(hào)令,避免優(yōu)先級(jí)反轉(zhuǎn)問(wèn)題
高效的軟件定時(shí)器
FreeRTOS源碼目錄結(jié)構(gòu)
這里以FreeRTOS v9.0.0版本為例,代碼包含F(xiàn)reeRTOS和FreeRTOS-Plus文件夾,后者是一些補(bǔ)充文件,初學(xué)者用不到,可以先忽略。在FreeRTOS文件夾中主要關(guān)注source文件夾,這里是FreeRTOS的全部源碼,包括6個(gè)c文件和include文件夾下的多個(gè)h文件。另外,在portable文件夾下,是針對(duì)不同硬件平臺(tái)的單獨(dú)區(qū)分使用的代碼,目前考慮使用Keil開(kāi)發(fā)STM32F407,所以portable文件夾只需使用RVDS的ARM_CM4F以及MemMang。
關(guān)于各個(gè)c文件的主要用途:
port.c : 針對(duì)不同硬件平臺(tái)的接口
heap_4.c : 內(nèi)存管理相關(guān)
croutine.c : 協(xié)程相關(guān)
event_groups.c : 事件標(biāo)志組相關(guān)
list.c : 列表,F(xiàn)reeRTOS的一種基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)
queue.c : 隊(duì)列相關(guān)
tasks.c : 任務(wù)創(chuàng)建、掛起、恢復(fù)、調(diào)度相關(guān)
timers.c : 軟件定時(shí)器相關(guān)
另外在Demo文件夾下還需要用到一個(gè)FreeRTOSConfig.h,該文件中通過(guò)各種宏定義的方式來(lái)配置FreeRTOS需要使用哪些資源。
?
任務(wù)相關(guān)API函數(shù)
任務(wù)創(chuàng)建 xTaskCreate()
函數(shù)原型(tasks.c中):
BaseType_t xTaskCreate( TaskFunction_t pxTaskCode,
const char * const pcName,
const uint16_t usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask )
pxTaskCode:自己創(chuàng)建的任務(wù)函數(shù)的函數(shù)名
pcName:任務(wù)的名字,隨意起,字符串型
usStackDepth:任務(wù)堆棧大小(實(shí)際上申請(qǐng)到的是這里的4倍),設(shè)的太小任務(wù)可能無(wú)法運(yùn)行!
pvParameters:任務(wù)函數(shù)的參數(shù),不需要傳參設(shè)為NULL即可
uxPriority:任務(wù)優(yōu)先級(jí),0~(configMAX_PRIORITIES-1)
pxCreatedTask:任務(wù)句柄,實(shí)際是一個(gè)指針,也是任務(wù)的任務(wù)堆棧
返回值:
pdPASS:數(shù)值1,任務(wù)創(chuàng)建成功,且添加到就緒列表
錯(cuò)誤代碼:負(fù)數(shù),任務(wù)創(chuàng)建識(shí)別
這里的返回值是BaseType_t,實(shí)際它是long類(lèi)型,可以在portmacro.h文件中看到其定義:
typedef long BaseType_t;
另外,任務(wù)句柄的類(lèi)型為T(mén)askHandle_t,實(shí)際它是void *類(lèi)型,可以在task.h文件中看到其定義:
typedef void * TaskHandle_t;
注:xTaskCreate()是一種動(dòng)態(tài)創(chuàng)建任務(wù)的方式,系統(tǒng)通過(guò)heap_4.c的配置為任務(wù)自動(dòng)分配相關(guān)內(nèi)存,還有一種靜態(tài)創(chuàng)建任務(wù)的方式xTaskCreateStatic(),這里先不介紹。
任務(wù)刪除 vTaskDelete()
函數(shù)原型(tasks.c中):
void vTaskDelete( TaskHandle_t xTaskToDelete )
參數(shù):
xTaskToDelete:要?jiǎng)h除的任務(wù)的任務(wù)句柄
注:通過(guò) xTaskCreate()動(dòng)態(tài)創(chuàng)建的任務(wù),在使用vTaskDelete()刪除后,該任務(wù)創(chuàng)建時(shí)申請(qǐng)的堆棧和內(nèi)存會(huì)在系統(tǒng)的空閑任務(wù)中被釋放掉。
任務(wù)調(diào)度 vTaskStartScheduler()
函數(shù)原型(tasks.c中):
void vTaskStartScheduler( void )
不需要參數(shù),開(kāi)啟后就由FreeRTOS開(kāi)始任務(wù)調(diào)度工作。
程序設(shè)計(jì)
主函數(shù)
主函數(shù)還是我們熟悉的main函數(shù),但FreeRTOS里的main函數(shù)不需要自己設(shè)計(jì)成死循環(huán),只需要?jiǎng)?chuàng)建任務(wù)并開(kāi)啟任務(wù)調(diào)度,即可使系統(tǒng)持續(xù)運(yùn)行。
任務(wù)的創(chuàng)建一般都是先創(chuàng)建一個(gè)開(kāi)始任務(wù),然后開(kāi)始任務(wù)再負(fù)責(zé)創(chuàng)建其它子任務(wù)。
int main(void)
{
//設(shè)置系統(tǒng)中斷優(yōu)先級(jí)分組4(FreeRTOS中的默認(rèn)方式!)
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
//初始化LED端口
LED_Init();
//創(chuàng)建開(kāi)始任務(wù)
xTaskCreate((TaskFunction_t )start_task, //任務(wù)函數(shù)
(const char* )"start_task", //任務(wù)名稱(chēng)
(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ù)句柄
//開(kāi)啟任務(wù)調(diào)度
vTaskStartScheduler();
}
開(kāi)始任務(wù)函數(shù)
開(kāi)始任務(wù)函數(shù)的功能就是用來(lái)創(chuàng)建其它的子任務(wù),創(chuàng)建完之后會(huì)把自己刪除掉。
//開(kāi)始任務(wù)任務(wù)函數(shù)
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //進(jìn)入臨界區(qū)
//創(chuàng)建TASK1任務(wù)
xTaskCreate((TaskFunction_t )task1_task,
(const char* )"task1_task",
(uint16_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_TASK_PRIO,
(TaskHandle_t* )&Task1Task_Handler);
//創(chuàng)建TASK2任務(wù)
xTaskCreate((TaskFunction_t )task2_task,
(const char* )"task2_task",
(uint16_t )TASK2_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK2_TASK_PRIO,
(TaskHandle_t* )&Task2Task_Handler);
vTaskDelete(StartTask_Handler); //刪除開(kāi)始任務(wù)
taskEXIT_CRITICAL(); //退出臨界區(qū)
}
兩個(gè)任務(wù)函數(shù)
每個(gè)任務(wù)函數(shù)都是一個(gè)死循環(huán),注意循環(huán)中必須添加vTaskDelay()延時(shí)函數(shù),用于任務(wù)的切換。
//task1任務(wù)函數(shù)
void task1_task(void *pvParameters)
{
while(1)
{
LEDa_Toggle;
vTaskDelay(500); //延時(shí)500ms
}
}
//task2任務(wù)函數(shù)
void task2_task(void *pvParameters)
{
while(1)
{
LEDb_ON;
vTaskDelay(200); //延時(shí)200ms
LEDb_OFF;
vTaskDelay(800); //延時(shí)800ms
}
}
main.c所有程序
#include "stm32f4xx.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
//任務(wù)參數(shù)--------------------------
//優(yōu)先級(jí) 堆棧大小 任務(wù)句柄 任務(wù)函數(shù)
#define START_TASK_PRIO 1
#define START_STK_SIZE 128
TaskHandle_t StartTask_Handler;
void start_task(void *pvParameters);
#define TASK1_TASK_PRIO 2
#define TASK1_STK_SIZE 128
TaskHandle_t Task1Task_Handler;
void task1_task(void *pvParameters);
#define TASK2_TASK_PRIO 3
#define TASK2_STK_SIZE 128
TaskHandle_t Task2Task_Handler;
void task2_task(void *pvParameters);
int main(void)
{
//設(shè)置系統(tǒng)中斷優(yōu)先級(jí)分組4(FreeRTOS中的默認(rèn)方式!)
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
//初始化LED端口
LED_Init();
//創(chuàng)建開(kāi)始任務(wù)
xTaskCreate((TaskFunction_t )start_task, //任務(wù)函數(shù)
(const char* )"start_task", //任務(wù)名稱(chēng)
(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ù)句柄
//開(kāi)啟任務(wù)調(diào)度
vTaskStartScheduler();
}
//開(kāi)始任務(wù)任務(wù)函數(shù)
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //進(jìn)入臨界區(qū)
//創(chuàng)建TASK1任務(wù)
xTaskCreate((TaskFunction_t )task1_task,
(const char* )"task1_task",
(uint16_t )TASK1_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK1_TASK_PRIO,
(TaskHandle_t* )&Task1Task_Handler);
//創(chuàng)建TASK2任務(wù)
xTaskCreate((TaskFunction_t )task2_task,
(const char* )"task2_task",
(uint16_t )TASK2_STK_SIZE,
(void* )NULL,
(UBaseType_t )TASK2_TASK_PRIO,
(TaskHandle_t* )&Task2Task_Handler);
vTaskDelete(StartTask_Handler); //刪除開(kāi)始任務(wù)
taskEXIT_CRITICAL(); //退出臨界區(qū)
}
//task1任務(wù)函數(shù)
void task1_task(void *pvParameters)
{
while(1)
{
LEDa_Toggle;
vTaskDelay(500); //延時(shí)500ms
}
}
//task2任務(wù)函數(shù)
void task2_task(void *pvParameters)
{
while(1)
{
LEDb_ON;
vTaskDelay(200); //延時(shí)200ms
LEDb_OFF;
vTaskDelay(800); //延時(shí)800ms
}
}
運(yùn)行結(jié)果
運(yùn)行效果是板子上的兩個(gè)LED按照各自任務(wù)函數(shù)中設(shè)定的亮滅時(shí)間不斷閃爍。
使用系統(tǒng)的原因就是可以讓兩個(gè)任務(wù)看起來(lái)像是同時(shí)運(yùn)行,試想,如果是裸機(jī)系統(tǒng),雖然也可以實(shí)現(xiàn)同樣功能(這兩個(gè)LED任務(wù)的閃爍規(guī)律比較簡(jiǎn)單),但需要將兩個(gè)任務(wù)結(jié)合起來(lái)管理亮滅時(shí)間,兩個(gè)任務(wù)就糾纏在一起了,如果是兩個(gè)更復(fù)雜的任務(wù),裸機(jī)系統(tǒng)可能就無(wú)法實(shí)現(xiàn)了。
審核編輯:湯梓紅
-
FreeRTOS
+關(guān)注
關(guān)注
12文章
484瀏覽量
62271 -
實(shí)時(shí)操作系統(tǒng)
+關(guān)注
關(guān)注
1文章
199瀏覽量
30786
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論