您如何构建大型嵌入式项目?

电器工程 微控制器 嵌入式 设计 软件
2022-01-04 03:59:41

背景

初级研发电子工程师(公司唯一的 EE)——硬件和编码不是问题。我最大的问题是对项目有一个正确的概述,以及从哪里开始。

到目前为止,我只制作了小型软件项目(少于 500 行代码),但我无法想象自己在做更大的项目时不会失去对功能或缺乏功能的概述。

您如何最好地构建/使用什么工具来构建大型嵌入式软件系统?

我目前在做什么

我通常从勾画项目的功能开始。它可以是一对多的分层流程图或相关图表(框图等),并对组件/芯片进行一些研究。然后我在参考数据表/互联网时直接跳入编码(我猜很快失败),一次编码一个功能并使用虚拟数据或类似测试对其进行测试。它可能正在向 MEM 芯片写入数据,然后如果能正常工作,那么它可能是主芯片和 MEM 芯片之间的 SPI 驱动程序。

我正在寻找什么答案

真的什么都有。我会整理出我认为合理的东西。它可以是一本书、一篇文章、个人经历、建议等。

我很想知道老年人如何解决这个问题。


编辑

首先,感谢您分享您多年的经验!非常感谢所有答案。我的看法是;

  • 创建清晰准确的规范文档。
  • 创建软件设计文档。(我现在要添加的东西) 设计文档模板
  • 在模块中思考它可能看起来多么多余。(我需要更多关注的事情)
  • 遵循构建头文件/源文件的编码标准。(从未这样做过) Barr Group C 标准
  • 首先专注于创建低级实现。(通讯等)
  • 尽可能/合理地实施设计模式。 设计模式
  • 为版本控制设置一些东西(Github 等 - 从来没有用过这么多)
  • 研究持续集成/持续部署(我偶然发现的新事物) CI 和 CD 基础
4个回答

有几个方面会影响项目需求结构的详细程度。对我来说,主要因素之一是我是否是唯一的编码人员(在您编写时,您似乎是这种情况,您是唯一的 EE),或者是否有其他人参与其中。然后是“大”实际上意味着什么的问题。通常我将设计过程分为以下几个步骤:

需求定义 如果你得到了合适的软件规范来工作,那么很多计划就已经完成了。如果你只是得到模糊的要求,你要做的第一件事就是理清客户真正想要什么(有时他们一开始并不真正知道)。我知道直接跳入编码是很诱人的,但这会带来丢失一个重要功能的风险,这些功能一开始可能并不明显,而且不能轻易地在开发过程中的某个地方挤进你的代码中。

系统边界和可维护性 在嵌入式系统中,您通常有一些系统接口,一些面向外部(操作员),但也有一些在内部。很好地定义这些并尝试使依赖关系尽可能低,这将简化持续的工程和可维护性。还要在需要的地方注释/记录代码,你永远不知道还有谁必须使用它,(s)他会很高兴不必在真正知道函数的作用之前挖掘十几层代码。

定义可验证的任务 特别是如果其他开发人员正在使用相同的代码库,则不可避免地要定义明确的任务(功能)和它们之间所需的接口。只要有可能,应该独立于其他功能测试/验证各个功能,这就是您需要明确定义接口的地方,以便您可以定义测试用例。

一个接一个的功能 人们喜欢进步,所以如果你有各种各样的任务,他们通常会做任何承诺最大进步的事情。在开始下一个任务之前,我通常会尝试完成一项任务并将其带到经过验证和测试的状态。这使您的代码可以被其他人测试,而您最终不会忘记某些东西。

版本控制 在项目的生命周期中,您有时需要旧版本,可能是为了识别一些新版本引入的错误,或者只是为了构建一个与您 3 年前发布的设备完全相同的设备。确保您的代码中有明确的构建版本和标签。Git 绝对是你的朋友。

Humpawumpa 写了一个很好的答案我只是想补充他的一些观点,但是由于这太长了,不能发表评论,所以我会单独写一个答案。

我曾经担任过 OP 的职位——不是唯一的 EE,而是唯一在一家小公司做过任何 MCU 开发的 EE。

