如何在标准C代码中使用Arduino库

5
我正在使用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调用的正确程序是什么? 我已经尝试在我的.cpp文件和.h文件中使用extern "C" {function()};,但没有用。

感谢任何帮助或指向我可以自行解决问题的地方的指针。


1
编译器会抛出链接错误 - 那会是什么错误? - Captain Obvlious
您可以使用gcc选项-Wl,--verbose来检查链接错误的详细信息。 - Mansuro
为了更清晰地表达,添加了代码片段。 - ThesQuid
你尝试过使用C++编译器进行编译吗?它应该可以编译你的代码,并且原生支持C++。 - Treesrule14
2个回答

1
您可以尝试将C代码编译为C++,只需将文件重命名为*.CPP即可,但很可能需要修改您的代码才能将其编译为C++代码。在C中允许的事情,在C++中可能不允许(例如调用未声明的函数)。
另一种解决方案是在要从C中使用的C++函数周围编写包装器。 您必须考虑C相对于C++的两个限制:
1. C不是面向对象的 2. C不支持函数重载
这个关于Serial.print()的示例展示了如何使用包装器处理这个问题:
extern "C" void SerialPrintInteger( int value )
{
    Serial.print( value );
}

在这个示例中,你需要编写类似于SerialPrintFloat()SerialPrintString()等函数。 extern "C"前缀告诉编译器以使其可以从C中调用的方式创建该函数。

0
你上面收到的错误不是编译器错误,而是链接器错误。我没有使用Eclipse进行Arduino开发,我只使用Arduino IDE,但标准的Arduino项目期望您的所有代码都在一个单独的源文件中,它会将其编译,然后与Arduino库链接。Arduino程序没有C / UNIX风格的“main”函数,标准函数是“setup”和“loop”。
我建议回到Arduino示例程序之一,例如blink,并观察控制台日志,以便Eclipse编译和链接程序。这里正在发生以下情况:
1. C / C ++编译器将您的源代码(包括setup(),loop()和任何其他函数)编译为对象文件。 2. 链接器将此单个对象文件与Arduino运行时和您指定的任何Arduino库链接。其输出是程序的映像,在您上面的示例中,它正在尝试创建'Virgin2ManualArdInsert.elf'。 3. 上传程序(可能是avrdude)将此映像加载到您的Arduino并重置它。 4. Arduino退出复位并运行您的新代码。

如果你的程序相对较小,比如不超过几百行,那么就把所有函数放在一个源文件中,这样你就不必学习如何驱动链接器。

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

至于C与C++源代码,你通常可以将C函数放入C++源文件中并进行编译。虽然有一些差异,但这样做你就不必担心"C"链接或任何愚蠢的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接