- FreeRTOS內核實現與應用開發實戰指南:基于STM32
- 劉火良 楊森
- 1977字
- 2019-04-15 17:51:24
第1章 初識FreeRTOS
1.1 FreeRTOS版權
FreeRTOS由美國的Richard Barry于2003年發布,Richard Barry是FreeRTOS的擁有者和維護者,在過去的十多年中FreeRTOS歷經了9個版本,與眾多半導體廠商合作密切,有數百萬開發者,是目前市場占有率最高的RTOS。
FreeRTOS于2018年被亞馬遜收購,改名為AWS FreeRTOS,版本號升級為V10,且開源協議也由原來的GPLv2+修改為MIT,與GPLv2+相比,MIT更加開放,你完全可以理解為完全免費。V9以前的版本還是維持原樣,V10版本相比于V9就是加入了一些物聯網相關的組件,內核基本不變。亞馬遜收購FreeRTOS也是為了進軍物聯網和人工智能領域。本書還是以V9版本來講解。
1.2 FreeRTOS收費問題
1.2.1 FreeRTOS
FreeRTOS是一款“開源免費”的實時操作系統,遵循的是GPLv2+的許可協議。這里說到的開源,指的是可以免費獲取FreeRTOS的源代碼,且當你的產品使用了FreeRTOS而沒有修改FreeRTOS內核源碼時,你的產品的全部代碼都可以閉源,不用開源,但是當你修改了FreeRTOS內核源碼時,就必須將修改的這部分開源,反饋給社區,其他應用部分不用開源。免費的意思是無論你是個人還是公司,都可以免費地使用,不需要花費一分錢。
1.2.2 OpenRTOS
FreeRTOS和OpenRTOS擁有的代碼是一樣的,但是可從官方獲取的服務卻是不一樣的。FreeRTOS號稱免費,OpenRTOS號稱收費,它們的具體區別如表1-1所示。
表1-1 FreeRTOS開源授權與OpenRTOS商業授權的區別

1.2.3 SaveRTOS
SaveRTOS也基于FreeRTOS,但是SaveRTOS為某些特定的領域做了安全相關的設計,有關SaveRTOS獲得的安全驗證具體如表1-2所示。SaveRTOS需要收費。
表1-2 SaveRTOS獲得的安全方面的驗證

1.3 FreeRTOS資料獲取
FreeRTOS的源碼和相應的官方書籍均可從官網www.freertos.org獲得,如圖1-1所示為官網首頁。
1.3.1 獲取源碼
單擊圖1-1中的Download Source按鈕,可以下載FreeRTOS最新版本的源碼。如果想下載以往版本,可從托管網址https://sourceforge.net/projects/freertos/files/FreeRTOS/下載。截至本章編寫時,FreeRTOS已經更新到V10.0.1,具體如圖1-2所示。

圖1-1 FreeRTOS官網首頁

圖1-2 FreeRTOS版本更新目錄
1.3.2 獲取書籍
單擊圖1-1中的PDF Books按鈕可以下載FreeRTOS官方的兩本電子書(英文版),分別為FreeRTOS V10.0.0 Reference Manual.pdf和Mastering_the_FreeRTOS_Real_Time_Kernel-A_Hands-On_Tutorial_Guide.pdf,一本是API參考手冊,另外一本是手把手入門教程。
1.3.3 快速入門
單擊圖1-1中的Quick Start按鈕,可獲取網頁版的快速入門教程。
1.4 FreeRTOS的編程風格
學習一個RTOS,弄清楚它的編程風格很重要,這可以大大提高我們閱讀代碼的效率。下面我們就從FreeRTOS中的數據類型、變量名、函數名、宏以及格式這幾個方面做簡單介紹。
1.4.1 數據類型
在FreeRTOS中,使用的數據類型雖然都是標準C里面的數據類型,但是針對不同的處理器,對標準C的數據類型又進行了重定義,給它們設置了一個新的名字,比如為char重新定義了一個名字portCHAR,這里的port表示接口,在將FreeRTOS移植到處理器上時,需要用這些接口文件把它們連接在一起。但是用戶在寫程序時并非一定要遵循FreeRTOS的風格,仍可以直接用C語言的標準類型。在FreeRTOS中,int型從不使用,只使用short型和long型。在Cortex-M內核的MCU中,short為16位,long為32位。
FreeRTOS中詳細的數據類型重定義在portmacro.h頭文件中實現,具體參見表1-3和代碼清單1-1。
表1-3 FreeRTOS中的數據類型重定義

