楼主

[嵌入式] 【分享帖】用C++11开发STM32程序

[复制链接]
无人机放弃=给你自由
2017-12-14 22:00:43 只看该作者

马上注册,玩转Robomaster!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
今天这篇文章有点复杂,大家要注意一点看啦!
我们知道KEIL是支持C++的,网上一搜索也能找到一些使用C++的方法,无非是在Keil里的options->C/C++->Misc Controls里添加—cpp,如果要支持c++11,还需要指定—cpp11。事实上这样的C++并不是完整意义的上的C++,本人测试过,有好多C++的新功能都是没有办法实现的。这里需要注明的是,在KEIL5.18a以前的版本(包括5.18a)所支持的Arm Compiler只有ARM Compiler 5以及更低的版本,C++11支持不完整,而对C++11有完整支持就必须要使用Arm Compiler 6 即 AC6。
为了使用对C++11有完整支持的Arm Compiler 6(AC6),今天所使用的KEIL MDK版本至少应用为5.20版本以上(Arm Compiler 6.4)
本文中本人使用的AC6为6.7版本,为KEIL MDK 4.24a所自带的AC6编译器
这里需要注意的是AC6仅支持以下系统
  • Windows Server 2012, 64-bit only.
  • Windows 7 Enterprise SP1.
  • Windows 7 Professional SP1.
  • Windows 8.1, 64-bit only.
  • Windows 10, 64-bit only.

所以大家在试验之前,一定要检查下自己所使用的环境,否则就会浪费时间啦。
关于MDK的下载以及和谐办法,大家自行百度解决啦~
在开始之前,有个东西要了解,那就是microlib,不知道大家知道不知道,本来想写一篇关于microlib的文章,想必这是大家最熟悉的陌生人了。使用STM32CubeMX生成的MDK工程都会自动链接这个系统自带的库。

                               
登录/注册后可看帖子
它就是Code Generation里的Use MicroLIB,默默地被勾上。
那么他最主要的作用是什么呢?
  • 创建栈空间
  • 创建堆空间,如果需要的话,这样才可以使用malloc等一些函数
  • 初始化用户可能用到的系统库
  • 调用用户的main函数
  • Microlib不支持exit函数

如果是C/C++ standardlib 还支持
  • 支持应用程序使用ISO定义的函数
  • 可以捕捉运行时错误并发送信号,如果需要,在错误发生时或行程序退出时还可以停止运行

然而真正的C++开发是不能链接microlib的,因为他只是标准C library的一个精简集。网上能查到microlib的一些限制,这里列举一些出来
  • Microlib和标准的IOS C库不兼容,所以不支持有些ISO所提供的特性或者功能不完整
  • 仅对C99库提供有限的函数支持
  • Microlib不支持C++
  • 不支持位置独立的代码
  • 不支持单个或双个的内存区域模型
  • 不支持Mutex以及不支持宽字符

正常情况下,在STM32CubeMX通过成的.s文件里可以看到一个__main函数,这个就是microlib的入口地址,他会完成上述的初始化动作,最后跳转到我们熟悉的main。

                               
登录/注册后可看帖子
刚才也说过我们要实现真正的C++编程,就不能链接microlib,如果不链接microlib,就会默认链接到我们的C/C++标准库。
现在开始,首先依然是使用STM32CubeMX生成一个带串口的工程,阿圆有依旧是STM32F437ZGT6,工程名为ARMCCTest,要使用完整的C++11特性就必须使用AC6,这里把ARM Compiler设置为V6.7,并勾掉Use MicroLib

                               
登录/注册后可看帖子
这里根据ARM官方的建议,检查下Short enums/wchar是否勾上

                               
登录/注册后可看帖子
这样就设置好了。
但是呢,如果就这样去编译,会有一堆的编译错误
主要是__weak编译失败

                               
登录/注册后可看帖子
AC6己经不支持直接声明 __weak了,需要使用 __attribute__((weak))替代。这里不建议使用全局替代的方法, 如下图所示

                               
登录/注册后可看帖子
因为如果你的的工程里有包含了C++文件,这种方法可能把系统库里的__weak也给替换了,曾经吃过大亏!结果都重装KEIL了
好的,为了测试C++11的功能,我们新建一个CppTest.cpp文件,为了保持和C的兼容性呢我们把main挪到了cpp文件里,将原来Keil生成的main改为cmain即可

                               
登录/注册后可看帖子

                               
登录/注册后可看帖子
这里看到有一个Test类,这就是我们需要对C++11特性进行测试的类

                               
登录/注册后可看帖子
这里面还包含了一个Base和Derived类

                               
登录/注册后可看帖子
这样一个简单的C++测试用例就写好了!
但是!这样是不能执行的!一旦执行系统在跳到__main时之后就跑飞了!
大家可以想一想这是怎么一回事?
留白
留白
留白
好啦,不卖关子啦,事实上本人也找了近两天的时间才找到解决办法,一开始认为是heap和stack没有初始化好,尝试了好久均未成功,后来在网上得到启发,这个问题是出在STDIO初始化上。
如果要使用C/C++标准库就要对其STDIO进行Retarget的,很简单,但却是非常关键的一步,就是这么一回事啦。
下载ARM官方的retarget文件,并加入到工程当中
下载链接
http://infocenter.arm.com/help/topic/com.arm.doc.faqs/attached/3844/retarget.c
稍微进行小修改,把它重定向到串口就可以啦!

                               
登录/注册后可看帖子
现在就可以把代码编译运行一下,从SSCOM看到代码正常运行并输出了log

                               
登录/注册后可看帖子
都运行成功了!
要问为什么没有使用std::cout,我也觉得很奇怪啦
../Src/CppTest.cpp(44): error: no member named 'cout' in namespace 'std'
std::cout<< "adsaf" ;
~~~~~^
上面只是简单测试了C++ vector容器,智能指针,auto变量和lambda表达式,当然C++11的内容比这要广泛得多,大家可自行测试!
不过要使用上完整的C++11代价也是非常大的(未开启优化 -O0编译)!上面的代码几乎不做什么有用的功能其大小竟然达到了可怕的231K!

                               
登录/注册后可看帖子
大家还Hold住吗!哈哈!



