发新帖本帖赏金 50.00元(功能说明)我要提问
12下一页
返回列表
打印
[学习资料]

软件框架设计好了,代码跨平台移植不再是噩梦!

[复制链接]
6121|29
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
dffzh|  楼主 | 2025-5-30 11:25 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 dffzh 于 2025-6-3 13:29 编辑

#申请原创#
@21小跑堂

做嵌入式产品的软件开发时,我们会经常遇到因为成本、交期或芯片资源紧张等原因更换MCU平台的情况,加上不同MCU厂商在芯片外设、寄存器和库函数接口等方面的命名规则和名称又不一样,这个时候就肯定会涉及到代码跨平台移植操作。其实,代码移植是一个比较耗费精力和磨性子的过程,可能会让人“发狂”;这个时候,如果你的代码框架在起初设计时就考虑了后续可能会出现的代码跨平台移植这个可能性,那你的代码移植工作量就会大大减少了。
那什么样的软件框架有利于代码移植呢?下面给出一个比较适用于刚出校门入职场的软件同仁们的参考框架,我们一起来看看吧!
代码一定要分层设计,切忌把全部文件放在同一个文件夹下面,最简单的就是区分一下代码层次:
应用层:主要实现业务逻辑,不涉及与MCU平台相关的操作;
MCU驱动层:可以称为BSP(板级支持包)层,主要实现MCU外设驱动代码;
外置芯片驱动层:主要实现与MCU通过总线等方式进行通信的芯片驱动代码;
固件库层:MCU芯片的固件库源文件;
协议层:如果有标准协议,可以单独建个文件夹存放。
根据以上描述,基本上可以按如下拓扑进行设计:

app文件夹下面以模块化的方式实现需要的应用功能,一个功能/模块对应一个源文件+一个头文件,可以用app_功能名称命名源文件和头文件:

main.c文件可以直接放到app文件夹下面。
bsp文件夹下面以区分外设的方式实现需要的芯片驱动,可以用bsp_外设名称命名源文件和头文件:

并且尽量用宏定义方式在头文件里申明GPIO和引脚配置信息,类似下面代码:

MCU芯片处理中断向量表的源文件也可以放到bsp文件夹下面。
driver文件夹下面以区分外置芯片的方式实现需要的芯片驱动,可以用芯片名称来命名源文件和头文件:

并且尽量用宏定义方式在头文件里申明与MCU平台相关的信息,包括GPIO和库函数操作等,后续移植时仅需要修改头文件即可,类似下面操作:


宏定义的越详细越具体,代码移植修改时会越简单越方便。
libraries文件夹下面存放固件库文件:
另外,在设计工程时,可以新建两个文件夹,把固件库文件区分开(外设文件+启动文件):


ethercat文件夹存放协议文件,直接用协议名称命名该文件夹即可,比如wifi、tcp_ip等:

通过以上的分层和解耦设计,在执行代码移植时,你只需要以下的几个操作步骤即可完成大部分的代码移植:
1、直接把固件库全部替换;
2、修改bsp相关文件,这块的工作量相对来说是最大的
3、修改driver里面的驱动头文件,其源文件不需要任何修改;
4、修改工程配置里的库文件包含信息。
通过以上的几个移植修改步骤,基本上就完成了代码跨平台移植,编译后可能还会出现个别报错,再修改修改就可以了,毕竟代码移植的第一步就是要让你的代码编译通过,然后再慢慢调试功能即可。

当然软件框架的设计还可以继续深入,比如把MCU底层配置抽象出来并形成一个独立的文件,这样外置芯片驱动的头文件可能都不需要修改了,而只需要修改MCU底层配置文件即可;或者把包括排序算法、滤波算法等通用的算法以API接口的方式封装起来并放到一个源文件里等等。

比如封装GPIO名称:
目前是在驱动代码头文件里按如下方式申明:
#define   IS3980S_GPIO   GPIOB
可以把GPIOB封装到单独的通用头文件(commonHeader.h)里,并按如下方式命名:
#define  IS3980S_MCU_GPIO  GPIOB
而驱动头文件里修改如下:
#define  IS3980S_GPIO   IS3980S_MCU_GPIO
如此操作后,代码移植时,只需要修改commonHeader.h文件即可。
其他宏定义的封装操作类似。

以上是作者针对如何降低代码跨平台移植的工作量的实操经验和拙见,希望对你有用!

使用特权

评论回复

打赏榜单

21小跑堂 打赏了 50.00 元 2025-06-12
理由:恭喜通过原创审核~期待您更多的原创作品~~

