| 
 
| 结识更多同行,共同讨论“嵌入式”技术。欢迎添加社区客服微信,备注发送“电源+公司名(学校)+职位(专业)”拉您入群。 
 简介
 
 本文描述了如何使用在搭载了 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-threadbspstm32f411-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=mdk51. 生成 mdk5工程,将示例代码附带的 main.cpp替换掉 BSP中的 main.c并重新加入到工程中,如图所示:
 
 编译,下载程序,在终端输入 help命令可以看到 test_cpp已经添加成功了。
 
 运行 C++程序:
 
 在终端输入 test_cpp运行结果如下图所示。
 
 C++ 全局对象构造函数的调用
 
 RT-Thread中对全局对象构造函数的实现中,以 GNUC为例,在 rt-threadcomponentscplusplus目录下的 crt_init.c文件中对 C++进行了系统初始化, 在特定的 BSP目录下,连接脚本文件 link.lds为 C++全局构造函数的代码分配了段,使 C++全局对象构造函数链接后能够存放在指定的段中。如下图所示:
 
 crt_init.c文件完成了 C++系统的初始化工作
 
 C++系统初始化部分:
 
 1RT_WEAK intcplusplus_system_init(void)
 
 2{
 
 3typedefvoid(*pfunc);
 
 4externpfunc __ctors_start__[];
 
 5externpfunc __ctors_end__[];
 
 6pfunc *p;
 
 7
 
 8for(p = __ctors_start__; p < __ctors_end__; p++)
 
 9(*p);
 
 10
 
 11return0;
 
 12}
 
 13INIT_COMPONENT_EXPORT(cplusplus_system_init);
 
 在 cplusplus_system_init函数中,将全局对象的构造函数依次链接到了链接脚本文件中为其分配的段中,并且调用了 RT-Thread组件自动初始化的宏 INIT_COMPONENT_EXPORT,所以在链接的时候,C++全局对象构造函数所产生的目标文件就被链接到了__ctors_start__和__ctors_end__组成的段中。
 
 链接脚本中为 C++全局构造函数分配的段部分:
 
 1PROVIDE(__ctors_start__ = .);
 
 2KEEP (*(SORT(.init_array.*)))
 
 3KEEP (*(.init_array))
 
 4PROVIDE(__ctors_end__ = .);
 
 __ctors_start__分配了 C++全局构造函数段的起始地址, __ctors_end__分配了 C++全局构造函数段的结束地址,所以全局构造函数在系统初始化的时候,就会被链接到这里分配的段地址中。
 
 RT-Thread C++ 异常说明
 
 同样,在链接脚本文件 link.lds中,也为 C++异常分配了段地址:
 
 1__exidx_start = .;
 
 2ARM.exidx :
 
 3{
 
 4*(.ARM.exidx* .gnu.linkonce.armexidx.*)
 
 5_sidata = .;
 
 6} > CODE
 
 7__exidx_end = .;
 
 __exidx_start分配了 C++异常的起始地址, __exidx_end分配了 C++异常的结束地址,当异常产生的时候,就会被分配到指定的段地址中。
 
 这里以一个 C++除零异常的抛出和捕获为例:
 
 1#include<math.h>
 
 2
 
 3#defineMIN_VALUE (1e-4)
 
 4#defineIS_DOUBLE_ZERO(d) (abs(d) < MIN_VALUE)
 
 5
 
 6doublediv_func(doublex, doubley)
 
 7{
 
 8if(IS_DOUBLE_ZERO(y))
 
 9{
 
 10throwy; /* throw exception */
 
 11}
 
 12
 
 13returnx / y;
 
 14}
 
 15
 
 16voidthrow_exceptions(void*args)
 
 17{
 
 18try
 
 19{
 
 20div_func( 6, 3);
 
 21rt_kprintf( "there is no errn");
 
 22div_func( 4, 0); /* create exception*/
 
 23rt_kprintf( "you can run here?n");
 
 24}
 
 25catch( double) /* catch exception */
 
 26{
 
 27rt_kprintf( "error of dividing zeron");
 
 28}
 
 29}
 
 30
 
 31MSH_CMD_EXPORT(throw_exceptions, throwcpp exceptions);
 
 当除零异常发生的时候 div_func函数会抛出一个异常,在 throw_exceptions函数中会去捕获这个异常。
 
 下载代码,并在终端输入 throw_exceptions运行结果如下图所示。
 
 到这一步为止,如何在搭载了 RT-Thread系统的 STM32平台上如何使用 C++的介绍就结束了。
 
 参考资料
 
 1、ENV 用户手册
 
 https://www.rt-thread.org/document/site/programming-manual/env/env/
 
 2、STM32F411-ST-NUCLEO BSP 源码
 
 https://github.com/RT-Thread/rt-thread/tree/master/bsp/stm32/stm32f411-st-nucleo
 
 (请将以上链接复制至外部浏览器打开)
 | 
 |