Wie rufe ich C-Funktionen aus der Arduino-Skizze auf?


10

Ich möchte wissen, ob es eine Möglichkeit gibt, Funktionen, die in C-Dateien enthalten sind, mithilfe einer Arduino-Skizze aufzurufen.

Meine C-Datei deklariert und definiert eine Funktion. Um zu vermeiden, dass die unordentliche Funktionsdefinition in meine Arduino-Skizze eingefügt wird, möchte ich die Funktion direkt aus der Skizze aufrufen.

Gibt es eine Standardmethode, um dies mit Arduino und C zu tun? Hier ist die Skizze:

#include "crc16.h";

void setup(){

}

void loop(){

  CalculateCRC16("<09M", 4);

}

und dies ist die abgespeckte C-Datei:

#include <stdio.h>
#include <stdint.h>

uint16_t crctable[256] =
{
    0x0000, 0x1189,.....



uint16_t // Returns Calculated CRC value
CalculateCRC16( // Call example CalculateCRC16("<09M", 4);
    const void *c_ptr, // Pointer to byte array to perform CRC on
    size_t len)        // Number of bytes to CRC
{

    uint16_t crc = 0xFFFF // Seed for CRC calculation
    const uint8_t *c = c_ptr;

    while (len--)
        crc = (crc << 8) ^ crctable[((crc >> 8) ^ *c++)];

    return crc;
}

Gibt es einen Grund, warum Ihre Datei C anstelle von C ++ verwenden muss?
Peter Bloomfield

Eigentlich ja. Wenn ich versuche, die Datei mit C ++ zu kompilieren, gibt es Fehler, aber in C ist sie fehlerfrei. Der Fehler wird durch die Zeilen: const void *c_ptrund verursacht const uint8_t *c = c_ptr;. Die Fehlermeldung erwähnt eine ungültige Konvertierung zwischen Typen.
Benutzername

4
Könnten Sie bitte die 2 Codedateien (oder eine vereinfachte Minimalversion davon), die den Fehler verursachen, veröffentlichen und die Fehlermeldung vollständig kopieren und einfügen?
Drodri

Die Fehlermeldungen sind nicht so hübsch: In function uint16_t CalculateCRC16(uint16_t, const void*, size_t)': 46 invalid conversion from const void * 'toconst uint8_t*' In function int main()': 57 system' undeclared (first use this function) (Each undeclared identifier is reported only once for each function it appears in.)
user_name

Antworten:


10

Sie können extern "C" #include wie folgt einschließen:

extern "C"{
#include "crc16.h"
};

void setup(){
}

void loop(){
  CalculateCRC16("<09M", 4);
}

Und die Datei crc16.h könnte sein (einige kleinere Korrekturen, das #pragma einmal, eine Besetzung):

#pragma once

#include <stdio.h>
#include <stdint.h>

uint16_t crctable[2] ={ 0x0000, 0x1189};

uint16_t CalculateCRC16( // Call example CalculateCRC16("<09M", 4);
    const void *c_ptr, // Pointer to byte array to perform CRC on
    size_t len)        // Number of bytes to CRC
{
    uint16_t crc = 0xFFFF; // Seed for CRC calculation
    const uint8_t *c = (const uint8_t *)c_ptr;

    while (len--)
        crc = (crc << 8) ^ crctable[((crc >> 8) ^ *c++)];

    return crc;
}

Danke, es funktioniert jetzt ganz gut. Könnten Sie bitte die Notwendigkeit des Pragmas erklären?
Benutzername

1
Sicher, es ist eine gute Praxis, obwohl sie in Ihrem Beispiel nicht benötigt wird. Es wird vermieden, dass dieselbe Header-Datei zweimal in eine Kompilierungsdatei aufgenommen wird. Stellen Sie sich a.cpp -> (bh und ch) und bh-> ch vor. Dadurch wird der Inhalt von ch beim Kompilieren von a.cpp dupliziert. Das # Pragma vermeidet dies einmal. Auch Schutzanweisungen #ifndef _MY_FILE_H_INCLUDED #define _MY_FILE_H_INCLUDED sind hierfür üblich. Beachten Sie jedoch, dass es, wie Peter R. Bloomfield betont, möglicherweise besser ist, die Implementierung von CalculateCRC16 in eine CPP-Datei einzufügen und nur die Deklaration in der Header-Datei zu belassen.
Drodri

Ok, ich kann sehen, dass dies zu einem Problem wird, wenn der Code immer komplizierter wird. Danke für den Hinweis.
Benutzername

4

Ihre CRC-Funktion kann einfach in C ++ konvertiert werden, sodass sie in eine * .cpp-Datei verschoben werden kann. Alles, was Sie tun müssen, ist eine explizite Umwandlung zu verwenden, wenn Sie Ihren cZeiger initialisieren . Hier ist der 'richtige' C ++ - Weg, dies zu tun:

const uint8_t *c = static_cast<const uint8_t*>(c_ptr);

Eine alte Besetzung im C-Stil würde jedoch auch funktionieren:

const uint8_t *c = (const uint8_t*)c_ptr;

Das Problem ist im Grunde, dass C etwas toleranter sein kann, wenn Sie Zeiger implizit zwischen Typen konvertieren lassen. Um dies in C ++ zu tun, müssen Sie dem Compiler explizit mitteilen, dass die Konvertierung beabsichtigt ist.


1

Ja, kopieren Sie einfach die Deklarationszeile in Ihre Skizze:

extern "C" {
    void myfunction(int arg);
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.