数码之家

 找回密码
 立即注册

QQ登录

只需一步,快速开始

微信登录

微信扫一扫,快速登录

搜索
查看: 11649|回复: 72

[ARM] 用C++写单片机程序 STM32F103 + 自建固件库 + FreeRTOS 用gcc编译器和newlib(1篇)

[复制链接]
发表于 2019-8-17 18:22:59 | 显示全部楼层 |阅读模式
本帖最后由 freemancn 于 2019-8-17 18:46 编辑

      作为论坛的新人,先自我介绍一下。本人有10年的Win平台开发经验,从VS6.0一直用到VS2019,主要使用C#构建程序。在安徽某大学任教C语言程序设计7年,C语言自然是滚花烂熟。由于工作需要或者说是个人爱好,转战单片机。刚开始学习也是51+Keil用C语言开发,既然是学习实现的功能并不复杂,编写的代码量也不大,但还是体会到什么是一夜回到解放前。Keil的代码自动完成功能太弱鸡,如果做正式的项目效率会非常低。当时也只是想想而已,因为知道自己并不会去做实际的项目。之后当然就是学习STM32了,选择STM32主要是看中了中文资料多,学习人数多学习氛围好。STM32十足让我惊叹,比51复杂N倍的体系架构,超多的片上外设,还有如此低廉的价格。深入学习后发现还是Keil+C语言,至少市面上99%的学习都是基于这一框架的。非常的失望,非常的不适应。因为之前用C#开发Win应用,肯定是面向对象的开发思路,因为.NET Framework(相当于STM32的固件库)就是OO(面相对象)设计的,这么多年用下来,也深深的体会到OO的优势。不光是程序设计思路,还有就是IDE(集成开发环境)对开发者的重要性。我独自开发的Win应用最大的有10万行代码,我可以很轻松的构建,还能很轻松的完成代码维护,这里的代码维护指的是修订BUG,优化功能,增加功能,版本迭代等等。

      STM32F103的主频已有72MHz,复杂的系统架构,超多的片上外设。想要喂饱这个MCU或者说是发挥出它强大的功能,肯定是需要大量代码的。当代码数量达到一定规模,自然要面对代码结构的问题。用Keil+C可以做,完成需要的功能肯定没有问题,而且现在绝大多数人都在这么做。但是C语言是面相过程的语言,对代码结构毫无帮助,毫无益处,因为无计可施。达到一定规模后,代码逻辑估计只有设计者很清楚,别人要想看懂是一件很耗费时间的事情。导致这一结果的原因是有大量的宏,更可怕的是宏嵌套、使用全局变量,这个变量会被多少函数共享,在什么时候会被改变分析起来很头疼、大量的函数,这些函数在语言层面是相互独立的,但逻辑上可能是有联系的,在语言级并没有这种逻辑关系的表达。就像官方的HAL库,我读起来想死的心都有。不是我读不懂而是读懂这些我付出的时间代价太大,要在OO思路下,这个要轻松N倍。时间就是金钱,效率就是生命。官方的HAL库其实就是想实现一个硬件抽象层,让开发者对于不同型号的MCU有一个统一的应用层开发界面,提高代码的移植性,缩短开发周期。想法是好的,做法是失败的,因为HAL库还是再用C语言编写,硬是用C语言套OO思路,代码恶心到极致。这也就是STD库还是有人在用的原因。如果使用真OO就可以把逻辑上有关联的函数组织到一起,将一些全局变量限定在部分函数中共享,其实这就OO中的封装,是语言层面提供的支持。还有要吐槽的地方就是IDE,VS的代码自动完成功能真的很好用,只要你按下任何按键都会出现提示列表,按下空格自动填充你还没有输入的内容,还有参数列表的提示。带来的好处就是,我不需要记住所有函数的名称和参数列表,我只要有一个模糊的映像,输入代码的时候IDE协助我完成。让我专注于逻辑思路,代码只是完成逻辑思路的工具而已。对语言再熟悉,对函数再熟悉,没有一个好的逻辑思路仍然写不出优秀的应用。不光是代码自动完成,还有代码着色,代码折叠,代码重构等等IDE功能,对于开发真的是不可或缺。Keil可能也有这方面的支持,但和其它一些IDE相比真的太弱了。再次重申一遍,时间就是金钱,效率就是生命。Keil+C可以吐槽的地方还有很多很多,我可以给你说一整天,我并不想开吐槽大会,只是想告诉大家其实可以有更好的选择。

     说一下代码效率问题,这可能是大家非常关注的地方。绝大多数人会认为C++的时间效率不如C,但是你要知道C++是C的超集,使用C++开发并不是什么地方都必须C++,你任然可以写C函数,任然可以写嵌入汇编代码。C++的效率损失主要是函数调用,C语言中会将参数压栈,而C++对象函数除了压栈参数以外还要压栈一个this指针,多一个32位的变量而已。表面上看是多了一个参数,但事实上呢?C语言函数可能需要4个参数,而对象函数的这个this指针却能代表这4个参数,因为C++通过这个this指针去访问私有变量,而这些私有变量恰恰是C函数的那4个参数。以上的说明可能过于抽象,你现在未必需要知道细节,你只要明白一点,效率的损失不是绝对的,有时却是一种效率的提升。再高级一点的效率损失来自于多态。在C99里面已有函数参数的多态支持,即使相同函数名但参数不同,调用时根据给定参数自动选择对应的函数。这种多态在C++里面也是存在的,但这种多态是在编译时完成的,对运行效率毫无影响。而虚函数多态的效率损失才是重点,当使用基类指针指向一个子类并调用虚函数,实际运行的时候会确定实际对象的类型去调用不同版本的虚函数,这需要在运行时查找虚函数表来完成,多了一个查找的过程,在内存中多了一份虚函数表。但是这种特性有助于实现一个优秀的代码结构或设计思路,用纯C可能实现不了或者实现了效率也未必比C++来的高效,而代码的逻辑和结构肯定没有C++的优雅,构建的速度也没有C++来的快。对于虚函数的采用是选择性的,没有什么项目在任何位置都需要虚函数。而一些普通的代码,例如:int a, b; a = 10; b = a + 200; if、for......不管是用C还是C++生成的汇编代码都是一致的。第二是空间效率,上面也分析了时间效率,所以空间效率可能有所损失,但也不是绝对的。当你用到一些特性的时候,执行的代码量必然增加,所以固件的体积肯定会有所增加。C++还有个STL库,里面实现了很多基础类,这些基础类可以直接使用或者进行再封装。当你使用这个库时,固件体积会极速增加。对于一些Flash只有64K或更小的MCU,可能有点紧张。但对于更大容量的Flash完全就不是问题了。使用这个库的好处就是,更少的BUG,更快的构建速度。这也是选择性的,你可以根据实际情况自由选择。而C语言中的常用库,例如printf、abs、floor等在C++中也是可以用的,且不会因为你是C++这些库函数就发生变化。总结起来就是可能会带来一些效率的损失,这些损失大部分是选择性的,当你选择牺牲性能的同时会得到C语言无法实现的功能,得到优雅的代码,得到清晰的逻辑,得到快速的构建。对于当今的MCU性能的损失往往都是可以接受的,你能不能喂饱单片机反而是个问题。当你在C++中需要极致性能的时候,你任然可以像C语言一样,该干嘛干嘛。

      互联网上可以找到的资料实在是少之又少,断断续续搞了2年,现在已经完整构建了整个环境,打算写一个连载。这是第一篇,主要是阐述这种开发环境的优势。后面将陆续给大家分享开发环境的搭建,为什么要自建固件库,如何自建固件库,FreeRTOS如何与C++联合使用,newlib中如何实现printf重定向到串口,以及在实践过程中遇到的各种零碎的问题。随着芯片科技的不断进步,MCU性能的进一步加强,我相信这种环境将是未来的主流。也希望一些技术大牛不要再保守秘密了,把真正的技术都分享出来,彻底提升MCU编程。目前我已在用这个环境做实际的项目了,下面给一张开发环境的截图。
