本文描述了如何使用在搭载了 RT-Thread 系统的 STM32 平台上使用 C++,包括 C++ 的配置和应用等。并给出了在STM32F411 NUCLEO开发板上验证的代码示例。
硬件平台简介
本文基于意法半导体 STM32F411 NUCLEO开发板,给出了 C++ 的具体应用示例代码,由于RT-Thread上层应用API的通用性,因此这些代码不局限于具体的硬件平台,用户可以轻松将它移植到其它平台上。
STM32F411 NUCLEO是意法半导体推出的一款基于ARM Cortex-M4内核的开发板,最高主频为100Mhz,该开发板具有丰富的板载资源,可以充分发挥STM32F411RE 的芯片性能。
STM32F411RE从属于销量名列前茅的STM32F4系列,众所周知,F4是STM32主打高性能和数字信号处理的“轻奢”系列。
“奢侈”在F4作为内核为Cortex-M4 (DSP+FPU)的MCU,可选180MHz 主频、2M Flash/384KB RAM、Chrom-ART加速器、MPI-DSI接口、延伸到125度的工作温度、DFSDM数字滤波器以及各种常见的音频(SAI)、连接(Ethernet、Camera、USB)、控制(CAN、UART、I2C)、存储(FMC、2/4/8 bits SPI、SDMMC)外设。
“轻”在价格让人“轻松”、尺寸“轻巧”(不到3mm*3mm的封装)、功耗“轻微”。
如何在 STM32 上使用 C++
准备工作
1、下载 RT-Thread 源码
2、下载 ENV 工具
3、进入rt-thread\bsp\stm32f411-st-nucleo 目录,检查 BSP rtconfig.py 文件和 SConstruct 文件是否支持 C++ 配置,如下图所示
检查 rtconfig.py 文件中对 C++ 的支持
检查 SConstruct 文件中对 C++ 的支持
打开 C++ 支持:
打开 Env 工具,在 Env 命令行中输入 menuconfig,进入配置界面,使用 menuconfig 工具(学习如何使用)配置工程。在 menuconfig 配置界面依次选择 RT-Thread Components ---> C++ features ---> Support C++ features,如图所示:
编译工程: scons --target=mdk5 1. 生成 mdk5 工程,将示例代码附带的 main.cpp 替换掉 BSP 中的 main.c 并重新加入到工程中,如图所示:
编译,下载程序,在终端输入 help 命令可以看到 test_cpp 已经添加成功了。
运行 C++ 程序:
在终端输入 test_cpp 运行结果如下图所示。
C++ 全局对象构造函数的调用
RT-Thread 中对全局对象构造函数的实现中,以 GNUC 为例,在 rt-thread\components\cplusplus 目录下的 crt_init.c 文件中对 C++ 进行了系统初始化, 在特定的 BSP 目录下,连接脚本文件 link.lds 为 C++ 全局构造函数的代码分配了段,使 C++ 全局对象构造函数链接后能够存放在指定的段中。如下图所示:
crt_init.c 文件完成了 C++ 系统的初始化工作
C++ 系统初始化部分:
RT_WEAK int cplusplus_system_init(void) { typedef void(*pfunc)(); extern pfunc __ctors_start__[]; extern pfunc __ctors_end__[]; pfunc *p; for (p = __ctors_start__; p < __ctors_end__; p++) (*p)(); return 0; }
复制代码链接脚本中为 C++ 全局构造函数分配的段部分:
PROVIDE(__ctors_start__ = .); KEEP (*(SORT(.init_array.*))) KEEP (*(.init_array)) PROVIDE(__ctors_end__ = .);
复制代码RT-Thread C++ 异常说明
同样,在链接脚本文件 link.lds 中,也为 C++ 异常分配了段地址:
__exidx_start = .; ARM.exidx : { *(.ARM.exidx* .gnu.l_sidata = .; } > CODE __exidx_end = .;
复制代码这里以一个 C++ 除零异常的抛出和捕获为例:
#include<math.h> #define MIN_VALUE (1e-4) #define IS_DOUBLE_ZERO(d) (abs(d) < MIN_VALUE) double div_func(double x, double y) { if (IS_DOUBLE_ZERO(y)) { throw y; /* throw exception */ } return x / y; } void throw_exceptions(void *args) { try { div_func(6, 3); rt_kprintf("there is no err\n"); div_func(4, 0); /* create exception*/ rt_kprintf("you can run here\n"); } catch(double) /* catch exception */ { rt_kprintf("error of dividing zero\n"); } } MSH_CMD_EXPORT(throw_exceptions, throw cpp exceptions);
复制代码下载代码,并在终端输入 throw_exceptions 运行结果如下图所示。
/** * @file main.cpp * @time 2019-6-8 13:31:39 * @author tyustli * @platform w10 + mdk5 + rtthread 4.0.0 */ #include <rtthread.h> #include <rtdevice.h> #include <board.h> /* defined the LED0 pin: PA5 */ #define LED0_PIN GET_PIN(A, 5) int main(void) { int count = 1; /* set LED0 pin mode to output */ rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT); while (count++) { rt_pin_write(LED0_PIN, PIN_HIGH); rt_thread_mdelay(500); rt_pin_write(LED0_PIN, PIN_LOW); rt_thread_mdelay(500); } return RT_EOK; } using namespace rtthread; class tran { public: void getnumber(int a, int b) { x = a; y = b; } void out(tran & s) { rt_kprintf("x = %d, y = %d\n", x, y); } private: int x, y; }; int test_cpp(void) { tran s; s.getnumber(13, 54); s.out(s); return 0; } MSH_CMD_EXPORT(test_cpp, test cpp); #include<math.h> #define MIN_VALUE (1e-4) #define IS_DOUBLE_ZERO(d) (abs(d) < MIN_VALUE) double div_func(double x, double y) { if (IS_DOUBLE_ZERO(y)) { throw y; /* throw exception */ } return x / y; } void throw_exceptions(void *args) { try { div_func(6, 3); rt_kprintf("there is no err\n"); div_func(4, 0); /* create exception*/ rt_kprintf("you can run here\n"); } catch(double) /* catch exception */ { rt_kprintf("error of dividing zero\n"); } } MSH_CMD_EXPORT(throw_exceptions, throw cpp exceptions);
复制代码参考资料
1、ENV 用户手册
https://www.rt-thread.org/docume ... ing-manual/env/env/
2、STM32F411-ST-NUCLEO BSP 源码
https://github.com/RT-Thread/rt- ... stm32f411-st-nucleo
转自:RT-Thread物联网操作系统