MDK中用C++开发STM32

作者: 良知犹存

​作者:良知犹存

转载授权以及围观:欢迎添加微信:Allen-Iverson-me-LYN

前言

最近想开发一段单片机的代码,代码本身有很多的重复元素,这重复定义的一些结构体使用起来有些繁琐,所以就想用C++开发,C++的继承 模板类可以很容易的解决这些问题。因为在单片机运行,习惯用MDK或者IAR这些软件。但是这些软件都是默认C开发的,用C++开发需要重新配置,有些麻烦。但是还是试了试,做了一个小demo供大家参考。

代码文件传到的github中去了,大家有兴趣可以参考一下

https://github.com/conscience-still/MDK-Cplusplus--LED

一、STM32CubeMX生成底层代码

因为是做一个demo,不需要很复杂,就用cubemx生成了一个简单的串口和IO控制的MDK代码,用了精简的LL库,具体实现就不讲了,详细操作可以看CubeMX配置的一些文章。的名是:良知犹存

二、进行IDE的C++配置(去掉C环境的配置)

1.首先打开MDK软件,去掉use microlib 勾选,这个一个C的依赖库,但比标准的库小,它可以减少C代码的大小。CubeMX生成的文件默认选择此项。因为这个精简库不支持C++,所以们需要去掉此项功能。

2.Options for Target 再点C/C++ 在下边的Misc Controls 中输入—cpp

3.去掉C99 mode选项

三、代码中C++的编写注意

  1. IDE中的编译器的这个工程时候,当文件后缀是C的时候IDE会使用C编译器进行编译,如果文件后缀是CPP则IDE使用C++编译器进行编译,工程包含的头文件是使用C++编译器进行编译的,不过头文件声明的还是C文件的符号,所以IDE会无法正确编译链接。此时们应该将头文件所有声明C符号的部分用预编译宏加extern “C” { }的形式包含起来,告诉编译器该段要使用C编译器进行编译。只包含需要进行C编译的部分即可

    ifndef MAIN_Hdefine MAIN_H​ifdef cplusplusextern “C” {endif​/ Includes ——————————————————————/include “stm32f0xx_ll_crs.h"include “stm32f0xx_ll_rcc.h"include “stm32f0xx_ll_bus.h"include “stm32f0xx_ll_system.h"include “stm32f0xx_ll_exti.h"include “stm32f0xx_ll_cortex.h"include “stm32f0xx_ll_utils.h"include “stm32f0xx_ll_pwr.h"include “stm32f0xx_ll_dma.h"include “stm32f0xx_ll_usart.h"include “stm32f0xx_ll_gpio.h”​ifdef cplusplus}endif

2.设置需要C++编译的文件,这时候有两种方法实现。

1>.在代码文件的界面,选择文件右击选择Option for Files “你点击的文件”,然后设置file type为需要的C++

2>.直接将文件改为.cpp文件,重新添加,此时候IDE自动进行C++编译

第二种方法简单快捷,但是第一种方法虽然麻烦,但是有个好处,们不需要修改文件名称,这样STM32CubeMX下一次生成代码就不会在生成相应名称的C代码了。

3.将中断服务函数添加 extern “C” 的标识,因为C++中无法直接识别中断函数,所以用C的方法进行设备编译。而在Cpp文件中引入C的部分代码,需要进行extern “C” { }进行修饰,否则不能通过编译链接。

四、C++实现时候遇到的情况

​ 1.写了个类没有注意到写成了虚函数,其他处也没有继承定义这个虚函数,导致编译错误,为什么把这个问题写出来呢,就是因为MDK中C++的报错没怎么遇到过,查了挺长时间,才发现这个问题的。

c++test\c++test.axf: Error: L6218E:Undefined symbol vtable for STM32_TEST::TestGPIO (referred from main.o).

把类中的虚函数改为定义好的函数即可。

2.因为把串口初始化都放在类中实现,想进行类的构造的时候进行串口数据的打印,但是网上查询得知,MDK不支持std的流打印输出,所以就用sub和super补丁函数,进行系统main函数执行前进行串口的初始化。

这是一种特殊模式:用于有一个已经存在且不能被改变的函数 的情况。使用这两个模式可以帮原函数打补丁。如存在一个函数foo();

$Sub$ $foo :定义的新功能函数,在foo()函数之前/后使用$Sub$$foo 可以添加一些新的程序代码。

$Super$ $foo :就是原始的未修补的foo函数,使用这个$Super$ $foo函数将直接跳转到foo()函数。


具体教程可以看ARM官网的资料学习哈,http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0377g/pge1362065967698.html。

因为super与sub函数属于c所以们在cpp文件下需要添加extern"C"进行编译才行,否则就要出现如下问题了,这些都遇到过,给大家把雷趟了一遍。


3.最后的一个bug,STDIO的初始化。

本来一个简单的C++程序就写完了,主要就是运行环境,但是程序收录进去之后无法工作,并且在硬件调试下明显看到系统到了__main之后不知道跑哪里去了,F5全速执行几次程序才有机会正常运行,这就很奇怪了,后来在网上找资料,终于找到问题所在了,在以为博主的文章看到,他最后找到问题原来是:

事实上本人也找了近两天的时间才找到解决办法,一开始认为是heap和stack没有初始化好,尝试了好久均未成功,后来在网上得到启发,这个问题是出在STDIO初始化上。

如果要使用C/C++标准库就要对其STDIO进行Retarget的,很简单,但却是非常关键的一步,就是这么一回事啦。

按照他的操作然后程序就可以正常运行了,下载ARM官方的retarget文件,并加入到工程当中。下载链接:

