如何在嵌入式项目中组织代码



高度嵌入式(有限的代码和RAM大小)项目给代码组织带来了独特的挑战。

我见过很多根本没有组织的项目。(根据我的经验,主要是硬件工程师,他们通常不关心代码的非功能方面。

但是,我一直在尝试相应地组织我的代码:

  1. 特定于硬件(驱动程序、初始化)
  2. 特定于应用程序(不太可能重复使用)
  3. 可重复使用,独立于硬件

对于每个模块,我都尝试将目的保留为这三种类型之一。

由于嵌入式项目的规模有限,并且强调性能,因此通常会保留此组织。

在某些情况下,我当前的项目是MSP430上的有限DSP应用程序,具有8k闪存和256字节RAM。

我已经在各种目标微处理器(包括 MSP430)上编写和维护了多个嵌入式产品(30+ 和计数)。 我最成功的"经验法则"是:

  • 尝试尽可能模块化通用概念(例如,将驱动程序代码与应用程序代码分开)。 -- 它使将来更容易维护和重用/移植项目到另一个目标微。
  • 不要一开始就
  • 担心优化的代码。 首先尝试解决域的问题,然后再进行优化。- 你的目标微可以处理比你想象的更多的"东西"。
  • 努力确保可读性。 尽管大多数嵌入式项目的开发周期似乎都很短,但项目的生存期通常比您预期的要长,并且另一个开发人员无疑必须使用您的代码。

我研究过具有类似限制的 8 位 PIC 处理器。

您没有的一个限制是您进行了多少注释或选择命名方法、变量等的内容。 利用。 速度和大小限制有时确实胜过组织,但您始终可以解释。

另一个技巧是将逻辑源文件分解为比您需要的更多的部分,然后通过在编译单元中#include它们来绑定它们。 这允许您拥有大量可重用的代码(甚至每个文件一个例程),但以您需要的任何顺序进行组合。 这很有用,例如,当尝试满足编译单元大小限制时,或者选择下一个项目需要的通用子例程时。

我尝试组织它,就好像我有无限的RAM和ROM,它通常工作正常。 正如其他地方提到的,在绝对需要之前,不要尝试优化它。

如果你能得到一个引脚兼容的处理器,它有更多的资源,最好让它工作,专注于良好的结构和布局,然后在你更好地理解代码时优化大小。

除非在特殊情况下(请参阅注释),否则代码的组织不会对最终产品产生影响。(代码的内容显然是另一回事)

因此,考虑到

这一点,您应该像组织任何其他项目一样组织代码。

话虽如此,以下是相当典型的:

如果这是您以前或将来将要处理的处理器,您通常需要保留一个专用的硬件抽象层,以便将来可以在项目之间共享。通常,此模块将包含用于管理任何uart,计时器等的例程等项目。

通常,维护一组特定于平台的代码进行初始化和设置是合理的,这些代码执行所有配置和初始化,直到您的主管接管并运行您的应用程序为止。它还将包括特定于平台的 hal 例程。

执行/应用程序可能作为单独的模块进行维护。所有特定于硬件的代码都应隐藏在 hal 中(如上所述)。

通过像这样拆分代码,您还可以选择在完全不同的平台上将应用程序作为模拟进行编译和运行,只需将特定于硬件的代码替换为模拟硬件的例程即可。这对于您可能遇到的单元测试和调试以及算法问题非常有用。


异常编译器限制可能施加的特殊情况。 例如。我遇到过一些编译器,它们希望所有中断服务例程都在单个对象文件中编译。

我使用过一些传感器,如Tmote Sky,我也看到组织不善,我不得不承认我为此做出了贡献。无论如何,我会说必须有一些混乱,因为加载太多模块或太多的程序部分也会(恕我直言)资源消耗,所以尽量注意组织和可用性之间的门槛在低资源上。

显然,这并不意味着让caos开始,但是例如尝试查看tinyOS源代码和应用程序的组织,这是我想说的一个想法。

虽然这有点痛苦,但嵌入式 C 库中有点常见的一种组织技术是将每个函数和变量拆分到单独的 C 源文件中,然后将生成的 O 文件集合聚合到库文件中。

这样做的动机是,对于大多数普通链接器,链接单元是一个对象,对于每个对象,你要么得到整个对象,要么不得到它。由于 C 文件和对象文件之间存在 1-1 关系,因此将每个符号放在其自己的 C 文件中会给每个符号提供自己的对象。这反过来又允许链接器仅拉入实际使用的函数和变量的子集。

这种游戏对标题根本没有帮助,它们可以愉快地保留为单个文件。

最新更新