代碼清單1-1 FreeRTOS中的數據類型重定義
1 #define portCHAR char 2 #define portFLOAT float 3 #define portDOUBLE double 4 #define portLONG long 5 #define portSHORT short 6 #define portSTACK_TYPE uint32_t 7 #define portBASE_TYPE long 8 9 typedef portSTACK_TYPE StackType_t; 10 typedef long BaseType_t; 11 typedef unsigned long UBaseType_t; 12 13 #if( config USE_16_BIT_TICKS == 1 ) 14 typedef uint16_t TickType_t; 15 #define portMAX_DELAY ( TickType_t ) 0xffff 16 #else 17 typedef uint32_t TickType_t; 18 #define portMAX_DELAY ( TickType_t ) 0xffffffffUL
在編程時,如果用戶沒有明確指定char的符號類型,那么編譯器會默認指定char型的變量為無符號或者有符號。正是基于這個原因,在FreeRTOS中,我們都需要明確指定變量char是有符號的還是無符號的。在KEIL中,默認char是無符號的,但是也可以配置為有符號的,具體配套過程如圖1-3所示。

圖1-3 char型變量的符號配置(KEIL)
1.4.2 變量名
在FreeRTOS中,定義變量時往往會把變量的類型當作前綴加在變量上,這樣做的好處是讓用戶一看到這個變量就知道該變量的類型。比如char型變量的前綴是c,short型變量的前綴是s,long型變量的前綴是l,portBASE_TYPE類型變量的前綴是x。還有其他的數據類型,比如數據結構、任務句柄、隊列句柄等定義的變量名的前綴也是x。
如果一個變量是無符號型的,那么會有一個前綴u,如果是一個指針變量,則會有一個前綴p。因此,當我們定義一個無符號的char型變量時會加一個uc前綴,當定義一個char型的指針變量時會加一個pc前綴。
1.4.3 函數名
函數名包含了函數返回值的類型、函數所在的文件名和函數的功能,如果是私有的函數,則會加一個prv(private)的前綴。特別地,在函數名中加入了函數所在的文件名,這將幫助用戶提高尋找函數定義的效率并了解函數作用,具體舉例如下:
1)vTaskPrioritySet()函數的返回值為void型,在task.c文件中定義。
2)xQueueReceive()函數的返回值為portBASE_TYPE型,在queue.c文件中定義。
3)vSemaphoreCreateBinary()函數的返回值為void型,在semphr.h文件中定義。
1.4.4 宏
宏均由大寫字母表示,并配有小寫字母的前綴,前綴用于表示該宏在哪個頭文件定義,部分舉例具體如表1-4所示。
表1-4 FreeRTOS宏定義舉例

這里要注意的是信號量的函數都是一個宏定義,但是其函數的命名方法是遵循函數的命名方法而不是宏定義的方法。
在貫穿FreeRTOS的整個代碼中,還有幾個通用的宏定義也要注意一下,都是表示0和1的宏,具體如表1-5所示。
表1-5 FreeRTOS通用宏定義

1.4.5 格式
1個Tab鍵等于4個空格鍵。我們在編程時最好使用空格鍵而不是使用Tab鍵,當2個編譯器的Tab鍵大小設置得不一樣時,移植代碼時格式就會變亂,而使用空格鍵不會出現這種問題。