Try   HackMD

🛠️ 【韌體】STM32CubeIDE 🛠️

C/C++ 混編專案架構

STM32 HAL 固件庫是基於 C 語言開發的,
為了使用 C++ 中許多更高級或方便的功能(class、overload),
以及像是使用 rosserial 通訊庫這種基於 cpp 開發的庫,
就誕生 C/C++ 混編的需求了。

我們知道 C++ 是向下兼容 C 語言的,
其中涉及蠻多 C/C++ 的編譯知識,留給讀者自行查詢。

STM32CubeIDE 有很多混編架構的解法,
我會放上我目前認為最優雅的架構,
完整版可參考我的 Github



1. 初步理解

初期建立專案時記得選 C++。

image


架構圖(不用看箭頭們):

Image Not Showing Possible Reasons
  • The image was uploaded to a note which you don't have access to
  • The note which the image was originally uploaded to has been deleted
Learn More →

  • 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 資料夾間是有依賴關係的。
所以也算不上真正地解藕,可以依照個人喜好彈性調整。



2. 專案架構 - 程式進入點 mainpp.h/.cpp

接下來的部分,因為實際步驟繁瑣,且涉及的原理知識其實不少。
我會建議先照著做,之後再去好好理解這幾個東西。
關鍵字:Header File、Header Guard、extern "C"、class、constructor。

為了避免炸版,請搭配 Github 看哦

mainpp.cpp 以及 mainpp.h 是混編的核心,
是 C 和 C++ 共同編譯的橋梁。

  1. main.c 只改兩個地方:
    • #include "mainpp.h":引入 mainpp 的標頭檔。
    • main_function();:這是個 while(1) 的死迴圈,目的是阻斷原本 main.cwhile(1),我們希望死迴圈是運作在 C++ 的環境裡。

之後,我們就不會在 main.c 中做任何事情,全部都拉出來實作。

  1. mainpp.h:全部照抄即可,extern "C" 原理自己查囉。

  2. mainpp.cpp:可照抄可自改,只要架構對就沒問題。

    mainpp.cpp 架構
    //// 這裡 include 自己的 library //// ​#include <dc_motor.h> ​#include <mainpp.h> ​#include <manual.h> ​#include <ros1.h>void main_function(void){//// 一次性初始化 ////DC_MOTOR::init();ROS1::init();//// while(1) 放要一直執行的邏輯 ////while(1){//// 這裡如果 MANUAL::MODE 是 true,就會在 MANUAL::loop()中無限迴圈 //////// 否則就會每次都執行一次 ROS1::spinCycle() ////if(MANUAL::MODE) MANUAL::loop();else ROS1::spinCycle();}//// 不會跑到 return ////return;}

至此,我會建議 mainpp.cpp 先註解掉 #includewhile(1) 內部邏輯。
並嘗試編譯,成功後再慢慢加入自定義 library。



3. 專案架構 - 自定義 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。

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

  • step 2. 對 Manual 資料夾右鍵,新增「Source File」。
    取名 manual.cpp,記得無論名字為何都要有檔名 .cpp。
    跳出來的檔案中應該會有類似這樣的註解。

    /* ​ * manual.cpp ​ * ​ * Created on: Aug 6, 2024 ​ * Author: User ​ */
  • step 3. 對 Manual 資料夾右鍵,新增「Header File」。
    一樣取名 manual.h,檔案會有自動生成的 Header Guard。

    /* ​ * manual.h ​ * ​ * Created on: Aug 5, 2024 ​ * Author: User ​ */ ​#ifndef INC_MANUAL_HPP_ ​#define INC_MANUAL_HPP_ ​ ​//// 新增代碼都要在這裡面 //// ​#endif /* INC_MANUAL_HPP_ */
  • step 4. 直接複製貼上 Github 上對應代碼。

  • step 5. 設定專案的路徑設定。
    注意上面 Configuration 中的 Debug 和 Release 要分別新增。

    Image Not Showing Possible Reasons
    • The image was uploaded to a note which you don't have access to
    • The note which the image was originally uploaded to has been deleted
    Learn More →

  • step 6. 這樣就可以了,其實很簡單。