跳转到指定楼层
推荐

[嵌入式] 【分享帖】用C++11开发STM32程序

[复制链接]
顾问wmd
2018-3-17 10:48:08 只看该作者
最近也在探索STM32用C++开发的方法,看了楼主的方法 感觉受益良多呀
这类教程和探索比较少 感觉大家都有自己的方法
在这里我可以分享一下我对应的各类处理方法和一些坑过我的地方:
像那个__weak其实可以不用全局替换 考虑到尽量不去碰库里面的文件,
因为cube重新生成的话这些没有在User code范围内的修改都会被覆盖,
所以对于这个情况我的方法是在main.h里面加一个宏定义:#define __weak __attribute__((weak))
这样即可以搞定所有的__weak,因为这些库都include了main.h
另外,如果stm32开发要用到中断的话一定要在stm32f4xx_it.c的开头与结尾加上extern "C" 和大括号扩住(这个文件的开头和结尾都有user code段) 因为中断的跳转向量表是写在汇编的startup里面的 然后C++因为要考虑重载函数 所以函数的链接符号会和C的不一样 为了能正确的进入中断必须保持这些中断函数按照C的方式引出

还有其他一些比较稀少的外部情况问题都可以按照main.h加修补宏定义的方式来解决

我这边偶尔也会有探索C++编译时解决不了的问题,如果楼主还在弄的话不如加个好友交流一下?
推荐

[嵌入式] 【分享帖】用C++11开发STM32程序

[复制链接]
梯队队员NCSTMFW
2018-1-15 17:02:04 只看该作者
666666666666
31#

[嵌入式] 【分享帖】用C++11开发STM32程序

[复制链接]
梯队队员szthomas
2019-10-11 11:16:14 只看该作者
厉害啊啊啊啊啊啊啊啊
30#

[嵌入式] 【分享帖】用C++11开发STM32程序

[复制链接]
梯队队员地平线的光
2019-9-23 10:09:19 只看该作者
学习了!
回复

使用道具 举报

29#

[嵌入式] 【分享帖】用C++11开发STM32程序

[复制链接]
顾问薅电机狂魔
2019-7-26 23:26:15 只看该作者
对了,语言最好选择GNU版本的,比如gnu99,不然会有很多很多预编译指令报错
28#

[嵌入式] 【分享帖】用C++11开发STM32程序

[复制链接]
顾问薅电机狂魔
2019-7-26 23:23:22 只看该作者
Keil官方有一个迁移到新编译器的教程
http://www.keil.com/appnotes/files/apnt_298.pdf

这个BBS讲得也很好
http://firebbs.cn/thread-22706-1-1.html

其实生成的代码大不一定代表运行速度慢。事实上,用新编译器编译出来的代码,运行速度更快!
而且新编译器对静态检查更完善,可以找到很多bug
27#

[嵌入式] 【分享帖】用C++11开发STM32程序

[复制链接]
英雄1094167453
2018-10-5 13:46:48 只看该作者
66666666666
26#

[嵌入式] 【分享帖】用C++11开发STM32程序

[复制链接]
梯队队员舟田鱼
2018-8-10 16:37:44 只看该作者
大神做的是工程以C++为主,需要调用C文件中的函数。但是我现在做的是工程以C为主,要调用C++文件中的内容,感觉也是个大坑,还要自己慢慢摸索。
25#

[嵌入式] 【分享帖】用C++11开发STM32程序

[复制链接]
顾问wmd
2018-3-17 10:59:35 只看该作者
再补充一些 我为了保持和Cube的高度相关,当时是直接把main.c设置为C++源文件了 这样就算cube重新生成的时候也不需要修改很多其他的东西.不过偶尔加第三方库的时候main.c直接当成c++文件用还是有一点问题的 这个感谢楼主的经验 我到时候再移植一波 然后刚刚说的stm32f4xx_it.c要加extern "C"的时候也要先把这个文件在keil里面直接设置成C++文件.这样中断就可以使用C++特性了
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

触屏版 | 电脑版

Copyright © 2024 RoboMasters 版权所有 备案号 粤ICP备2022092332号

快速回复 返回顶部 返回列表