STM32 C++编程系列2.5:让Keil MDK工程支持现代C++特性及填坑

一、问题背景

利用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列依次选择如下图所示:
在这里插入图片描述
选择完毕后点保存,编译。这样就能避免陷入半主机模式的中断当中去了。

四、解决动态分配内存问题

再执行完上面的操作之后,再进行编译,则可以编译通过,运行程序,不使用io相关函数的情况下也不会进入半主机模式,若需要使用io相关函数则对fput等函数进行重定向即可使用(直接使用会导致程序进入Error_Handler)。然而新的问题又会挡在我们面前:动态分配内存问题(malloc和free)
我们知道,C++中new运算符的底层实现原理如下:
1、调用malloc函数开辟内存空间
2、调用构造函数生成对象

而delete函数实现原理与之相反:
1、调用析构函数做各种释放处理
2、执行free函数释放内存空间

因此在C++中,动态分配内存决定了一个对象是否能被靠谱的new出来。
然而经过了前面的配置后,由于我们不再使用microlib,因此开发环境在编译时将会连接标准C库的malloc函数和free函数,受限于单片机小的可怜的RAM空间,且没有MMU的帮助下,标准C库的内存分配函数对于单片机来说比较庞大,若是进行new和delete对象,很容易出现状态异常,进入Error_Handler。所以我们需要重定向new和delete操作符。
通常情况下,有两种方法去实现malloc和free:
1、自己设计实现内存池,并实现malloc和free函数(例如正点原子例程里的mymalloc和myfree)
2、用操作系统自带的内存管理功能实现

在这里为了方便介绍实现重定向动态分配过程,以使用操作系统自带的malloc方式来介绍。
我们使用freertos自带的pvPortMalloc()vPortFree() 来替换C标准库的malloc()和free()函数,这样做的好处是当内存被释放的时候会由操作系统来进行回收,具体的内存位置在操作系统申请的HEAP空间中(configTOTAL_HEAP_SIZE ),分配和回收方式由加载到工程中的heap_x.c确定。
在stm32cubemx中,我们将configTOTAL_HEAP_SIZE根据各芯片的RAM空间设置为合适的大小,并利用pvPortMalloc()vPortFree() 来重载new和delete运算符,代码如下:

#if USE_OS
#include <new>
void *operator new(size_t size) throw(std::bad_alloc)
{
    return pvPortMalloc(size);
}

void operator delete(void *pointer) throw()
{
    vPortFree(pointer);
}
#endif

