本文不是一篇已完成的文章,其中的内容仍然面临更改的可能。
截止本文章写作,并非内部的所有工具都有现成的方案(或者难以迭代和更新),内部的电控框架仍待后续开发。
开发工具链
所有文件使用 UTF-8 完成编码。使用KeilμVision5 的六代编译器完成编译。
推荐使用CubeMX+Keil+Vscode的KeilAssitant 编译链
代码封装
代码的封装被分为四个层级:HAL(硬件抽象层)、Bsp(板级支持包)、Module(模块)、Application(应用)
大部分市售的消费级嵌入式产品的第一层的HAL封装,都已经由开发的公司完成了封装,用户可以在编写程序时按需求直接调用。
其余的三层代码(Bsp、Module、App)都将由队伍内部完成编写。在编写代码库时,可以使用C或C++混编;使用STM32_HAL库作为代码的驱动库;统一使用UTF-8格式完成编码(见代码规范Chap.1);但无论使用什么编程语言作为库的支持语言,都应保证接口的泛用性和可维护性。
泛用性:对于调用该库文件的人,无论使用C还是C++混编,本库都应该正常运作,编写者应对自己的库文件负责;该库文件能通过宏定义或内部变量覆盖尽可能多的情况;
可维护性:如无必要(如必须依靠某特性才能实现需求效果,或该特性能带来巨大的性能提升或规范性提升),非常不推荐使用编程语言中的进阶特性。代码应尽可能保持高可读性和低耦合的状态并符合代码规范。
对于Bsp层:鉴于众多模组、模块以及开源项目使用的通信帧格式的不同,在我们的工程中,Bsp层通常与Module层合并到一个文件中。
如果采用Bsp层与Module层分离的设计,则要求Bsp层具有相当高的泛用性。考虑到代码的维护、使用与迭代,这样的设计是不合理的。
对于Module层:Module层可以是具有实体硬件的驱动节点,提供操控某一实体硬件的接口;也可以是某个算法的驱动节点,提供某一算法的相关输入输出接口。在操控相关硬件时,Module层应当能直接驱动对应的Bsp层完成实体硬件的驱动操作。无论使用C还是C++,Module层都应当是基于实例的。(使用C时,使用结构体进行封装;使用C++时,使用类进行封装)
对于Application层:Application层中的节点应当具有完成复杂任务的能力。如:底盘控制(包含了运动和路径解算)、主函数(线性流程的入口和主要执行节点)、定位融合(通过与视觉组的上位机沟通来更新位置)等。
Robocon每年的赛题变化较大,App层很可能需要频繁更新,但是通过建立电控框架,可以很大程度上减少驱动上的重复开发,对于提升工作效率非常重要。