Jak wywołać funkcje C ze szkicu Arduino?

10

Chciałbym wiedzieć, czy istnieje sposób wywoływania funkcji zawartych w plikach C przy użyciu szkicu Arduino?

Mój plik C deklaruje i definiuje funkcję. Aby zapisać umieszczenie definicji niechlujnej funkcji w moim szkicu Arduino, chciałbym wywołać funkcję bezpośrednio ze szkicu.

Czy istnieje standardowy sposób na wykonanie tego przy użyciu Arduino i C? Oto szkic:

#include "crc16.h";

void setup(){

}

void loop(){

  CalculateCRC16("<09M", 4);

}

a to jest przycięty plik C:

#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;
}
Nazwa Użytkownika
źródło
Czy istnieje powód, dla którego Twój plik musi używać C zamiast C ++?
Peter Bloomfield
Aktualnie tak. Kiedy próbuję skompilować plik przy użyciu C ++, występują błędy, ale w C. jest on wolny od błędów. Błąd jest spowodowany przez linie: const void *c_ptri const uint8_t *c = c_ptr;. Komunikat o błędzie wspomina o niepoprawnej konwersji między typami.
nazwa_użytkownika
4
Czy możesz zamieścić 2 pliki kodu (lub ich uproszczoną minimalną wersję), które powodują błąd, oraz skopiować i wkleić komunikat o błędzie w całości?
drodri
Komunikaty o błędach nie są tak ładne: 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.)
nazwa_użytkownika

Odpowiedzi:

10

Możesz dodać „C” #include w następujący sposób:

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

void setup(){
}

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

Plik crc16.h może być (kilka drobnych poprawek, #pragma raz, rzutowanie):

#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;
}
drodri
źródło
Dzięki, teraz działa dobrze. Czy mógłbyś wyjaśnić potrzebę pragmy?
nazwa_użytkownika
1
Jasne, jest to dobra praktyka, choć nie jest to potrzebne w twoim przykładzie. Pozwala to uniknąć tego, by ten sam plik nagłówkowy był dwukrotnie zawarty w pliku kompilacji. Wyobraź sobie a.cpp -> (bh i ch) i bh-> ch To powieli zawartość ch podczas kompilacji a.cpp. #Pragma kiedyś tego unikało. Powszechne są do tego również strażowe dyrektywy #ifndef _MY_FILE_H_INCLUDED # zdefiniować _MY_FILE_H_INCLUDED. Zauważ jednak, że jak zauważa Peter R. Bloomfield, może być lepiej umieścić implementację CalculateCRC16 w pliku cpp i pozostawić tylko deklarację w pliku nagłówkowym.
drodri
Ok, widzę, że staje się to problemem, gdy kod staje się coraz bardziej skomplikowany. Dzięki za radę.
nazwa_użytkownika
4

Twoja funkcja CRC może być łatwo przekonwertowana do C ++, dzięki czemu można przejść do pliku * .cpp. Wszystko, co musisz zrobić, to użyć jawnego rzutowania podczas inicjalizacji cwskaźnika. Oto „właściwy” sposób na zrobienie tego w C ++:

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

Jednak działałaby również stara obsada w stylu C:

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

Problem polega na tym, że C może być nieco bardziej liberalny, pozwalając na niejawną konwersję wskaźników między typami. Aby to zrobić w C ++, musisz wyraźnie powiedzieć kompilatorowi, że konwersja jest zamierzona.

Peter Bloomfield
źródło
1

Tak, po prostu skopiuj jego linię deklaracji do szkicu:

extern "C" {
    void myfunction(int arg);
}
jfpoilpret
źródło