STM32cubeMX 和 C++ 记要

一、目的

本文是为了记录使用 stm32CubeMXarm-none-eabi-gccvscode 配置 arm 的 C++ 环境。

参考了下面的两篇文章。

二、CubeMX 基本配置

有两点记要:

  • SYS 的 Debug 选项
image.png

不然只能下载一次程序。

  • Toolchain 工具链
image.png

要选择 Makefile

三、VScode 配置

使用 vscode 打开项目后,按下 <Ctrl+Shift+P>,选择 C/C++ Edit Configurations (UI) ,进入 C/C++ 的基本配置。

3.1 配置编译类型

image.png

Compiler path 编译器路径,我选择了 gcc

IntelliSense mode 应该是智能提示,我电脑是 win10 故选了 windows-gcc-arm

3.2 对比 makefile 来配置

因为 C/C++ 的项目配置比较灵活,其查找的头文件路径要手动提示给编译器。故还需要告诉智能提示怎样找到头文件和一些宏定义。

image.png

Include path 头文件查找路径,要对照 Makefile 文件里的 C_INCLUDES

image.png

注意的是,要把 -I 和后面 \ 去掉。(-I 是给编译器用的, \make 里取消换行)

image.png

Defines 宏定义,HAL 库 使用的宏。其在 Makefile 里的位置是,

image.png

完成上面的配置后,基本就可把 vscode 当成 IDE使用了(还差些插件,如cortex-debug之类,可以网上查找)。

四、C++ 的入口

网上有些介绍怎样使用 C++ 里,是直接把 main.c 文件改成 main.cpp 。这种方法可取,但是有一个弊端。如果你写写下代码,突然想使用 cube 工具修改一些配置,其就会再生成一个 main.c 文件,且里面没有了你之前写的逻辑代码。因为你的逻辑代码还在 main.cpp 里。故只好又把代码搬到 c 中,再修改 c 文件后缀为 cpp。

这多麻烦啊。于是,我取纳了另一种方法。定义一个 C++ 的入口函数,再又 c 代码来调用他。

下面举例。

image.png

在项目的 Core 里分别定义了两个文件:

  • cpp_start.h 为 C++ 提供给 C 的接口文件
  • start.cpp 为 C++ 的入口函数的实现

其中,cpp_start.h 的内容如下:

#ifndef __CPP_START_H__
#define __CPP_START_H__ 

#ifdef __cplusplus
extern "C" {
#endif

int cpp_start();

#ifdef __cplusplus
}
#endif

#endif
image.png

因为如果使用 g++ 来编译程序,编译器自身会定义了一个宏 __cplusplus。不同语言之间,若想互相通信,互相调用,就要有相同类型的数据转换。而 C++ 自身是兼容 C 的,所以其调用 C 的函数或变量均是很容易。但是返过来就不一样了。

以函数为例,C++为了支持重载,其编译的函数名与我们定义的是不一样的,均包含有形参类型。例如

// 这个例子是举例,与实际名称是有差别。
// 现只是近似说明
void print(int a, int b);  // -> print_int_int()

但是 C 对于函数名称的编译是很单纯的,你给什么,我就使用什么。

因此,这里是为了告诉编译,别改我名字,好不。

这样接口就实现了,那么你就可以在 start.cpp 里任意使用 C++ 的乐趣了。

五、makefile 的修改

接下来,到了很关键的一步,也是最容易错的一样,修改 Makefile 文件。

5.1 增加 C++ 文件资源

image.png

5.2 增加编译方式

image.png

5.3 增加编译的 flags

image.png

CFLAGS 的基础上,增加 -fno-rtti-fno-exceptions 。表示不使用 rtti异常功能。因为这两者会增加编译后的体积。

5.3 增加object

image.png

C 为模板,把原来的 .c 改成 .cppC_SOURCES 改成 CPP_SOURCES

同时一定要注意,此处 OBJECTS 后接的是 +=。且,不能放在 # list of ASM program objects 之后。

5.4 增加 C++ 文件的编译规则

image.png

5.5 改写 clean 指令(只限 win 系统)

image.png

此命令为删除 build 文件夹下的中间文件。

5.6 完整如下

##########################################################################################################################
# File automatically-generated by tool: [projectgenerator] version: [3.18.0-B7] date: [Sun Apr 16 20:59:25 CST 2023]
##########################################################################################################################

# ------------------------------------------------
# Generic Makefile (based on gcc)
#
# ChangeLog :
#   2017-02-10 - Several enhancements + project update mode
#   2015-07-22 - first version
# ------------------------------------------------

