Wiki
Linux
本文由簡體中文內容確定性轉換,並受版本化術語表保護。
1.環境介紹
本教程環境介紹:
-
系統:Fedora 42 KDE Edition Linux
-
系統核心:Linux 6.15.6-200.fc42.x86_64
-
架構:X86_64
其他Linux環境也可以。
2.安裝各種環境
2.1.安裝C/C++環境
# debian系
sudo apt-get install gcc g++ gdb cmake-gui make
# rhel系
sudo dnf install gcc g++ gdb cmake-gui make

檢視是否環境安裝成功
gcc -v
g++ -v
gdb -v
cmake --version




接下來測試是否能夠對C/C++正常編譯,請找一個存放C++程式碼的資料夾,然後在終端中cd進去。

然後建立一個.cpp檔案並用vim編輯
vim hello.cpp
複製以下程式碼到該檔案裡
#include <iostream>
int main(int argc,char **argv)
{
std::cout << "你好,机电创新学会!" << std::endl;
return 0;
}
然後編譯
g++ -o hello hello.cpp
ls

執行
./hello

說明環境已經配置好了
2.2.安裝CubeMX

下載地址:
https://www.st.com.cn/zh/development-tools/stm32cubemx.html
推薦下載6.14.1版本(不要下載6.15.0,這個版本有bug,不知道後續何時會修復)


解壓出來

用root許可權開啟這個軟體SetupSTM32CubeMX-6.15.0
sudo ./SetupSTM32CubeMX-6.15.0

在新彈出的介面一直點下一步就行,安裝結束後出現如下圖就成功了。

/usr/local/STMicroelectronics/STM32Cube/STM32CubeMX進入這個資料夾,然後開啟終端輸入
./STM32CubeMX

點選Help

選Manage embedded software packages,把STM32F1,F4,H7的第一個最新的韌體勾上。

點install

登陸上賬號

然後等下載和安裝完

下載好就行了。
接下來可以把CubeMX應用配置一個桌面快捷方式等可以快速開啟,教程詳見Vinci機器人隊Linux入門教程的Appimage章節,可以用ctrl+F快速定位該章節。
桌面快捷方式如下:
[Desktop Entry]
Name=STM32CubeMX
Exec=/usr/local/STMicroelectronics/STM32Cube/STM32CubeMX/STM32CubeMX
Icon=/usr/local/STMicroelectronics/STM32Cube/STM32CubeMX/help/STM32CubeMX.png
Type=Application
Categories=Development;Electronics;Embedded;
Comment=STM32CubeMX configuration and code generation tool
Terminal=false
根據教程做,就可以實現這種效果啦。


2.3.安裝VScode
https://code.visualstudio.com/Download

如果是debian系下載deb,如果是rhel系下載rpm.
下載完之後,點選瀏覽器,找到這個安裝包的資料夾,並在該路徑開啟終端。

Debian系:輸入sudo apt install ./code然後按tab按鍵補齊檔名,回車。
RHEL系:輸入sudo dnf install ./code然後按tab按鍵補齊檔名,回車。
例如補齊後的:
sudo dnf install ./code-1.102.1-1752598767.el8.x86_64.rpm

然後開啟VScode,在終端輸入下面的命令
code

然後安裝一些外掛

下面這些都要裝




2.4.安裝ARM GNU工具鏈
編譯工具比較:
| 特性 | ARM GCC (GNU 工具鏈) | Keil AC5 (ARM Compiler 5) | Keil AC6 (ARM Compiler 6) |
|---|---|---|---|
| 核心身份 | 基於GNU GPL的開源編譯器 | ARM自家的傳統編譯器 | 基於LLVM/Clang的現代編譯器 |
| 許可模式 | 免費、開源 | 商業收費(包含在MDK中) | 商業收費(包含在MDK中) |
| 程式碼生成/最佳化 | 良好,持續改進 | 優秀(尤其在小程式碼尺寸上) | 極佳,在效能與尺寸間有最佳平衡 |
| 標準相容性 | 緊跟最新C/C++標準(如C17,C++17/20) | 主要支援C++98,較陳舊 | 支援現代C++(C++11/14/17),相容性更好 |
| 錯誤/警告資訊 | 比較清晰易懂 | 相對晦澀 | 非常清晰和友好,類似GCC/Clang |
| 與Keil MDK整合 | 需要手動配置或通過CubeIDE | 原生、無縫整合 | 原生、無縫整合,是ARM推薦選擇 |
| 連結指令碼 | 使用自有的連結指令碼語法(.ld檔案) | 使用ARM自家的分散載入檔案語法(.sct) | 使用ARM自家的分散載入檔案語法(.sct) |
| 彙編語法 | 使用GNU彙編語法(.S檔案) | 使用ARM彙編語法(.s) | 使用ARM彙編語法(.s),但AC6更嚴格 |
| 生態與未來 | 生態強大,是很多開源專案(如Zephyr,ESP-IDF)和IDE(CubeIDE,VS Code)的首選 | 處於維護模式,ARM不再增加新功能,不推薦新專案使用 | 是ARM的未來和主力,持續更新和最佳化 |
2.4.1.安裝
建議都用官方法進行安裝。
2.4.1.1.方法一(官網法)
https://developer.arm.com/downloads/-/arm-gnu-toolchain-downloads

