7

我为设备创建了一个 Arduino 库,通常可以通过多种方式对其进行配置。例如使用中断或轮询它。从其他示例中,我为库创建了以下文件:foo.h、fooConfig.h 和 foo.cpp,如下所示。其中 fooConfig.h 包含如何使用屏蔽的配置。例如有或没有中断等......

在这样做时,我希望主草图的 INO 文件能够覆盖默认设置,这些设置已使用#define 声明。包括在图书馆的实例中。结果表明确实如此。至少我是这样做的。

下面的代码是一个有问题的简化示例:

定义测试.ino

#define BAR USE_POLL
#include <foo.h>

foo test;

void setup() {
  Serial.begin(115200);
  delay(1000);

  Serial.print(F("setup's defined BAR was "));
  Serial.println(BAR);

  Serial.print(F("inside foo.begin defined BAR was "));
  Serial.println(test.begin());
}

void loop() {
}

foo.h

#ifndef FOO_h
#define FOO_h

#include "FOOConfig.h"

class foo {
  public:
    int begin();
};
#endif // FOO_h

FooConfig.h

 #ifndef FOOCONFIG_h
  #define FOOCONFIG_h

  #define USE_INT      1
  #define USE_POLL     2

  #ifndef BAR
    //default to using interrupts
    #define BAR USE_INT
  #endif // BAR

#endif  // FOOCONFIG_h

foo.cpp

#include <foo.h>

int foo::begin() {
#if defined(BAR) && BAR == USE_INT
  Timer1.attachInterrupt( isr );  // error here, because of the define...
  return 1;
#elif defined(BAR) && BAR == USE_POLL
  return 2;
#endif
  return 0;
}

产生以下串行输出:

setup's defined BAR was 2
inside foo.begin defined BAR was 1

如果希望 foo.begin 中的 BAR 等于 2,而不是 1。请注意,希望让预编译器决定是否忽略 attachInterrupt。不想要库的资源在不使用的情况下的依赖和消耗。只是希望它是一个高级选项。

我知道这可能最好用 make 文件或 eclipse 来处理,但我正在尝试为目前 1.0.3 的 Arduino IDE 发布这个库。

任何帮助表示赞赏。

仅供参考,真实的完整代码在这里。 https://github.com/mpflaga/Sparkfun-MP3-Player-Shield-Arduino-Library/tree/master/SFEMP3Shield

4

4 回答 4

8

Regardless of tool chain, the program does not and should not determine how the library is compiled. A key concept of a library is that it is fully developed, compiled and packaged without the existence of any program. There is a one way dependency: a program depends on the library -- a library has no dependency on any program. A key point that highlights this is that you do not have to distribute source code to use a library. A library can be used with just headers and binary (.a) Take a peek into all the WinAvr libraries that are used.

What you are seeking is how to have multiple configurations of your library. In other tool chains this is readily done at the project level where you can create any number of output configurations. In your case you would have poll and int, and the toolchain would produce two libraries, for example:
libMySomething_int.a
libMySomething_poll.a

Programs choose which configuration of the library they wanted to use.

As noted by others, the Arduino IDE will not provide for this form of complexity. Since you stated you intend to stay within that toolchain, these are solutions I can see:

  1. Make two copies of the library that differ just by the one #define. This is basically you providing the two configurations. Because they differ by a tiny amount, it will be easy to WinMerge between to two and keep codebases synchronized.

  2. Rethink whether it is necessary to have one interface to the two forms. You do not have to have just one begin(), you can have two forms:

    void beginInt();
    void beginPoll();

    void getSomethingInt();
    void getSomethingPoll();

Keep in mind that this does not waste code space. The linker will remove all unused functions from the final program, so if you just use the Int form, all the Poll functions get dropped.

The choice between these two isn't clear and somewhat subjective. The decision should consider what you are intended to encapsulate/hide in the library, and what you want to make clear. If this library was an interface to a variety of real time clock chips, then you would clearly be fair to encapsulate all the differences and provide one set of functions. But in your case you are implying key changes in resource consumption, timing, and concurrency -- I'm not sure it is best to hide this.

于 2013-01-20T21:24:41.783 回答
2

Arduino IDE 单独编译库,因此您需要在编译期间将定义作为 -D 选项传递。Arduino IDE 目前不提供让您轻松做到这一点的工具。Arduino 1.5 通过 board.txt 系统提供了一些功能,但这可能无法提供您需要的灵活性。

因此,正如您所说,选项是在 Eclipse 等产品中编辑 make 文件,或者在 Visual Studio Pro 中设置“定义”项目属性之一(例如“定义 - 项目”)。

或者通过使用 TeensyDuino IDE 并将您自己的menu.defs 添加到 board.txt

于 2013-01-20T00:58:50.927 回答
1

如果您的库仅在主草图中使用
并且您可以将所有代码放在 .h 文件中(即没有 .cpp 文件)
,那么您可以实现您想要的。

这样做是有问题的编码实践,但在 Arduino 世界中似乎并不少见。

PS:完全正确,实际上也可以有一个 .cpp 文件,但前提是它的编译完全不受可覆盖的#define 的影响。

于 2013-07-14T10:40:44.680 回答
0

我不是 Arduino 专家,但乍一看。您的 foo::begin() 输出 1,因为您没有在 foo.cpp 中定义“BAR”,所以预处理器属于您的默认值。也许您可以向“foo”类添加“配置”方法。此方法将接收具有所需配置的参数,因此您将能够将您的定义作为参数从 INO 文件传递​​给“foo”类实例。

于 2013-01-19T21:51:35.890 回答