打印
[学习资料]

又换MCU平台了?驱动代码怎么玩可以达到修改最小化!

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

#申请原创#
@21小跑堂

做嵌入式产品的软件开发时,我们会经常遇到因为成本、交期或芯片资源紧张等原因更换MCU平台的情况,加上不同MCU厂商在芯片外设、寄存器和库函数接口等方面的命名规则和名称不一样,软件上肯定是避免不了要重新搭建和开发调试;这个时候,如果你的与MCU平台相关的底层驱动代码的复用率高,那你的开发工作量就会大大减少了。
下面作者就以实际开发案例与大家分享一下怎么样设计驱动代码以提高代码复用率,主要是针对MCU基于外围芯片的驱动代码与MCU配置相关的阐述,供大家参考和使用。
项目上用到了IS3980S芯片和U74HC595芯片,前者是输入:读取数字输入状态,后者是输出:驱动LED显示。
MCU和IS3980S芯片之间有如下4根信号线连接通信:

那在设计IS3980S的驱动代码时,这几根信号线就是实现为MCU的GPIO的定义和配置;
在通过GPIO口读写数据时,怎么样设计可以更方便代码以后的维护呢?
在C语言中,我们可以用宏定义#define的方式来实现GPIO口的绑定以及用宏函数实现GPIO的数据读写,相关代码如下所示,定义在is3980s.h头文件里面:

虽然这个项目里几个信号线引脚都是绑定在GPIOB,但为什么没有用IS3980S_GPIO,而要对每个信号线引脚单独加个宏定义来指向GPIO呢?这样设计的话,如果后续硬件更改了GPIO口,每个信号线引脚你只需要修改一个地方即可,方便快捷安全。如果MCU使用的引脚很多,不要觉得这种方式繁琐,反而更要用这种方式实现,后续维护时,你会很轻松,哪怕换了MCU平台,你一般只需要修改头文件里对应的宏定义名称即可,驱动代码源文件is3980s.c则不需要做任何更改。源文件里的函数实现举例如下:

总之一句话:
你的芯片驱动代码源文件里尽量不要直接使用MCU平台底层的东西,改用宏定义等方法来封装到头文件里;
宏定义功能越具体越详细,后续代码维护就越方便越简单,出现Bug的可能性就越低。

再举个例子,加深大家的印象:
MCU和U74HC595芯片之间有如下4根信号线连接通信:

同样地,我们依葫芦画瓢,在u74hc595.h文件里就可以按如下代码定义这几个信号线引脚:


源文件里的一个函数实现如下:

这样,无论后续更换了什么MCU平台,你要做的工作就是把头文件里的相关宏定义更改一下即可,除非是什么比较奇葩的MCU平台,那另当别论了。

通过以上这种提高芯片驱动代码复用率的方法,无论是在代码修改量方面,还是在解决MCU平台移植和编译时报错问题多方面,或者是代码可读性和可维护性等方面,你将会深深受益,不信的话,你可以试试!

使用特权

评论回复
评论
dffzh 2025-5-30 14:56 回复TA
@21小跑堂 管理员,你好,求原创审核哦! 
沙发
734774645| | 2025-5-22 14:50 | 只看该作者
把底层抽象出来,作为一个独立的文件。

使用特权

评论回复
板凳
dffzh|  楼主 | 2025-5-22 15:04 | 只看该作者
734774645 发表于 2025-5-22 14:50
把底层抽象出来,作为一个独立的文件。

阁下的这种方法确实更好更进一步了,彻底把底层的东西与其他代码解耦

使用特权

评论回复
地板
逆鳞风暴| | 2025-6-3 09:11 | 只看该作者
非常实用的分享!通过宏定义和封装确实可以大大减少跨平台移植的工作量。能否再详细说明一下如何针对不同的MCU平台进行宏定义的调整?

使用特权

评论回复
5
dffzh|  楼主 | 2025-6-3 13:24 | 只看该作者
逆鳞风暴 发表于 2025-6-3 09:11
非常实用的分享!通过宏定义和封装确实可以大大减少跨平台移植的工作量。能否再详细说明一下如何针对不同的 ...
其实可以把头文件里的与MCU平台相关的宏定义再封装一层,并抽象出来单独封装到一个头文件里进行管理,这样代码移植时,无需修改驱动代码的源文件和头文件,而只需要修改封装的头文件即可,比如封装GPIO名称:目前是在驱动代码头文件里按如下方式申明:
#define   IS3980S_GPIO   GPIOB
可以把GPIOB封装到单独的通用头文件(commonHeader.h)里,并按如下方式命名:
#define  IS3980S_MCU_GPIO  GPIOB
而驱动头文件里修改如下:
#define  IS3980S_GPIO   IS3980S_MCU_GPIO
如此操作后,代码移植时,只需要修改commonHeader.h文件即可。
其他宏定义的封装操作类似。



使用特权

评论回复
6
EchoInEons| | 2025-6-14 17:35 | 只看该作者
可以学习一下ST的标准库和HAL库,HAL基本就是bsp层和中间层是分开的,但是这工作量比你修改代码本身更大哦

使用特权

评论回复
7
迷雾隐者| | 2025-6-15 11:49 | 只看该作者
非常赞同楼主的观点,使用宏定义来封装GPIO操作确实可以大大减少因MCU平台更换带来的代码修改量。这种方法不仅提高了代码的可移植性,也使得代码更加清晰易读。

使用特权

评论回复
8
dffzh|  楼主 | 2025-6-16 08:54 | 只看该作者
EchoInEons 发表于 2025-6-14 17:35
可以学习一下ST的标准库和HAL库,HAL基本就是bsp层和中间层是分开的,但是这工作量比你修改代码本身更大哦 ...

HAL库的设计理念确实值得我们好好研究一下。

使用特权

评论回复
9
dffzh|  楼主 | 2025-6-16 08:55 | 只看该作者
迷雾隐者 发表于 2025-6-15 11:49
非常赞同楼主的观点,使用宏定义来封装GPIO操作确实可以大大减少因MCU平台更换带来的代码修改量。这种方法 ...

是的,效果非常明显。

使用特权

评论回复
10
复古留声机| | 2025-6-17 09:01 | 只看该作者
非常实用的分享,通过宏定义和封装确实可以大大提高代码的复用率和可维护性。在实际项目中,这种方法可以大大减少因平台更换带来的工作量。

使用特权

评论回复
11
qinlu123| | 2025-6-17 11:03 | 只看该作者
dffzh 发表于 2025-6-16 08:55
是的,效果非常明显。

不能用宏,要用函数指针将各层分割开来

使用特权

评论回复
12
彩虹捕手| | 2025-6-17 16:02 | 只看该作者
非常赞同楼主的观点,使用宏定义和封装确实可以大大减少因更换MCU平台而带来的代码修改量。这种方法在实际项目中非常实用,感谢分享!

使用特权

评论回复
13
dffzh|  楼主 | 2025-6-18 08:39 | 只看该作者
彩虹捕手 发表于 2025-6-17 16:02
非常赞同楼主的观点,使用宏定义和封装确实可以大大减少因更换MCU平台而带来的代码修改量。这种方法在实际 ...

希望有所帮助

使用特权

评论回复
14
星空魔法师| | 2025-6-18 09:52 | 只看该作者
确实,更换MCU平台时,代码复用率的提升可以大大减少工作量。通过宏定义和封装确实是一种有效的方法,值得学习。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

64

主题

810

帖子

15

粉丝