STM32 HAL 固件庫是基於 C 語言開發的,
為了使用 C++ 中許多更高級或方便的功能(class、overload…),
以及像是使用 rosserial 通訊庫這種基於 cpp 開發的庫,
就誕生 C/C++ 混編的需求了。
我們知道 C++ 是向下兼容 C 語言的,
其中涉及蠻多 C/C++ 的編譯知識,留給讀者自行查詢。
STM32CubeIDE 有很多混編架構的解法,
我會放上我目前認為最優雅的架構,
完整版可參考我的 Github。
架構圖(不用看箭頭們):
Core/
、Manual/
、Motor/
…:
這些是同層級的資料夾們,其中只有 Core/
是建立專案時即生成的。
Core/
:
底下的 main.c
是 STM 的程式進入點。
之後會新增 mainpp.cpp
,接入 C++。
Interrupt/
:
HAL 庫中原本用 C 語言寫的中斷函式,也可被拉到 .cpp
中實作。
Manual/
、Chassis/
、Motor/
…:
這些是自定義,並以功能區分的 C++ lib。
他們可以引用 HAL 固件庫,他們之間可以有依賴關係。
他們也可以被 Core/mainpp.cpp
引入。
這個架構最大好處,除了可以混編 C/C++,
是每個功能都被解藕成獨立的資料夾,要新增功能或移植代碼都非常方便。
不過在這個專案中,C++ lib 資料夾間是有依賴關係的。
所以也算不上真正地解藕,可以依照個人喜好彈性調整。
接下來的部分,因為實際步驟繁瑣,且涉及的原理知識其實不少。
我會建議先照著做,之後再去好好理解這幾個東西。
關鍵字:Header File、Header Guard、extern "C"、class、constructor。
為了避免炸版,請搭配 Github 看哦
mainpp.cpp
以及 mainpp.h
是混編的核心,
是 C 和 C++ 共同編譯的橋梁。
main.c
只改兩個地方:
#include "mainpp.h"
:引入 mainpp 的標頭檔。main_function();
:這是個 while(1)
的死迴圈,目的是阻斷原本 main.c
的 while(1)
,我們希望死迴圈是運作在 C++ 的環境裡。之後,我們就不會在 main.c 中做任何事情,全部都拉出來實作。
mainpp.h
:全部照抄即可,extern "C"
原理自己查囉。
mainpp.cpp
:可照抄可自改,只要架構對就沒問題。
至此,我會建議 mainpp.cpp 先註解掉 #include
和 while(1)
內部邏輯。
並嘗試編譯,成功後再慢慢加入自定義 library。
因為接下來的 library,像是 Chassis、Motor、Manual 等,
都有依賴關係,就是 A #include B,B #include C 之類的。
我會建議先按照下方步驟複製貼上全部的,懂了再自己改就好。
注意和 ROS1 相關的先全部省略,
包含 mainpp.cpp 的 ROS1 函式庫以及 ROS1 資料夾,
因為那必須多安裝 rosserial 庫才能正確編譯,
只有其他部分還是能正常編譯的。
這裡我先示範如何新增 Manual 的 Library,其他資料夾完全同理。
step 1. 在專案根目錄中,新增「Source Folder」。
輸入 Manual 後 Enter。
step 2. 對 Manual 資料夾右鍵,新增「Source File」。
取名 manual.cpp,記得無論名字為何都要有檔名 .cpp。
跳出來的檔案中應該會有類似這樣的註解。
step 3. 對 Manual 資料夾右鍵,新增「Header File」。
一樣取名 manual.h,檔案會有自動生成的 Header Guard。
step 4. 直接複製貼上 Github 上對應代碼。
step 5. 設定專案的路徑設定。
注意上面 Configuration 中的 Debug 和 Release 要分別新增。
step 6. 這樣就可以了,其實很簡單。