Linux
環境介紹
本教程環境介紹:
- 系統:Fedora 42 KDE Edition Linux
- 系統內核:Linux 6.15.6-200.fc42.x86_64
- 架構:X86_64
其他Linux環境也可以。
安裝各種環境
安裝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

說明環境已經配置好了
安裝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
根據教程做,就可以實現這種效果啦。


安裝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

然後安裝一些插件

下面這些都要裝




安裝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的未來和主力,持續更新和優化 |
安裝
建議都用官方法進行安裝。
方法一(官網法)
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
方法二(系統倉庫法)
不建議本法
# Debian系
sudo apt install arm-none-eabi-gcc
# Rhel系
sudo dnf install arm-none-eabi-gcc

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

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

安裝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”指令退出該模式。

下載並安裝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

測試
打開終端輸入
ozone

下載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/


工程創建與測試
使用CubeMX創建工程
點擊進入單片機挑選的按鈕

搜索對應芯片,並雙擊對應芯片選項。

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


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


FreeRTOS也要配置一下。


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


對工程進行配置與編譯
在工程文件夾打開終端

然後打開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
這樣就是編譯成功了。

對代碼提示進行配置
在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,頭文件提示正常

移植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

下載程序到板子
配置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就出來了

將設備連接到JLink並燒錄程序
圖形界面燒錄
#打开终端输入
JFlashLite
選擇對應的芯片型號和速度

添加hex文件


點擊燒錄並完成:

成功點亮led:

終端燒錄
算鳥算鳥,太麻煩了。
配置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仓库下的***`工程文件移植(创建新模板请看这里)`***文件夹了,到时候新建一个工程后,直接把这个文件夹下的所有文件全部复制过来即可。
使用ozone進行Flash燒錄和Debug調試
基礎配置
打開終端輸入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)。

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

點繼續就行。


燒錄與調試
可以看下面這個視頻,講的挺好的。(從30:10開始看)
https://www.bilibili.com/video/BV1yrLHzZEoE

點擊File讓他按文件名排序。

找到led_task.cpp點擊就可以打開這個源文件啦。