能回复的回复一下啊,让我有写完整篇的动力。



本帖子中包含更多资源

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

x

打赏

参与人数 17家元 +337 收起 理由
xinxinwx + 2
缘起缘灭123 + 15 安徽那个大学 我是合肥滴
smfox10 + 40 行动支持!拜读大作
invent + 3 優秀文章
cala4a5a7a0a + 30 good morning teacher freeman
待定d + 20 精彩回帖
wenxueroom + 20 虽然看不懂
飞向狙沙 + 20 優秀文章
jxcnj + 3 優秀文章牛人,希望能出成果
jpdd521 + 20 一直没有研究单片机代码,就是因为环境不好.

查看全部打赏

 楼主| 发表于 2019-8-17 19:17:50 | 显示全部楼层

后续会逐步介绍环境搭建、设计思路、代码也会贴出来一部分的,都是关键性代码。至于开不开源我认为不重要。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-8-17 19:31:10 | 显示全部楼层
la45088d1 发表于 2019-8-17 19:25
我喜欢极致效率,所以我只用ASM,至少现在为止。
连FFT都能用ASM写出来,当然不是我,我还不知道有什么是AS ...

任何语言都会转换到ASM,在硬件如此强大的今天如何快速构建应用是我追求的目标。软件应该从2个方面衡量效率,一就是代码自身的执行效率,二是构建效率。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-8-17 23:09:03 | 显示全部楼层
amo73 发表于 2019-8-17 22:15
咋看有些道理,但是实际……不知楼主能否听的进去?
任何技术都要先谈定位。系统、OO、数据库、框架……对 ...

      这些道理不用你说我也很明白的。世界上也存在大量的C语言应用案例,而且是非常成功的应用案例。我并不是整出一整套开发系统,而是如何更好的利用现有的开发环境与思路。你即使要我整我也整不出来。我是从OO思路转到MCU的,进入这个领域后各种的不适应。在Keil+C的环境下我失去的太多了,反观OO我对其有了更为深刻的理解,我是想找回我失去的哪些便利,哪些不能在MCU中使用的设计模式,不能在MCU中实现的代码构建方法。我相信从事过OO开发的人与我有同样的想法。在我将要介绍的开发环境下,即使不用OO思路也比Keil方便N倍。况且整套方案中的核心gcc编译器用的可是ARM的亲儿子,是ARM自己干的。GCC编译器的地址是这个https://developer.arm.com/tools- ... nu-toolchain/gnu-rm    有这样的思路并不是想比C语言作出更多的功能,而是利用新的IDE和设计思路提高生产效率。结合C++ C和汇编的所有优势,有的放矢,而不是一根筋的为OO而OO。在国内的论坛,提出这样的思路往往都会遭到大量的质疑与反驳,这我也早有心里准备,但我希望大家能放下偏见与思维定式。反观国外,这样的话题大家聊得都非常开心。而且很多IDE中都带有OO的例程,其实就连Keil也是支持C++开发的,况且现在的MCU性能足够支撑OO开发,那何必不做一次有益的尝试呢?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-8-18 00:06:41 | 显示全部楼层