######################################
# target
######################################
TARGET = study-5

######################################
# building variables
######################################
# debug build?
DEBUG = 1
# optimization
OPT = -Og

#######################################
# paths
#######################################
# Build path
BUILD_DIR = build

######################################
# source
######################################

# C++ sources
CPP_SOURCES = \
Core/Src/start.cpp

# C sources
C_SOURCES =  \
Core/Src/main.c \
Core/Src/gpio.c \
Core/Src/stm32f1xx_it.c \
Core/Src/stm32f1xx_hal_msp.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio_ex.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim_ex.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc_ex.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_gpio.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pwr.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash_ex.c \
Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_exti.c \
Core/Src/system_stm32f1xx.c  

# ASM sources
ASM_SOURCES =  \
startup_stm32f103xe.s

#######################################
# binaries
#######################################
PREFIX = arm-none-eabi-
# The gcc compiler bin path can be either defined in make command via GCC_PATH variable (> make GCC_PATH=xxx)
# either it can be added to the PATH environment variable.
ifdef GCC_PATH
CC = $(GCC_PATH)/$(PREFIX)gcc
AS = $(GCC_PATH)/$(PREFIX)gcc -x assembler-with-cpp
CP = $(GCC_PATH)/$(PREFIX)objcopy
SZ = $(GCC_PATH)/$(PREFIX)size
CPP = $(GCC_PATH)/$(PREFIX)g++
else
CC = $(PREFIX)gcc
AS = $(PREFIX)gcc -x assembler-with-cpp
CP = $(PREFIX)objcopy
SZ = $(PREFIX)size
CPP = $(PREFIX)g++
endif
HEX = $(CP) -O ihex
BIN = $(CP) -O binary -S
 
#######################################
# CFLAGS
#######################################
# cpu
CPU = -mcpu=cortex-m3

# fpu
# NONE for Cortex-M0/M0+/M3

# float-abi

# mcu
MCU = $(CPU) -mthumb $(FPU) $(FLOAT-ABI)

# macros for gcc
# AS defines
AS_DEFS = 

# C defines
C_DEFS =  \
-DUSE_HAL_DRIVER \
-DSTM32F103xE

# AS includes
AS_INCLUDES = 

# C includes
C_INCLUDES =  \
-ICore/Inc \
-IDrivers/STM32F1xx_HAL_Driver/Inc \
-IDrivers/STM32F1xx_HAL_Driver/Inc/Legacy \
-IDrivers/CMSIS/Device/ST/STM32F1xx/Include \
-IDrivers/CMSIS/Include

# compile gcc flags
ASFLAGS = $(MCU) $(AS_DEFS) $(AS_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections

CFLAGS += $(MCU) $(C_DEFS) $(C_INCLUDES) $(OPT) -Wall -fdata-sections -ffunction-sections

ifeq ($(DEBUG), 1)
CFLAGS += -g -gdwarf-2
endif

# Generate dependency information
CFLAGS += -MMD -MP -MF"$(@:%.o=%.d)"

CPP_FLAGS = $(CFLAGS) -fno-rtti -fno-exceptions

#######################################
# LDFLAGS
#######################################
# link script
LDSCRIPT = STM32F103VETx_FLASH.ld

# libraries
LIBS = -lc -lm -lnosys 
LIBDIR = 
LDFLAGS = $(MCU) -specs=nano.specs -T$(LDSCRIPT) $(LIBDIR) $(LIBS) -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref -Wl,--gc-sections

# default action: build all
all: $(BUILD_DIR)/$(TARGET).elf $(BUILD_DIR)/$(TARGET).hex $(BUILD_DIR)/$(TARGET).bin

#######################################
# build the application
#######################################
# list of objects
OBJECTS = $(addprefix $(BUILD_DIR)/,$(notdir $(C_SOURCES:.c=.o)))
vpath %.c $(sort $(dir $(C_SOURCES)))

# list of C++ objects
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(CPP_SOURCES:.cpp=.o)))
vpath %.cpp $(sort $(dir $(CPP_SOURCES)))

# list of ASM program objects
OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o)))
vpath %.s $(sort $(dir $(ASM_SOURCES)))

$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR) 
    $(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@

$(BUILD_DIR)/%.o: %.cpp Makefile | $(BUILD_DIR) 
    $(CPP) -c $(CPP_FLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.cpp=.lst)) $< -o $@

$(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR)
    $(AS) -c $(CFLAGS) $< -o $@

$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile
    $(CC) $(OBJECTS) $(LDFLAGS) -o $@
    $(SZ) $@