進入下載目錄並開啟終端

在終端裡輸入下列命令,將編譯器檔案tar壓縮包複製到你存放程式的資料夾(這個資料夾你自己定,建議在home分割槽,別以後刪了就行)。
具體命令為cp ./arm-gnu然後按tab補齊,然後空格,再跟上你要複製到的資料夾的路徑。
比如下面的命令:
cp ./arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi.tar.xz ~/UserFolder/Applications/
然後進入複製到的資料夾:
cd ~/UserFolder/Applications/

在終端裡輸入tar -xvf ./arm-gnu並按tab補齊。
例如我補齊後的:
tar -xvf ./arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi.tar.xz

再進入這個解壓後的資料夾
cd ./arm-gnu按tab補齊。
cd ./arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/
cd ./bin
檢視資料夾路徑
pwd

複製一下/home/tungchiahui/UserFolder/Applications/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/bin
然後需要配置環境
vim ~/.bashrc
在末尾輸入下面的命令,把下面~/UserFolder/Applications/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/bin替換成你剛才複製的路徑,/home/用户名可以用~來代替。
export PATH=/home/tungchiahui/UserFolder/Applications/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/bin:$PATH

載入環境
source ~/.bashrc
2.4.1.2.方法二(系統倉庫法)
不建議本法
# Debian系
sudo apt install arm-none-eabi-gcc
# Rhel系
sudo dnf install arm-none-eabi-gcc

2.4.2.測試
檢查版本
arm-none-eabi-gcc -v

2.5.安裝JLink驅動
2.5.1.安裝libreadline庫
我們燒錄會用到JLinkExe的命令,而JLinkExe會用到libreadline庫,所以要安裝libreadline庫,執行如下命令安裝:
# debian系
sudo apt-get install libreadline-dev
# rhel系
sudo dnf install readline-devel

2.5.2.安裝JLink驅動
https://www.segger.com/downloads/jlink/

是Debian系下載64位DEB
是RHEL系下載64位RPM
(這裡的64位指的是amd64和X86_64,如果你是ARM64請下載下方那個Linux ARM裡的64位)

開啟下載到的資料夾,並開啟終端

然後sudo apt install ./JLink然後tab補齊。
然後sudo dnf install ./JLink然後tab補齊。
sudo dnf install ./JLink_Linux_V852_x86_64.rpm

檢查是否安裝成功
JLinkExe

我們點選No,然後會進入Commander互動模式,在這種模式下,我們可以執行各種 J-Link Commander 提供的命令來連線、配置偵錯程式,下載程式或檔案到目標裝置等操作,感興趣的同學可自行學習。
執行“q”指令退出該模式。

2.5.3.下載並安裝Ozone
https://www.segger.com/products/development-tools/ozone-j-link-debugger/


是Debian系下載64位DEB
是RHEL系下載64位RPM
(這裡的64位指的是amd64和X86_64,如果你是ARM64請下載下方那個Linux ARM裡的64位)

然後sudo apt install ./Ozone然後tab補齊。
然後sudo dnf install ./Ozone然後tab補齊。
sudo dnf install ./Ozone_Linux_V338g_x86_64.rpm

2.5.4.測試
開啟終端輸入
ozone

2.6.下載SVD
https://www.st.com.cn/content/st_com/zh.html
在搜尋裡搜尋晶片型號,如stm32f103c8t6

點CAD資源

下載SVD,滑鼠點紅色框的區域就可以下載了

解壓後就可以獲得F1系列的SVD檔案了

依次把F4和H7的也下載解壓了就可以了。(可以解壓到一個資料夾裡)

然後在上面的資料夾開啟終端
將這些資料夾全部複製到Ozone的Config/Peripherals/目錄下。(你需要提前確定一下ozone的配置是否是這個路徑再複製)