40560335 发表于 2019-8-17 23:57
不如直接搞类似arduino一类的,搞个Python或者JAVA的那才叫牛逼,那才叫高效,否则就只能自己一个人玩玩, ...

大哥做不到啊。当我写完整后,你或许会发现GCC还是很友好的。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-8-19 20:28:02 | 显示全部楼层
wu314296988 发表于 2019-8-19 15:29
不管怎么结果怎么样,支持楼主这样的实干家,相信不论对楼主还是对我们大家都将多有裨益。 ...

其实已经有结果了,所有的问题都解决,不过还是存在一些小瑕疵,是IDE方面的BUG。而且现在已经在用整套体系做项目了。只是需要一点时间将所有的一切整理成一份说明分享给大家。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-8-20 11:46:58 | 显示全部楼层
飞向狙沙 发表于 2019-8-20 10:04
顶楼主,合适自己的就是最好的,在满足自己的基础上再面向大众,至于谁接受就看谁感兴趣了。之前对 ...

:handshake:

eclipse 是可以在线调试的,还可以查看寄存器.比Keil来的漂亮.至于效率,我用C++写的代码比官方库来的快,因为我重写了库,我在反汇编下做了对比,我的库操作一个寄存器在O0状态下要4行汇编,官方的LL库要10左右,具体的看我后面的文章,正在准备中.

本帖子中包含更多资源

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

x
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-8-20 11:48:23 | 显示全部楼层
281421065 发表于 2019-8-20 07:28
vs之前装过2015的,感觉版面很强大,就是占用空间太大,有什么解决方法?

升级你的硬盘
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-8-20 11:49:14 | 显示全部楼层
skywolflin 发表于 2019-8-20 07:58
楼主好,我学习C#好几年了,由于时间关系和其他原因,一直不得其门而入,楼主能不能推荐一下入门教程?谢谢 ...