$(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
    $(HEX) $< $@
    
$(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR)
    $(BIN) $< $@    
    
$(BUILD_DIR):
    mkdir $@        

#######################################
# clean up
#######################################
clean:
#   -rm -fR $(BUILD_DIR)
    rmdir /s/q $(BUILD_DIR)
  
#######################################
# dependencies
#######################################
-include $(wildcard $(BUILD_DIR)/*.d)

# *** EOF ***

六、遇过的错误

遇过的错误大都和 Makefile 有关。

6.1 路径书写错误

make: *** No rule to make target 'build/start.o', needed by 'build/study-5.elf'.  Stop.

这个错误里的 build/start.o ,指的是 Core/Src/start.cpp 这个文件没找到,因此编译不出 build/start.o 这个规则来。

这个规则是在

image.png

这里产生的。

形成这个错误的主要原因在于,你的 CPP_SOURCES 的路径书写出错 。

# 错误形式
# C++ sources
CPP_SOURCES = \
Core\Src\start.cpp

# 正确的应为
CPP_SOURCES = \
Core/Src/start.cpp

而我错的原因是使用 vscode 右键文件时的选项 Copy Relative Path,因为其复制的是 win 的路径风格。

6.2 编译器选择错误

g++ -c -mcpu=cortex-m3 -mthumb   -DUSE_HAL_DRIVER -DSTM32F103xE -ICore/Inc -IDrivers/STM32F1xx_HAL_Driver/Inc -IDrivers/STM32F1xx_HAL_Driver/Inc/Legacy -IDrivers/CMSIS/Device/ST/STM32F1xx/Include -IDrivers/CMSIS/Include -Og -Wall -fdata-sections -ffunction-sections -g -gdwarf-2 -MMD -MP -MF"build/start.d" -fno-rtti -fno-exceptions -Wa,-a,-ad,-alms=build/start.lst Core/Src/start.cpp -o build/start.o
g++: warning: '-mcpu=' is deprecated; use '-mtune=' or '-march=' instead
g++: error: unrecognized command line option '-mthumb'; did you mean '-mtbm'?
make: *** [Makefile:181: build/start.o] Error 1

一开始,我对其中的 -mcpu= 百思不得其解,因为其他人的 makefile 也是这样用的,为何我的就不行。

后来我细看才发现 .cpp 的编译器使用了 g++,而不是 arm-none-eabi-g++

image.png

另外,还会出现一种情况

image.png

CPP 的编译规则里,忘记改成 CPP 了。

6.3 链接错误

d:/programfiles/armgcc/12.2 rel1/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: d:/programfiles/armgcc/12.2 rel1/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7-m/nofp\libc_nano.a(libc_a-closer.o): in function `_close_r':
closer.c:(.text._close_r+0xc): warning: _close is not implemented and will always fail
d:/programfiles/armgcc/12.2 rel1/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: d:/programfiles/armgcc/12.2 rel1/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7-m/nofp\libc_nano.a(libc_a-lseekr.o): in function `_lseek_r':
lseekr.c:(.text._lseek_r+0x10): warning: _lseek is not implemented and will always fail
d:/programfiles/armgcc/12.2 rel1/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: d:/programfiles/armgcc/12.2 rel1/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7-m/nofp\libc_nano.a(libc_a-readr.o): in function `_read_r':
readr.c:(.text._read_r+0x10): warning: _read is not implemented and will always fail
d:/programfiles/armgcc/12.2 rel1/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: d:/programfiles/armgcc/12.2 rel1/bin/../lib/gcc/arm-none-eabi/12.2.1/thumb/v7-m/nofp\libc_nano.a(libc_a-writer.o): in function `_write_r':
writer.c:(.text._write_r+0x10): warning: _write is not implemented and will always fail
d:/programfiles/armgcc/12.2 rel1/bin/../lib/gcc/arm-none-eabi/12.2.1/../../../../arm-none-eabi/bin/ld.exe: warning: build/study-5.elf has a LOAD segment with RWX permissions

这个是什么原因,我也不太清楚。反正我重装了 arm-gcc 就解决了。

6.4 只编译 C++ 的文件,不会编译 C 的文件

这种情况,一般是 OBJECTS 改错了。

image.png

这里的 OBJECTS 后要跟 += 。不然,会覆盖了原来 C 的内容。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,002评论 6 509
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,777评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,341评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,085评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,110评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,868评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,528评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,422评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,938评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,067评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,199评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,877评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,540评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,079评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,192评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,514评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,190评论 2 357

推荐阅读更多精彩内容