你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

如何在搭载了 RT-Thread 系统的 STM32 平台上使用 C++?

[复制链接]
gaosmile 发布时间:2020-4-1 18:39
硬件平台简介
  n5 k, x6 |2 M7 v2 E
本文基于意法半导体 STM32F411 NUCLEO开发板,给出了 C++ 的具体应用示例代码,由于RT-Thread上层应用API的通用性,因此这些代码不局限于具体的硬件平台,用户可以轻松将它移植到其它平台上。# z3 ]1 |3 J6 i
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的封装)、功耗“轻微”。

微信图片_20200401183618.jpg

如何在 STM32 上使用 C++

4 r7 }  d* E& u# {% {
准备工作
5 }  n, w9 Z- m0 }+ K  T

1、下载 RT-Thread 源码

2、下载 ENV 工具

3、进入rt-thread\bsp\stm32f411-st-nucleo 目录,检查 BSP rtconfig.py 文件和 SConstruct 文件是否支持 C++ 配置,如下图所示

检查 rtconfig.py 文件中对 C++ 的支持

微信图片_20200401183621.jpg

检查 SConstruct 文件中对 C++ 的支持

微信图片_20200401183624.jpg

打开 C++ 支持:

打开 Env 工具,在 Env 命令行中输入 menuconfig,进入配置界面,使用 menuconfig 工具(学习如何使用)配置工程。在 menuconfig 配置界面依次选择 RT-Thread Components ---> C++ features ---> Support C++ features,如图所示:

: o- E' J- `) y# r9 N8 s

微信图片_20200401183628.png

编译工程: scons --target=mdk5 1. 生成 mdk5 工程,将示例代码附带的 main.cpp 替换掉 BSP 中的 main.c 并重新加入到工程中,如图所示:

微信图片_20200401183631.jpg

编译,下载程序,在终端输入 help 命令可以看到 test_cpp 已经添加成功了。

4 M! Q. {) i. ?

微信图片_20200401183633.png

运行 C++ 程序:

在终端输入 test_cpp 运行结果如下图所示。

微信图片_20200401183637.png


" @; H& O* v6 ^8 F9 Y! M" i: C
+ A# q/ q! I5 I" ]' a- v
C++ 全局对象构造函数的调用, b5 n- s5 P% t3 U$ _* r9 x8 p

