前言

在嵌入式MCU软件开发过程中,程序分层设计也是重中之重,关系到整个软件开发过程中的协同开发,降低系统软件的复杂度(复杂问题分解)和依赖关系,同时有利于标准化,便于管理各层的程序,提高各层逻辑的复用等。灵活的系统结构,一致的模块接口,清晰的软硬件脉络,才是可移植的关键。可移植性是可靠性的基石,产品的可靠性来自于3个方面:正确设计以减少缺陷、充分测试以修正缺陷、充分使用中暴露缺陷。反复使用是暴露bug的一个重要手段,同时也是暴露设计缺陷的手段。只有可移植性强的模块,才有机会在不同的产品、不同的使用环境中反复使用。“拿来”一个可移植的、经过反复使用考验的模块,显然是设计高可靠性产品的最好的保证。


一、分层介绍

将同功能硬件的共性抽象出来形成一个软件层,将差异保留在硬件的具体驱动代码中,这样可以屏蔽硬件差异,当硬件发生改变时,上层代码不用改变。

1.1 硬件抽象层 (HAL)

嵌入式开发的核心就是CPU,它提供固定的片内资源(常用的有I/O、TIM、UART、ADC、ISR等,稍微好点的还有DAC、IIC、SPI等硬件资源,不需要CPU外扩芯片或模拟IIC、SPI)供开发者使用。它不随项目的新增需求变动而变动,所以将其作为持。大部分情况下该层都会有芯片厂商提供相应的库函数包或者配置工具生成对应API函数,基本只要知道如何配置和使用就行,当然也有可能存在芯片厂商提供的库函数包或者配置工具使用自由度不高,需要自己查看芯片参考手册实现需要的API函数。

1.2 硬件驱动层 (HDL)

嵌入式开发通常都会使用片外资源,用来弥补硬件抽象层实现不了的功能或者需要扩展的功能。如AT24C02、W25QI28、MAX3485等常见的外围芯片,需要IIC、SPI、UART通信发送相应指令、数据驱动该芯片,使得该芯片能正常工作。因此驱动这部分的API函数实现程序即为硬件驱动层。即使更换了MCU,也只需将调用过的硬件抽象层的API函数替换即可。

1.3 功能模块层 (FML)

硬件抽象层和驱动层就是为功能模块层服务的,功能模块层是实现项目需要的功能。而这一层又为上层提供最基本的功能API函数,各功能模块之间没有太多联系。比如KEY、LED和EEPROM等功能,其中KEY、LED基本调用硬件抽象层的API函数(更复杂的可能通过片外芯片获取、控制等,因此可能也需要使用硬件驱动层的API函数),EEPROM调用硬件驱动层的API函数,即使EEPROM芯片更换,也不影响EEPROM之前编写的功能代码程序(前提是提供的API函数提供的是统一标准)。

1.4 应用程序层 (APL)

应用程序层主要负责的就是功能模块的使用和功能模块之间的逻辑关系处理等,比如用户交互界面应用程序可能需要按键(KEY)、指示灯(LED)、显示屏(LCD)、GUI库等,实现一系列的人机交互功能,通常应用程序层相对于功能模块层而言独立性较低。一般情况下也可细分出应用业务层,但是对于单片机产品来说,这一层的必要性反而不高,分层太多,反而显得臃肿。


二、总结

2.1 硬件抽象层与硬件驱动层的区别

硬件抽象层使用的是芯片内本身的资源(芯片手册都有介绍),而硬件驱动层使用的是芯片本身不存在的资源,而且需要编写相应代码才能实现的资源。比如用STM32MCU实现CAN通信,CAN控制器属于STM32的片内资源,但还需要外扩CAN收发器芯片才能实现该功能,这些收发器芯片属于片外资源,但这些收发器不需要额外的代码就能通过STM32中CAN本身提供的API函数就能正常工作,因此可以认为这些收发器芯片不属于硬件驱动层。如果使用片外的CAN控制器芯片,则需编写额外代码才能正常工作,因此可以将其归为硬件驱动层。

2.2 功能模块层和硬件抽象层、硬件驱动层的主要区别

功能模块层是按照项目需求提取出来的功能,需要硬件抽象层和硬件驱动层的硬件支持才能实现,功能模块层根据项目的功能需求改变而改变,而硬件抽象层和硬件驱动层是项目需求书中的功耗等硬件相关的需求变动而变动,当然,若子功能的增加而已有硬件不支持,则也需更换硬件驱动。比如项目中的数据存储功能,硬件支持有AT24C02、W25QI28和芯片本身的片内FLASH,都可以支持数据存储功能,即使后期因为功耗或节约成本问题,硬件的更换也不影响数据存储功能的实现(前提规划好标准规范的API函数定义)且避免了重写该功能代码所带来的各种问题,保证了该功能的稳定性。


三、分层结构示意图

在这里插入图片描述

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