你去看一下微软的官方课堂以前叫WebCast.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-8-23 12:27:39 | 显示全部楼层
netbeetle 发表于 2019-8-23 10:18
模块化的开发是便于代码的快速移植和项目的快速开发,这就是官方库的魅力,实际上就算自己用寄存器开发, ...

OO思想和结构可以更好的实现模块解耦、代码重用、以及代码维护,这不管是面向过程还是面相对象都在追求的东西,除非你无视<<软件工程>>.你说的只是OO的封装特性,这只是OO的皮毛。精髓在于继承和多态。OO单片机在国外是很成熟很自然的事情,例如mbed,可以多看看国外的论坛.在国内谈这个事情绝大多数人都会觉得奇怪,但到底不对不对由时间来说明.
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-8-23 16:36:10 | 显示全部楼层
HAL库我看了啊,没有看全部,我看的最多的是F103的USB封装。HAL是支持被C++调用的,但本身实现用的语言是C,却又想实现某些OO的特性。所以代码看上去很恶心,用结构体+函数指针完成封装和多态的特性。用C++的话,这样的代码将会是多么的优雅。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-8-24 11:35:57 | 显示全部楼层
netbeetle 发表于 2019-8-24 10:18
可以看出你可能不了解HAL到底是个什么东西,说白了,HAL只是ST对底层驱动的一个封装,目的是为了让程序员 ...

用了C++以后不是什么地方都要求必须是OO,任然可以继续用C或嵌入式汇编。见机行事,有的放矢。肯定不是,也不能为OO而OO,在我做的实际项目中是C++、C、ASM混合的。OO解决的问题不是功能层面的问题,而是代码构成方面的问题。就像你说的HAL,HAL的全称就是Hardware Abstraction Layer,设计理念你描述的很正确,但是你知道吗,这种设计模式在C++里面实现是有专门的语言级支持,是有专门的关键字实现这种理念的。HAL应该是由Abstract Class构成,然后Application layer完全只依赖Abstract layer,之后通过直接更换Driver layer实现不同硬件的适配。举个例子,有一个应用控制一个显示屏实现菜单显示和相应操作,如果按这种3层设计,面对不同屏幕时只需要替换不同的Driver layer就可以实现对SSD1306或ST7735S或更多型号的适配。实际的代码变更简单到只需要调整一条语句。当然如果长时间只跟固定的硬件结构打交道的确没必要,如果你是一个应用开发商,每天跟不同的硬件打交道呢?最后还是归结到一点根据自己的需要,有的放矢,不是一根筋的写代码。C语言可以实现所有功能,但有些时候OO一下会变得更好。Github有更专业的STM Abstract layer,如果觉得不正式不专业mbed可以了解一下。我重写驱动层的自然有我的目的,而且重写并不会给我增加负担,写出的驱动库也只是给我自己用的。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-9-9 20:33:06 | 显示全部楼层
钟义亭 发表于 2019-9-9 16:51
半移植  單片機 會變好用
全移植 變成OS   就不是單片機
移植  就為了好用的



用OO是为了更高层级的复用

本帖子中包含更多资源

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

x
回复 支持 1 反对 0

使用道具 举报

 楼主| 发表于 2019-9-10 10:45:56 | 显示全部楼层
njshenxian 发表于 2019-9-9 21:00
环境很重要,C并不是专门为单片机的,事实上,汇编才是单片机的底层语音。C只是更加口语化的工具,编译的时 ...

同志请多多学习,多多了解业界动态。国外论坛可以逛一逛,mbed了解一下,《软件工程》这么课多学学。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2019-9-10 17:27:14 | 显示全部楼层
钟义亭 发表于 2019-9-9 16:51
半移植  單片機 會變好用
全移植 變成OS   就不是單片機
移植  就為了好用的



单片机OO不是我异想天开,这是软件开发的潮流。

本帖子中包含更多资源

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

x
回复 支持 反对

使用道具 举报

 楼主| 发表于 2020-2-3 05:05:35 | 显示全部楼层
顶起此贴,希望有更多的人来拌嘴,消磨这战疫放假时光。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册 微信登录

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2025-7-22 00:42 , Processed in 0.234000 second(s), 14 queries , Redis On.

Powered by Discuz!

© 2006-2025 MyDigit.Net

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