其中,头文件包含了运算符new和delete的函数声明,我们在自己的程序中利用将new和delete运算符进行重载。至此,在程序中我们可以new和delete对象了。

  • 30
    点赞
  • 148
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
### 回答1: Keil MDK5作为一款强大的MCU开发工具,可以用于从头开始建立STM32 Project项目。下面是详细的步骤: 1. 打开Keil MDK5软件,点击“File”菜单,选择“New”→“Project”来创建新工程。 2. 在弹出的对话框中,选择“STMicroelectronics”作为Manufacturer,选择“STM32F4xx”作为Device。 3. 输入工程名称,选择工程存放路径,然后点击“Save”按钮。 4. 在“Project”窗口中,点击“Options for Target”来打开“Target Options”页面。在这个页面中,我们可以设置编译器、链接器、调试器等选项。 5. 在“C/C++”选项中设置编译器,一般选择ARMCC,同时可以设置一些编译器的选项,如编译优化等。 6. 在“Linker”选项中设置链接器,一般选择ARMLINK,同时设置链接器的选项,如堆栈大小等。 7. 在“Debug”选项中设置调试器,一般选择ST-LINK Debugger,同时可以设置一些调试器的选项,如Flash编程等。 8. 在“Target”选项中设置目标设备,选择STM32F407VG,同时可以设置一些芯片的选项,如时钟频率等。 9. 点击“OK”按钮保存设置并关闭“Target Options”页面。 10. 在“Project”窗口中,右键点击“Source Group 1”目录,选择“Add Existing Files to Group”。 11. 在弹出的对话框中,选择工程所使用的源文件(.c、.h等)。 12. 在“Project”窗口中,右键点击“Target 1”目录,选择“Options for Target”来打开“Target Options”页面。 13. 在“Debug”选项中,勾选“Use ST-Link”选项,然后点击“Settings”按钮。 14. 在“ST-Link Debugger”页面中,设置一些调试器选项,如芯片型号、连接方式等,然后点击“OK”按钮保存并关闭页面。 15. 点击“Build”菜单,然后选择“Build Target”来编译工程。 16. 点击“Flash”菜单,然后选择“Download”来下载程序到芯片中。 17. 程序下载成功后,可以进行调试和测试。 以上就是Keil MDK5从头建立STM32 Project项目的详细步骤。通过这些步骤,您可以快速创建STM32工程,并开始您的MCU开发工作。 ### 回答2: Keil MDK5是一款广泛使用的嵌入式开发集成环境(IDE),它可以用来开发多种类型的嵌入式系统,包括基于ARM Cortex-M处理器的STM32系列芯片。下面是使用Keil MDK5从头建立一个STM32项目的详细步骤。 1. 安装Keil MDK5 首先,需要从Keil官网上下载和安装MDK5。安装完成后,打开Keil MDK5 IDE界面。 2. 创建新工程Keil MDK5 IDE界面中,选择“File”→“New…”菜单,弹出“Create New Project”对话框。在该对话框中,选择“Device Database”中的STM32系列,然后选择芯片型号和开发板,并指定工程文件夹,并设置工程名称,最后点击“OK”按钮。 3. 配置工程 在相关设备和程序库之前,必须设定一些工程配置项。这些项包括所使用的编译器、产生的代码、和选项。在Keil MDK5的工程管理器中,会显示新建的工程。右键单击该工程,并选择“Options for…”命令选项。在弹出的对话框中,配置编译器和链接器选项,以及其他必要的信息。 4. 添加外设驱动程序库 要使用STM32芯片上的外设,需要编写相应的驱动程序库。可以在ST网站上下载相应的驱动库文件。下载好后,将其解压缩,并添加到Keil MDK5的工程中。具体操作是,在工程管理器中,右键单击“Project”条目,选择“Add Files…”菜单项,并选择下载解压后生成的文件,然后选择“Add”按钮,即可加入工程中。 5. 编写程序 使用Keil MDK5 IDE所提供的开发工具,编写所需的STM32程序代码。通过设定代码所用的宏、数据类型、和内 Core外的存储器类型信息,可以得出性能和体积。 6. 编译和调试 使用Keil MDK5 IDE所提供的编译工具将程序编译成可执行文件,并运行调试程序,检查程序是否正常运行。主要是在工程管理器中,右键单击“Project”条目,选择“Build Target”菜单项,以执行编译操作,查看编译结果是否正常,并可以进行一些简单的调试和排错。 以上就是使用Keil MDK5从头建立一个STM32项目的详细步骤。通过这些步骤,可以快速地建立一份STM32的程序,然后进行编译和调试。当然,在实际的项目开发中,还需要根据具体的要求进行一些调整和修改。 ### 回答3: Keil MDK5是一款非常常用的嵌入式开发环境,用于在嵌入式系统中开发、编译和调试。下面将详细介绍如何在Keil MDK5中从头开始建立STM32项目: 1.安装STM32支持包 在Keil MDK5中创建STM32项目之前,您需要先安装STM32支持包。您可以在Keil官方网站上下载并安装。安装完毕后,启动Keil MDK5。 2.创建新的项目 在Keil MDK5的菜单栏中,选择"File" -> "New Project",在弹出的对话框中选择"STM32F4xx"和"MDK-ARM"作为芯片类型和编译器类型。然后为您的项目选择一个合适的名称并选择存储的位置,最后单击"OK"按钮。 3.配置芯片参数和系统时钟 在创建新项目时,Keil MDK5会为您自动配置一些芯片参数。您可以在左侧的"Project"栏中选择"Options for Target"来进一步配置芯片参数,如GPIO、UART和SPI。同时你还需要配置系统时钟,以便更好地适应芯片型号。您可以在左侧的"Project"栏中选择"Manage Run-Time Environment"来更改时钟源和频率。 4.添加程序代码 将您的程序代码添加到项目中。可以在左侧的"Project"栏中添加新的源文件或在现有的源文件中添加代码。务必注意您的代码中所用的指令集是否与目标芯片所支持的指令集匹配。 5.编译和调试 在代码添加完成后,您可以通过编译和调试来验证代码是否正常工作。点击Keil的"Build"按钮来编译您的代码。如果出现错误,请确认代码是否正确并解决错误。如果编译成功,则可以使用Keil MDK5的"Simulator"或"Debug"功能来调试您的程序。 6.烧录 如果您已经完成了程序的编译和调试,可以通过烧录器将程序烧录到芯片中。选择"In-System Programming"后编译一下程序,然后你能通过烧录插件来将程序烧录到指定芯片上。 以上是在Keil MDK5中从头建立STM32项目的详细步骤。您只需要按照以上步骤一步一步进行操作,就能在Keil MDK5中成功开发和调试STM32项目。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值