一、问题背景
利用STM32CubeMX建立的Keil工程中,默认是使用AC5(Arm Compiler 5)编译器的,该编译器仅支持C99标准和C++98标准,无法支持现代C++(C++11之后由于添加了大量现代编程语言特性而被称作现代C++),且AC5编译速度的慢也是有目共睹的。诸多因素之下,我们选用更新更强大的AC6(Arm Compiler 6)来给我们的开发(折腾)上一个新的台阶。毕竟C++11之后出现的大量新特性还是很香的,不在STM32这个平台上大显身手就可惜了。
比如强大的auto关键字:
auto ff = "hello";
比如lambda表达式:
auto fun =[=](int x,int y)->bool{return x%10<y%10;};
再比如基于范围的(range-based)for循环:
map<int,string> index_map{{1,"hello"},{2,"world"},{3,"!"}};
for(const auto &e : index_map)
{
HAL\_UART\_Transmit(&huart1, (uint8\_t \*)e.second.data() , e.second.length() , 0xff);
}
是不是感觉打开新世界的大门了呢?稍稍配置,STM32与现代C++的结合,体验一种新的开发方式。现在我们就来从STM32进入现代C++的世界吧。
二、开启步骤
1、点击进入工程配置对话框,
将ARM编译器改为编译器6,如图所示
这时C/C++选项卡会变成C/C++(AC6)
与AC5不同的是,这里的语言选项支持到C11和C++17,因此现代C++的语言特性大部分都可以在上面得到比较好的支持。如果在cubemx中添加了FreeRTOS支持的同学,到这里应该会收到数百个错误的提示。这时只需要将…Middlewares\Third_Party\FreeRTOS\Source\portable里的文件替换为cubemx的firmware库中GCC版本即可正常编译。
到这里开启工程支持就结束了,很简单是不是?
But!
仅仅这样配置完是运行不起来的,或者说运行起来会有各种问题。首先出现的就是一个大家熟知也困扰已久的问题:ARM的半主机模式。
三、解决半主机模式
STM32玩的比较熟的都知道,如果在工程选项中没有勾选上microlib支持又使用到一些和stdio相关的函数时,就会陷入一个很尴尬的问题,怎么debug一上来就停在一个地方进行不下去了?
BKPT 0xAB
当出现这个的时候,就说明你的CPU就陷入了半主机模式。具体半主机模式是什么,很多地方解释了我也就不再赘述。在一般的C程序中,我们可以用两种方式解决这个问题:
一、使用microlib库
二、重定向stdio.h里的方法,并在工程里加上如下代码:
#pragma import(\_\_use\_no\_semihosting) // 确保没有从 C 库链接使用半主机的函数
\_sys\_exit(int x) //定义 \_sys\_exit() 以避免使用半主机模式
{
x = x;
}
struct \_\_FILE // 标准库需要的支持函数
{
int handle;
};
/\* FILE is typedef ’ d in stdio.h. \*/
FILE __stdout;
在网上的各种资料以及正点原子的例程中,我们都可以看到有这一段代码用来解决半主机模式的问题。在传统的C程序当中,这两招是公认的终极解决办法,然而这两招在AC6与C++上就不好使了,会报各种各样的错:
比如引用microlib后报的错:
再比如加入重定向代码后出的错(不用试图改错,改好了还会有更多的报错等着):
因此,就只能使用另一种办法来解决该问题:使用keil补丁。
Keil补丁
估计是ARM开发团队也意识到这个问题了吧,在后来的版本中可以自动添加进官方版本的重定向代码,在补丁中可以选定是进入中断、进入错误回调函数还是使用用户自定义实现版本,于是就有了下面的方法:
一、点击在这里插入图片描述按钮进入运行时环境配置界面:
二、做些配置
依次进入Compiler->I/O,将里面的STDERR、STDIN、STDOUT勾选上,并将variant列依次选择如下图所示:
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新