评论
21小跑堂 2025-6-12 11:31 回复TA
非常好的软件框架设计,不用每次更换平台都重头开始,不重复造轮子,文件的分类和分层设计理念非常合理,应该是说是走向高级软件工程师的必备能力。 
沙发
yiy| | 2025-5-31 06:41 | 只看该作者
是的,很多时候学会合理的管理代码是很重要的。

使用特权

评论回复
板凳
gaoyang9992006| | 2025-5-31 07:29 | 只看该作者
这就是顶层设计。

使用特权

评论回复
地板
dffzh|  楼主 | 2025-5-31 17:08 | 只看该作者
yiy 发表于 2025-5-31 06:41
是的,很多时候学会合理的管理代码是很重要的。

是的,初期尽量考虑全一些,后面维护成本大大降低

使用特权

评论回复
5
dffzh|  楼主 | 2025-5-31 17:09 | 只看该作者

专业呀

使用特权

评论回复
6
HXM1593| | 2025-6-2 09:27 | 只看该作者
那么,芯片的头文件是如何声明的,不应该是全部位置都用啦,哪个该放那个不该放,有时候搞不清楚

使用特权

评论回复
7
caigang13| | 2025-6-2 10:04 | 只看该作者
所以软件架构设计很重要啊

使用特权

评论回复
8
丙丁先生| | 2025-6-2 22:35 | 只看该作者
感谢分享

使用特权

评论回复
9
dffzh|  楼主 | 2025-6-3 09:26 | 只看该作者
HXM1593 发表于 2025-6-2 09:27
那么,芯片的头文件是如何声明的,不应该是全部位置都用啦,哪个该放那个不该放,有时候搞不清楚 ...

芯片固件库的头文件太多,有时候确实难区分哪些可以不放到工程;
一般情况下,头文件有包含通用系统级别的和指定外设的,所以还是需要开发者对头文件有一些认知才行。

使用特权

评论回复
10
dffzh|  楼主 | 2025-6-3 09:26 | 只看该作者

一起学习

使用特权

评论回复
11
dffzh|  楼主 | 2025-6-3 09:29 | 只看该作者
caigang13 发表于 2025-6-2 10:04
所以软件架构设计很重要啊

所以我一直觉得软件架构师牛呀

使用特权

评论回复
12
灵犀幻影| | 2025-6-3 10:21 | 只看该作者
非常赞同!代码分层设计确实能大大减少跨平台移植的工作量,这个框架设计很实用。

使用特权

评论回复
13
星空魔法师| | 2025-6-3 13:28 | 只看该作者
非常同意,分层设计确实可以大大减少代码移植的工作量。实际操作中,我发现将配置信息通过宏定义隔离出来,确实可以简化移植过程。

使用特权

评论回复
14
dffzh|  楼主 | 2025-6-3 13:30 | 只看该作者
灵犀幻影 发表于 2025-6-3 10:21
非常赞同!代码分层设计确实能大大减少跨平台移植的工作量,这个框架设计很实用。
...

感谢认可!

使用特权

评论回复
15
asdsfgwsafd| | 2025-6-4 08:32 | 只看该作者
不止是移植。
软件分层,模块解耦才能分解任务协同开发。
后期维护调试也更方便。

使用特权

评论回复
16
mxkw0514| | 2025-6-4 09:01 | 只看该作者
请问如何理解“解耦设计”呀?

使用特权

评论回复
17
dffzh|  楼主 | 2025-6-4 09:19 | 只看该作者
asdsfgwsafd 发表于 2025-6-4 08:32
不止是移植。
软件分层,模块解耦才能分解任务协同开发。
后期维护调试也更方便。 ...

是的,软件分层和模块解耦能做好的话,那就很优秀了

使用特权

评论回复
18
dffzh|  楼主 | 2025-6-4 09:21 | 只看该作者
mxkw0514 发表于 2025-6-4 09:01
请问如何理解“解耦设计”呀?

就是不同功能模块之间(或者理解为不同功能的源文件之间)尽量不要有相互的全局变量什么的进行读写操作,哪怕有,也要以函数封装全局变量的方式进行,不要直接暴露全局变量,这样代码移植时修改的地方就会太多,效率就会比较慢。

使用特权

评论回复
19
前功尽弃| | 2025-6-4 09:30 | 只看该作者
一直在往这个方向努力,但是总是写着写着就串在一起了

使用特权

评论回复
20
dffzh|  楼主 | 2025-6-4 09:41 | 只看该作者
前功尽弃 发表于 2025-6-4 09:30
一直在往这个方向努力,但是总是写着写着就串在一起了

只要往这个方向努力,就一定会实现的;
多参考C++的封装性设计以及多层宏定义实现等,可能就不容易串在一起了。

使用特权

评论回复
发新帖 本帖赏金 50.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

61

主题

755

帖子

8

粉丝