即使您是唯一的开发人员,我也无法充分强调模块化的重要性。随着项目的发展,这是保持理智的唯一方法。您需要严格编写每个只处理一个功能概念的模块,并尽可能减少它们的外部接口。高级模块将对应于功能需求,而低级模块将与硬件资源(即设备驱动程序)密切相关。

我花了很多时间维护一个详细的数据流图1,它准确地显示了各个模块如何共享信息。一些特性在实时性能方面会有非常不同的要求;确保您知道信息共享如何影响它。该图在其上绘制了边界,将非中断代码与各种中断驱动的域分开。


1与专注于控制流的流程图非常不同

对于任何大型项目,即使我打算自己完成整个事情,我也会将其计划为有多个开发人员参与。

原因很简单:

1复杂性。大型项目总是涉及复杂性。像涉及多个团队一样规划项目意味着已经考虑并记录了复杂性。我看到大型项目遇到问题的次数很多,通常是因为某些东西“从裂缝中溜走”。不要忘记还必须考虑机械组装,而不仅仅是考虑盒子的大小 - 是否需要散热器?为了安全,盒子必须接地吗?仅这一类就有很多问题。

2要求。假设涉及多个人意味着顶级需求(我经常挑战,因为它们可能带来不必要的复杂性和成本)必须分解为各种较小的所需和可实现的任务(可以提供给更大组织中的另一个团队) 而不是只看一个 blob。

3分区。有两种主要的分区类型;硬件功能和硬件/软件。第一种类型是确定需要存在哪些单独的(但可以通信的)功能块。第二个是更简单(有时)硬件和软件的权衡,但请记住,简单地将更多东西转移到软件上不一定能解决硬件问题。在某些情况下,更多地转向软件实际上会大大增加硬件的复杂性(更多的处理能力、更复杂的接口等等)。

4 个接口。划分过程将有助于定义内部接口;外部接口通常是整体需求的一部分(尽管并非总是如此)。系统的不同部分可以通过多种方式进行协作,这可能是复杂的通信协议,也可能是简单的好/坏信号。

5验证。这是低级别测试(针对硬件和驱动程序)和系统级别的混合。在定义明确的块中完成项目后,可以进行稳健的验证(可能通过分析或实际测试,通常是两者的混合;对设计的更新可能会使用相似性参数)。

6标准。我使用编码和绘图标准,就好像它是一个更大的团队一样。我使用 Barr group 的编码标准,因为它们不太繁琐,但确实可以防止代码中出现许多类别的错误。对于 PCB 输出文档,我遵循IPC-D-326(调用 IPC-D-325),因为这是向 PCB 制造商和组装商传达我的意图的一种行之有效的方法。这可能看起来很奇怪,但是遵守一些标准的纪律意味着质量是一致的。

7版本控制。我对项目的所有部分(系统、硬件、软件、机械、测试要求 - 一切)都使用版本控制。我使用的 CAD 工具支持版本控制,就像所有软件和 FPGA 构建工具一样。

我参与过许多嵌入式项目(这里有许多经验丰富的人),团队规模从 1 个(我自己)到几十个(或一组特定项目的数百个)不等,分布在多个学科,有时甚至是其他地理位置偏远的地方网站。使用相同的总体方法(已知有效)意味着我可以在相对孤立的情况下完成一项特定任务并完成它,并将其作为更大项目的独立部分进行彻底测试。这也意味着如果有必要,我有时可以分出一些东西。

做所有这些事情会增加一些前期时间,但最终对于复杂的嵌入式系统来说是一条更快的途径。

其他答案提供了许多很棒的提示。以下是我发现在我的嵌入式开发生涯中最重要的两个:

  1. 将尽可能多的代码制作成单独的、定义良好的模块。
  2. 使模块可在 PC 上自动测试。

这就是在嵌入式系统上进行“持续集成”风格开发所需要的。总会有一些代码与硬件过于紧密地联系在一起,无法进行自动测试,但请尽量减少它。通过使用模拟数据或从实际硬件捕获的数据,您可以走得更远,然后将其输入测试系统。