用C++开发STM32程序

今天这篇文章有点复杂,大家要注意一点看啦!

我们知道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工程都会自动链接这个系统自带的库。

用C++开发STM32程序_第1张图片

它就是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++开发STM32程序_第2张图片

刚才也说过我们要实现真正的C++编程,就不能链接microlib,如果不链接microlib,就会默认链接到我们的C/C++标准库。

现在开始,首先依然是使用STM32CubeMX生成一个带串口的工程,阿圆有依旧是STM32F437ZGT6,工程名为ARMCCTest,要使用完整的C++11特性就必须使用AC6,这里把ARM Compiler设置为V6.7,并勾掉Use MicroLib

用C++开发STM32程序_第3张图片

这里根据ARM官方的建议,检查下Short enums/wchar是否勾上

用C++开发STM32程序_第4张图片

这样就设置好了。

但是呢,如果就这样去编译,会有一堆的编译错误

主要是__weak编译失败

AC6己经不支持直接声明 __weak了,需要使用 __attribute__((weak))替代。这里不建议使用全局替代的方法, 如下图所示

用C++开发STM32程序_第5张图片

因为如果你的的工程里有包含了C++文件,这种方法可能把系统库里的__weak也给替换了,曾经吃过大亏!结果都重装KEIL了

好的,为了测试C++11的功能,我们新建一个CppTest.cpp文件,为了保持和C的兼容性呢我们把main挪到了cpp文件里,将原来Keil生成的main改为cmain即可

用C++开发STM32程序_第6张图片

用C++开发STM32程序_第7张图片

这里看到有一个Test类,这就是我们需要对C++11特性进行测试的类

用C++开发STM32程序_第8张图片

这里面还包含了一个Base和Derived类

用C++开发STM32程序_第9张图片

这样一个简单的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

稍微进行小修改,把它重定向到串口就可以啦!

用C++开发STM32程序_第10张图片

现在就可以把代码编译运行一下,从SSCOM看到代码正常运行并输出了log

用C++开发STM32程序_第11张图片

都运行成功了!

要问为什么没有使用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!

用C++开发STM32程序_第12张图片

大家还Hold住吗!哈哈!

你可能感兴趣的:(STM32学习笔记,C++学习笔记)