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