如何将arduino库与标准C代码一起使用

时间:2014-07-09 14:54:25

标签: c++ c eclipse arduino avr

我正在使用Eclipse kepler进行AVR开发。 我拥有的代码是C(开源),我已经调整它以便它完美运行。我的目标是ATmega2560,采用arduino mega2560的形式。 使用arduino板严格用于硬件方便;我们正在开发硬件作为定制板,其中包含大多数核心arduino mega2560组件。

我需要在这个项目中使用几个库,它们只能用作arduino库,即电子纸屏幕库(来自seeedstudio)和Nordic的BLE nRF8001。

如果我在eclipse中使用插件创建一个新的arduino项目,我可以完美地构建和运行arduino库的测试。

当我尝试将两个代码库合并在一起时,我似乎无法调用添加的arduino库中的函数 - 如果我调用它们,编译器会抛出链接错误。

Building target: Virgin2ManualArdInsert.elf
Invoking: AVR C Linker
avr-gcc -Wl,-Map,Virgin2ManualArdInsert.map -mmcu=atmega2560 -o "Virgin2ManualArdInsert.elf"         ./avr/adc.o ./avr/eeprom.o ./avr/lcd_and_input.o ./avr/main.o ./avr/strings.o ./avr/unimplemented.o ./avr/usart.o  ./aes.o ./baseconv.o ./bignum256.o ./ecdsa.o ./endian.o ./fft.o ./fix16.o ./hash.o ./hmac_sha512.o ./messages.pb.o ./p2sh_addr_gen.o ./pb_decode.o ./pb_encode.o ./pbkdf2.o ./prandom.o ./ripemd160.o ./sha256.o ./statistics.o ./stream_comm.o ./test_helpers.o ./transaction.o ./wallet.o ./xex.o   
./avr/main.o: In function `main':
main.c:(.text.startup.main+0xc): undefined reference to `writeEink'
collect2: error: ld returned 1 exit status
makefile:53: recipe for target 'Virgin2ManualArdInsert.elf' failed
make: *** [Virgin2ManualArdInsert.elf] Error 1

作为测试,我只是试图从main.c中调用eInk.cpp中的基本“写入显示”调用:

extern "C"{
void writeEink()
{

    EPAPER.begin(EPD_SIZE);                             // setup epaper, size
    EPAPER.setDirection(DIRNORMAL);                     // set display direction

    eSD.begin(EPD_SIZE);
    GT20L16.begin();

//    int timer1 = millis();
    EPAPER.drawString("testing", 10, 10);
    EPAPER.drawNumber(12345, 60, 40);
    EPAPER.drawFloat(-1.25, 2, 80, 65);
    EPAPER.display();                                   // use only once

}

是否可以使用arduino核心构建静态库?我已经尝试过了(虽然看起来大多数程序已经过时了)并且库不想链接/被调用。

在我的C代码中包含C ++ / Arduino调用的正确步骤是什么? 我尝试过使用extern“C”{function()};在我的.cpp文件和.h文件中但没有用。

感谢您提供任何帮助或指示我可以自己解决的问题。

2 个答案:

答案 0 :(得分:1)

您可以尝试通过简单地将文件重命名为* .CPP来将C代码编译为C ++,但是您可能需要修改代码以使其编译为C ++代码。有些东西是C允许的,但不适用于C ++(比如调用未声明的函数)。

另一种解决方案是围绕要从C中使用的C ++函数创建包装器。 你必须考虑C对C ++的两个限制:

  1. C不是面向对象的
  2. C不支持功能重载
  3. Serial.print()的示例显示了如何使用包装器处理此问题:

    extern "C" void SerialPrintInteger( int value )
    {
        Serial.print( value );
    }
    

    在此示例中,您将编写类似的函数,如SerialPrintFloat()SerialPrintString()等。 extern "C"前缀告诉编译器以使其可从C调用的方式创建函数。

答案 1 :(得分:0)

上面收到的错误不是编译器错误,而是链接器错误。我没有使用Eclipse进行Arduino开发,我只是坚持使用Arduino IDE,但是标准的Arduino项目希望你的所有代码都在一个源文件中,它编译然后链接到Arduino库。 Arduino程序没有C / UNIX风格的“主”功能,标准功能是“设置”和“循环”。

我建议回到其中一个Arduino示例程序,例如blink,并在Eclipse编译并链接程序时观察控制台日志。这里发生的事情是:

  1. C / C ++编译器将您的源代码(包括setup(),loop()和您创建的任何其他函数)编译到目标文件中。
  2. 链接器将此单个目标文件与Arduino运行时以及您指定的任何Arduino库相链接。这个节目的输出是一个程序的图像,在你上面的例子中它试图制作'Virgin2ManualArdInsert.elf'。
  3. 上传者(可能是avrdude)将此图片加载到您的Arduino中并重置它。
  4. Arduino退出重置并运行新代码。
  5. 如果您的程序相当小,比如说不超过几百行,只需将所有函数放在一个源文件中,那么您就不必学习如何驱动链接器。

    如果由于某种原因需要将源代码放在一个单独的文件中(也许它们与另一个程序或其他平台共享),那么你将不得不学习如何让Eclipse链接目标文件来自您的多个源文件。这可能只涉及正确地将源添加到Eclipse项目中,或者您可能必须编写Makefile或类似的东西。

    对于C vs C ++ 源代码,通常可以将C函数放入C ++源文件并进行编译。有一些差异,但这样你就不必担心“C”联系或任何愚蠢。