http://infocenter.arm.com/help/topic/com.arm.doc.faqs/attached/3844/retarget.c

然后将里面的串口读写按照现有的硬件需求进行重写就可以了。如下代码所示:

char UART_read(void);void UART_write(char ch);    char UART_read(void){  return 0;}void UART_write(char ch){  while(!(USART2->ISR & USART_ISR_TXE)){};   USART2->TDR = ch;}

五、最后测试的一些体验与感想

刚开始想用C++在MDK中开发是因为,有些个需求的功能C++特别符合,但是在调试这个demo过程中,发现使用的单片机容量太小,一个头文件的包含就让一个只有串口加几组IO控制的最小程序代码膨胀到了32K,而去掉该头文件,代码缩小到了5K。

代码过大是c++的依赖项过多,而C++ 中模板类 、虚拟继承 、STL库等精华由于依赖的问题都不建议在单片机中用,代码膨胀的时候单片机吃不住。所以C++虽好,可不一定适合小容量的单片机,大家需要按照自己的功能进行有效的使用C++,精简使用的依赖,这个可以通过每次编译的生成的.map文件进行增该删,其次对于C++中内存以及代码扩增一些基础知识需要熟悉,负责很容易代码膨胀,导致们的程序无法在单片机使用。

这就是分享的在MDK用C++开发的demo,里面代码是实践过的,如果大家有什么更好的思路,欢迎分享交流哈。

更多分享,扫码关注

微信:Allen-Iverson-me-LYN

原文作者:良知犹存

原文链接:https://www.cnblogs.com/conscience-remain/p/12841096.html

更多推荐

更多
  • IOS开发者的AWS和DevOps指南-十、iOS 应用开发的持续交付渠道 Jenkins 管道公司,AWS 代码管道,摘要,Fastlane 测试阶段,AWS 设备场测试阶段,Fastlane 构建阶段,Fastlane 交付阶段,为 AWS 代码管道设置 Jenkins 环境,在 AWS 控制台上设置代码管
    Apache CN

  • IOS开发者的AWS和DevOps指南-九、将 AWS 设备群用于测试 AWS 设备群简介,为应用测试生成 ipa 包,设置设备场项目并安排测试运行,AWS 设备场 Jenkins 插件,使用 Jenkins 自动化 AWS 设备群测试,摘要,使用 AWS 控制台安排测试运行,使用 AWS CLI 计划测试
    Apache CN

  • IOS开发者的AWS和DevOps指南-八、使用 Fastlane 自动构建、测试和发布 使用 Fastlane 匹配和亚马逊 S3 设置代码签名,设置 Jenkins 环境,用 Fastlane 自动化测试和构建,自动发布到 App Store Connect,摘要,正在初始化 Fastlane 匹配,在亚马逊 S3 存储
    Apache CN

  • IOS开发者的AWS和DevOps指南-六、使用 AWS CodeCommit 的源代码管理 Git 基础,创建 AWS 代码提交存储库,在 AWS 代码提交中添加源代码,AWS 代码提交中分支,AWS 代码提交中的拉请求,摘要,Git 安装,初始化 Git 存储库,记录对 Git 存储库的更改,克隆和使用远程 Git 存储库,
    Apache CN

  • IOS开发者的AWS和DevOps指南-七、将 AWS CodeCommit 与 Jenkins 集成 Jenkins 代码提交插件,设置集成组件,配置插件,使用 AWS 代码提交源创建 Jenkins 作业,摘要,通过 AWS 控制台设置组件,通过 Terraform 设置组件,测试 AWS 代码提交插件, 当应用源代码存储在 AWS
    Apache CN

  • IOS开发者的AWS和DevOps指南-四、AWS 上的 macOS 服务器 Amazon EC2 Mac 服务器,部署 Amazon EC2 Mac 服务器,连接到 Amazon EC2 Mac 服务器,使用 Amazon CloudWatch 监控 EC2 Mac 服务器,清理 Amazon EC2 Mac
    Apache CN

  • IOS开发者的AWS和DevOps指南-五、在 macOS 实例上设置开发工具 增加 macOS 实例宗卷大小,设置 Xcode,陷害 Jenkins,建立 Fastlane,设置 GitLab,摘要,Xcode 命令行工具,供应 Jenkins 控制器,EC2 Mac 实例作为 Jenkins 构建代理,创建 G
    Apache CN

  • IOS开发者的AWS和DevOps指南-三、亚马逊网络服务(AWS)上的 DevOps 三、亚马逊网络服务AWS上的 DevOpsAWS 上的持续集成,AWS 上的连续交付,基础设施作为代码,监控和记录,摘要,AWS 代码提交,AWS 代码构建,AWS 程式码人工因素,AWS 代码部署,AWS 代码管道,AWS 云阵,AW
    Apache CN

  • IOS开发者的AWS和DevOps指南-二、从 Xcode 到 App Store Connect 标识符,应用商店连接,从 Xcode 上传构件,测试和发布,摘要,截图和应用详细信息,TestFlight 软件,应用提交, 在前一章中,我们看到了如何使用 Xcode 在物理 iPhone 设备和模拟器上构建和运行应用。我们将进一步探
    Apache CN

  • IOS开发者的AWS和DevOps指南-一、iOS 应用开发基础 开发要求,迅速发生的,摘要,苹果个人计算机,苹果开发者账户,Xcode 简介,创建应用,构建应用,Xcode 命令行工具, 为了开发 iOS 应用,苹果提供了几种工具和资源。iOS 应用可以用原生编程语言开发,如 Swift 或 Obj
    Apache CN

  • 近期文章

    更多
    文章目录

      推荐作者

      更多