- f$ u  {9 k0 s* R8 t$ j% [

RT-Thread 中对全局对象构造函数的实现中,以 GNUC 为例,在 rt-thread\components\cplusplus 目录下的 crt_init.c 文件中对 C++ 进行了系统初始化, 在特定的 BSP 目录下,连接脚本文件 link.lds 为 C++ 全局构造函数的代码分配了段,使 C++ 全局对象构造函数链接后能够存放在指定的段中。如下图所示:

微信图片_20200401183640.jpg

crt_init.c 文件完成了 C++ 系统的初始化工作

C++ 系统初始化部分:

1RT_WEAK int cplusplus_system_init(void)
" ]1 X6 Q) h! X0 l8 q0 U7 V5 Q 2{9 H; f/ H' Q! l  a
3    typedef void(*pfunc)();
; R9 o1 i5 g5 K5 }$ h) R# S 4    extern pfunc __ctors_start__[];
. f& u6 d5 H8 s3 Y, s# } 5    extern pfunc __ctors_end__[];
0 U, o4 R; g* U" y 6    pfunc *p;
; X  \' k% k; E! [% i 7
6 `; h7 O0 y  y- A. M0 h) N9 P 8    for (p = __ctors_start__; p < __ctors_end__; p++)
: e' y( O* t4 g0 z. A3 V1 n 9        (*p)();0 I/ Z0 S: m3 N+ b; d/ f' a
10! Y1 r0 x& a# c2 V8 W4 a  I
11    return 0;- Z5 v+ b9 k5 D
12}; o+ f7 r. h( l' {7 Z
13INIT_COMPONENT_EXPORT(cplusplus_system_init);

在 cplusplus_system_init 函数中,将全局对象的构造函数依次链接到了链接脚本文件中为其分配的段中,并且调用了 RT-Thread 组件自动初始化的宏 INIT_COMPONENT_EXPORT,所以在链接的时候,C++全局对象构造函数所产生的目标文件就被链接到了__ctors_start__和__ctors_end__组成的段中。
! ?& g7 ^3 }* e1 v2 J

链接脚本中为 C++ 全局构造函数分配的段部分:

5 E0 P9 h5 o4 R) }% ~
1PROVIDE(__ctors_start__ = .);! K- l. P( ~5 p* @, J" }0 [4 @4 V
2KEEP (*(SORT(.init_array.*)))  H' x2 s2 t. h9 r5 }0 R
3KEEP (*(.init_array))
! _. o7 _. e/ s7 A$ A4PROVIDE(__ctors_end__ = .);

" m( H7 Q7 j9 [6 ]( f

__ctors_start__ 分配了 C++ 全局构造函数段的起始地址, __ctors_end__ 分配了 C++ 全局构造函数段的结束地址,所以全局构造函数在系统初始化的时候,就会被链接到这里分配的段地址中。

RT-Thread C++ 异常说明

: E* ^/ u8 ~& C+ w7 l

同样,在链接脚本文件 link.lds 中,也为 C++ 异常分配了段地址:

1    __exidx_start = .;" T7 u! t# L9 A9 a" Q+ @
2    ARM.exidx :% u7 Q  A  F1 I
3    {! Y) a. d+ _; |& R
4        *(.ARM.exidx* .gnu.linkonce.armexidx.*)
" ~! g" d2 ?8 E/ H: ]5 |5        _sidata = .;
" d0 @% P, y' n3 X; E2 X& A6    } > CODE" x3 P, w* G+ }) [( I3 r) ?! f' C
7    __exidx_end = .;

$ W; X- j/ Q- v) {3 W' o* H
. e4 X/ @* a3 _; @) P

__exidx_start 分配了 C++ 异常的起始地址, __exidx_end 分配了 C++ 异常的结束地址,当异常产生的时候,就会被分配到指定的段地址中。

这里以一个 C++ 除零异常的抛出和捕获为例:

1   #include<math.h>
% V2 p' `) T1 c' i9 ?/ o 2
3 b; ?4 q9 B, ^% B. r3 m 3    #define MIN_VALUE                 (1e-4)                          3 V# g" K. R9 {
4    #define IS_DOUBLE_ZERO(d)         (abs(d) < MIN_VALUE)5 [7 E$ n, |/ G% X4 n1 |) W& v
5' m+ O2 I" |6 v4 I$ v6 h5 ^1 M
6    double div_func(double x, double y)                     
' v' i7 s9 F' r/ b6 g 7    {
: e* ~8 m' i9 a  A0 d 8        if (IS_DOUBLE_ZERO(y))
  k5 _( R! |# j 9        {
" U2 Q4 a! i4 {1 M( o10            throw y;                                           /* throw exception */
+ `. K; G: ?- v' q2 x* b* Q11        }
0 f; ^- K- b1 ], e& o$ Q1 r& E12
2 \* {# H2 G; H( T: o9 X. e1 ]% H8 ]13        return x / y;                                 
3 ~) Q4 b/ Z/ g! I14    }
) N' j  g" c" R% M' g- F  e5 x156 w/ h" O9 n: U
16    void throw_exceptions(void *args)
3 ^' ]  @8 P0 T. b( K9 g4 _1 {7 h17    {
) c& W8 c: ^; N0 W18        try                                            0 W* E- p- ^1 r0 ?
19        {
7 W2 D  J+ _0 [& A20            div_func(6, 3);& m- n. J! f" K# u9 {3 A
21            rt_kprintf("there is no err\n");! b( E& ?4 g5 s: q& e( b+ e
22            div_func(4, 0);                                   /* create exception*/
% r( k1 X* W! p- V& h1 k23            rt_kprintf("you can run here?\n");% h' ]' h1 g' v+ F( D
24        }( i7 \6 c' }9 f2 F
25        catch(double)                                         /* catch exception */     : ?9 G. k$ |1 @0 \/ P& s
26        {" b6 L( y9 O% B! T/ b# M
27            rt_kprintf("error of dividing zero\n");
& Z" N* s. l. r) w+ w* P# Z28        }
7 A) ^5 s. t7 E! ^29    }
  a7 ?) `, q' @30
  Z' O- V7 M7 b31    MSH_CMD_EXPORT(throw_exceptions, throw cpp exceptions);

  a) c5 |5 S$ l# U

9 d% a# }$ Z( r+ c2 e

当除零异常发生的时候 div_func 函数会抛出一个异常,在 throw_exceptions 函数中会去捕获这个异常。

下载代码,并在终端输入 throw_exceptions 运行结果如下图所示。

微信图片_20200401183643.png

到这一步为止,如何在搭载了 RT-Thread 系统的 STM32 平台上如何使用 C++ 的介绍就结束了。


9 S/ X6 I! M9 V2 g7 B/ g! R- V
收藏 评论0 发布时间:2020-4-1 18:39

举报

0个回答

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版