sudo cp ./*.svd /opt/SEGGER/Ozone_V338g/Config/Peripherals/


3.工程建立與測試
3.1.使用CubeMX建立工程
點選進入微控制器挑選的按鈕

搜尋對應晶片,並雙擊對應晶片選項。

進行一些配置,以下都是很基礎的東西,你在看這個影片前肯定都會了


隨便開一個IO用來測試,比如LED的GPIO


FreeRTOS也要配置一下。


這些資料夾也要配置好,最後Toolchain選擇CMake,編譯器選擇GCC(6.14.1及之前沒有選擇編譯器這個選項很正常)
(但是CubeMX6.15.0有bug,這個選擇GCC編譯器並沒有用,還需要後續自己手動選擇編譯器,以後可能會修復這個bug.)


3.2.對工程進行配置與編譯
在工程資料夾開啟終端

然後開啟vscode
code .

進入vscode後,點選目錄下的CMakeLists.txt

檢查第25行左右是否有下面這行,如果沒有,你需要手動給他加上這兩行。(6.14.1版本沒有這個bug)
tips1:這就是上面說的CubeMX6.15.0版本的bug,因為這個版本增加了對clang編譯器的支援,在CubeMX裡也支援了選擇編譯器的操作,但是這個選項估計是工程師沒寫好,選擇編譯器不管選哪個,他都不會選擇咱們選擇的編譯器,所以咱們需要手動選擇。
tips2:這CubeMX6.15.0有第二個bug,這個工作區根CMakeLists.txt他說了只會生成一次,後續不會再重新覆蓋生成,但是發現每次在CubeMX修改配置後,然後重新生成程式碼,其他命令都被保留了,就這個命令不會被保留。不知道後續會不會被修復,或者直接修復上面tips1的bug.所以每次重新配置CubeMX後,需要再把這句加上。

# Include toolchain file
include("cmake/gcc-arm-none-eabi.cmake")
按ctrl+~開啟內建終端。

使用下方命令建立並進入build資料夾
mkdir build
cd build

接下來使用cmake命令生成makefile檔案
cmake ..
檢查一下是否ARM的C/C++以及彙編編譯器都被找到了(如果沒有,請檢查上面的教程是否有做錯的地方)

然後使用make命令進行編譯,命令為make或者make -jxx,這裡的xx是你想使用CPU的幾個執行緒來進行編譯,比如我電腦是8核16執行緒,我就可以讓xx是比16低的數字。而make是預設用一個執行緒。如果你並不知道你CPU有幾個執行緒,那你就老老實實用make命令,別用make -jxx命令了。
make -j16
這樣就是編譯成功了。

3.3.對程式碼提示進行配置
在VScode中按Ctrl+Shift+P,搜尋clangd,並選擇下載語言服務

在右下角選擇安裝即可,安裝完就會出現下圖提示。

接著停用C/C++外掛的程式碼提示功能(如果沒這個介面,請往下看)

如果沒有上圖的彈窗,可以進行手動關閉,依然是ctrl shift P,輸入settings然後找到如下圖的選項

找到下圖這個選項,改成disabled即可。
"C_Cpp.intelliSenseEngine": "disabled"

在VScode中再按Ctrl+Shift+P,搜尋clangd,並選擇重啟clangd語言服務(重啟clangd語言服務之前必須編譯過一遍程式碼了)

此時,可以看程式碼裡標頭檔案都正常識別了,程式碼提示也正常了。



⚠️注意:Clangd 預設找的是 本機系統的 libc/include 路徑(比如 x86_64 的 /usr/include) ,而我們工程裡面實際使用的是 ARM 工具鏈的標頭檔案路徑 ,這就有機率導致包含C/C++庫函式的標頭檔案報錯
例如:

這裡的 #include <math.h>顯示找不到標頭檔案,但是我們進行編譯的時候卻沒有報錯,說明是clangd的配置有問題 。以下介紹一種解決方法:
- 執行以下命令,獲取 ARM GCC 使用的標準 include 路徑:
arm-none-eabi-gcc -x c -E -v - </dev/null

- 在工程根目錄下面建立 .clangd 檔案 將自己的標頭檔案路徑包含進去(引號裡面替換成你自己的arm gcc標頭檔案路徑)
CompileFlags:
Add: [
"-isystem", "/home/xiaofang/Applications/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/lib/gcc/arm-none-eabi/14.3.1/include",
"-isystem", "/home/xiaofang/Applications/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/lib/gcc/arm-none-eabi/14.3.1/include-fixed",
"-isystem", "/home/xiaofang/Applications/arm-gnu-toolchain-14.3.rel1-x86_64-arm-none-eabi/arm-none-eabi/include"
]
儲存,此時重新整理一下clangd,標頭檔案提示正常

3.4.移植Vinci機器人隊標準C/C++工程模板
用git clone命令克隆倉庫:https://github.com/tungchiahui/CubeMX_MDK5to6_Template
git clone https://github.com/tungchiahui/CubeMX_MDK5to6_Template.git
把倉庫裡的“工程檔案移植”資料夾裡的 所有內容 複製到我們CMake工程的目錄裡。

然後開啟applications資料夾,在Src和Inc資料夾分別建立led_task.cpp和led_task.h,內容分別如下:

led_task.cpp:
#include "led_task.h"
#include "cmsis_os.h"
#include "stm32f1xx_hal.h"
GPIO_PinState pinstate = GPIO_PIN_RESET;
extern "C"
void StartDefaultTask(void *argument)
{
for(;;)
{
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,pinstate);
pinstate = (pinstate == GPIO_PIN_RESET) ? GPIO_PIN_SET : GPIO_PIN_RESET;
osDelay(500);
}
}
led_task.h:
#ifndef __LED_TASK_H_
#define __LED_TASK_H_
#ifdef __cplusplus
extern "C"
{
#endif
#include "cpp_interface.h"
#ifdef __cplusplus
}
#endif
#endif
然後開啟cmake/user資料夾下的CMakeLists.txt,把剛才新建的led_task.cpp新增上去。
詳細介紹(可以不看):這裡的cmake/stm32cubemx下的CMakeLists.txt是被CubeMX管理的,你重新用CubeMX生成新程式碼後,這個檔案裡的東西會被覆蓋。而工作區根目錄下的CMakeLists.txt是不會被重新覆蓋的,而且給我們留了一些區域加原始檔和標頭檔案,但是這樣會讓這個檔案太過於嘈雜。所以我們選擇新建一個user資料夾,然後在這裡面弄一個CMakeLists.txt,再用頂層CMakeLists.txt去載入這個子CMakeLists.txt,這個子CMakeLists.txt方便咱們修改,檔案結構也更加明顯。(這些都不需要咱們自己建立,我已經給建立到 工程檔案移植 裡了,你在上面複製的時候已經複製過來了)

然後要去最頂層的CMakeLists.txt里加上這句話來引用我們自己的CMakeLists.txt。

# Add USER generated sources
add_subdirectory(cmake/user)
大功告成,編譯一次試試。可以看到下圖,那些新加的檔案都編譯上了。
cmake ..
make

然後去main.c中引用cpp_interface.h標頭檔案,並將cpp_main()函式在main函式的這個地方呼叫。(我這裡是開RTOS了,所以需要在啟動RTOS之前呼叫cpp_main函式,如果你是沒有用RTOS的裸機程式,則在while (1)的上方呼叫cpp_main即可)


然後在cpp_interface.h裡修改isRTOS這個宏來讓程式知道你是否開啟了RTOS,如果開啟了,宏就為1,裸機就填0。


其他更加詳細的關於STM32的C/C++工程介紹請看Vinci機器人隊微控制器教程。
此時在build資料夾下進行編譯程式,發現成功!
cmake ..
make

3.5.下載程式到板子
3.5.1.配置CMake生成.bin和.hex檔案
在下載程式到板子之前,我們需要去看看咱們之前編譯的到底生成了啥檔案。
通過下圖可知,他只生成了.elf檔案,並沒有咱們常見的.bin和.hex檔案。

咱們需要再更改一下工作區下的CMakeLists.txt從而來讓編譯的時候生成.hex和.bin(沒辦法,就得這麼麻煩,我也不知道為啥CubeMX不給全乾好)

# 生成 .bin 和 .hex 文件
find_program(OBJCOPY arm-none-eabi-objcopy REQUIRED)
add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD
COMMAND ${OBJCOPY} -O binary ${CMAKE_PROJECT_NAME}.elf ${CMAKE_PROJECT_NAME}.bin
COMMAND ${OBJCOPY} -O ihex ${CMAKE_PROJECT_NAME}.elf ${CMAKE_PROJECT_NAME}.hex
COMMENT "Generating ${CMAKE_PROJECT_NAME}.bin and ${CMAKE_PROJECT_NAME}.hex from ${CMAKE_PROJECT_NAME}.elf"
)
這些需要在工作區主CMakeLists.txt裡新增的命令我全都寫在這個記事本里了,每次生成新工程直接複製即可。


然後再次編譯
cmake ..
make

此時再看build目錄:咱們需要的.hex或者.bin就出來了

3.5.2.將裝置連線到JLink並燒錄程式
3.5.2.1.圖形介面燒錄
#打开终端输入
JFlashLite
選擇對應的晶片型號和速度

新增hex檔案


點選燒錄並完成:

成功點亮led:

3.5.2.2.終端燒錄
算鳥算鳥,太麻煩了。
3.6.配置VScode任務
咱們在上面編譯,一直需要輸入以下命令
cd build
cmake ..
make
這樣每次編譯過於麻煩了,所以我們使用強大的VScode來一鍵編譯。
首先建立.vscode資料夾和tasks.json檔案

以下是tasks.json的內容:
{
"version": "2.0.0",
"options": {
"cwd": "${workspaceFolder}/build" //需要进入到我们执行tasks任务的文件夹中
},
"tasks": [ //tasks包含4个任务
{
"type": "shell",
"label": "stm32-cmake", //第一个任务的名字叫cmake
"command": "bash",
"args": [
"-c",
"mkdir -p ../log && echo \"===== CMake started at: $(date) =====\" | tee -a ../log/cmake.log && cmake .. 2>&1 | tee -a ../log/cmake.log"
],
"problemMatcher": [] //这里需要添加一个空的问题匹配器,否则会报错
},
{
"label": "stm32-make", //第二个任务的名字叫make
"command": "bash",
"args": [
"-c",
"mkdir -p ../log && echo \"===== Make started at: $(date) =====\" | tee -a ../log/make.log && make -j$(grep -c ^processor /proc/cpuinfo) 2>&1 | tee -a ../log/make.log"
],
"problemMatcher": [] //这里也需要添加一个空的问题匹配器,否则会报错
},
{
"label": "stm32-Build", //第3个任务的名字叫Build
"group": { //默认是build任务
"kind": "build",
"isDefault": true
},
"dependsOrder": "sequence", //顺序执行依赖项
"dependsOn":[ //依赖的2个项为cmake、make
"stm32-cmake", //即第一个任务的label
"stm32-make" //即第二个任务的label
]
},
{
"type": "shell",
"label": "stm32-clean", //第四个任务:清理 build 文件夹
"command": "bash",
"args": [
"-c",
"echo \"===== Clean started at: $(date) =====\" && rm -rf * && echo \"Build folder cleaned.\""
],
"options": {
"cwd": "${workspaceFolder}/build" //只清理build目录下的文件
},
"problemMatcher": [] //不需要问题匹配器
}
]
}
方法一:
在VScode標題欄上,找到终端,然後再選擇运行构建任务,快捷鍵是Ctrl+Shift+B。

可見任務已經被運行了。

方法二:
在VScode標題欄上,找到终端,然後再選擇运行任务。

下面有4個stm32的任務,第一個是stm32-Build任務,執行後的效果和剛才方法一是一樣的,方法一的那個运行构建任务的按鈕,就是執行的這個stm32-Build任務。
這個stm32-Build任務包含stm32-cmake和stm32-make任務。
然後stm32-clean任務就是清除build資料夾下的所有檔案。

可以試一下stm32-clean任務。

可以發現都刪完了。

你不用擔心每次新建工程都需要配置那麼多東西。
以上大多數配置檔案全部都已經包含在https://github.com/tungchiahui/CubeMX_MDK5to6_Template仓库下的***`工程文件移植(建立新模板請看這裡)`***資料夾了,到時候新建一個工程後,直接把這個資料夾下的所有檔案全部複製過來即可。
3.7.使用ozone進行Flash燒錄和Debug除錯
3.7.1.基礎配置
開啟終端輸入ozone開啟軟體或者直接找到應用圖示開啟ozone


先選擇device,比如我是STM32F407VET6


選擇Peripherals:

點選下一步

你用的SWD就填SWD,是JTAG就填JTAG

選擇ELF

elf,hex,bin都可以選,一般選elf就行。

這一步保持預設即可。

如果你開啟了RTOS可能會遇到這個問題。
warning (138): The target application seems to be using FreeRTOS, but FreeRTOS-awareness is not enabled.
意思是你的目標應用似乎使用了 FreeRTOS,但當前沒有啟用對 FreeRTOS 的除錯支援(RTOS-awareness)。

直接按照他底下的提示應用修復即可。

點繼續就行。


3.7.2.燒錄與除錯
可以看下面這個影片,講的挺好的。(從30:10開始看)
https://www.bilibili.com/video/BV1yrLHzZEoE

點選File讓他按檔名排序。

找到led_task.cpp點選就可以開啟這個原始檔啦。
