我为设备创建了一个Arduino库,通常可以通过多种方式配置它。例如。使用中断或轮询它。在其他示例中,我创建了以下文件:foo.h,fooConfig.h和foo.cpp,如下所示。其中fooConfig.h包含如何使用屏蔽的配置。如有或没有中断等...
这样做我希望主草图的INO文件能够覆盖使用#define声明的默认设置。包括在图书馆的实例中。结果表明它确实如此。至少就是我这样做的方式。
以下代码是一个带有问题的简化示例:
definetest.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
答案 0 :(得分:8)
无论工具链如何,程序都不会也不应该确定如何编译库。库的一个关键概念是它完全开发,编译和打包而不存在任何程序。有一种单向依赖:程序依赖于库 - 库不依赖于任何程序。强调这一点的一个关键点是您不必分发源代码来使用库。一个库可以只使用头文件和二进制文件(.a)查看所有使用的WinAvr库。
您正在寻求的是如何对库进行多种配置。在其他工具链中,这很容易在项目级别完成,您可以在其中创建任意数量的输出配置。在您的情况下,您将使用poll和int,并且工具链将生成两个库,例如:
libMySomething_int.a
libMySomething_poll.a
程序选择他们想要使用的库的配置。
正如其他人所说,Arduino IDE不会提供这种复杂性。既然你说你打算留在那个工具链中,这些是我能看到的解决方案:
制作两个与#define不同的库的副本。这基本上是您提供两种配置。因为它们之间的差别很小,所以WinMerge很容易在两个之间并保持代码库同步。
重新思考是否有必要为这两个表单设置一个接口。你不必只有一个begin(),你可以有两种形式:
void beginInt();
void beginPoll();
void getSomethingInt();
void getSomethingPoll();
请记住,这不会浪费代码空间。链接器将从最终程序中删除所有未使用的函数,因此如果您只使用Int表单,则所有Poll函数都将被删除。
这两者之间的选择并不明确,有些主观。决定应考虑您打算在库中封装/隐藏的内容,以及您想要明确的内容。如果这个库是各种实时时钟芯片的接口,那么显然可以公平地封装所有差异并提供一组功能。但在你的情况下,你暗示资源消耗,时间和并发性的关键变化 - 我不确定最好隐藏它。
答案 1 :(得分:2)
Arduino IDE单独编译库,因此您需要在编译期间将define作为-D选项传递。 Arduino IDE目前不提供便于您轻松完成的工具。 Arduino 1.5通过boards.txt系统提供了一些功能,但这可能无法提供您所需的灵活性。
因此,正如您所说,选项是在Eclipse等产品中编辑make文件,或者在Visual Studio Pro中设置“Defines”项目属性之一(例如“Defines - Project”)。
或者使用TeensyDuino IDE并将自己的menu.
defs添加到boards.txt
答案 2 :(得分:1)
如果您的图书馆仅在主草图中使用 并且您可以将所有代码放在.h文件中(即没有.cpp文件) 那么你就可以达到你想要的效果。
这样做是有问题的编码实践,但在Arduino世界中似乎并不罕见。
PS:完全正确,实际上也可以有一个.cpp文件,但前提是它的编译完全不受可覆盖的#define的影响。
答案 3 :(得分:0)
我不是Arduino专家,但乍看之下。你的foo :: begin()输出1,因为你没有在foo.cpp中定义“BAR”,所以预处理器会降到你的默认值。也许你可以在“foo”类中添加一个“配置”方法。此方法将接收具有所需配置的参数,因此您可以将define as参数从INO文件传递到“foo”类实例。