Comment appeler les fonctions C à partir d'un croquis Arduino?

10

Je voudrais savoir s'il existe un moyen d'appeler des fonctions contenues dans des fichiers C à l'aide d'un croquis Arduino?

Mon fichier C déclare et définit une fonction. Pour éviter de mettre la définition de la fonction désordonnée dans mon croquis Arduino, je voudrais appeler la fonction directement à partir du croquis.

Existe-t-il un moyen standard de le faire en utilisant Arduino et C? Voici le croquis:

#include "crc16.h";

void setup(){

}

void loop(){

  CalculateCRC16("<09M", 4);

}

et voici le fichier C réduit:

#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;
}
Nom d'utilisateur
la source
Y a-t-il une raison pour laquelle votre fichier doit utiliser C au lieu de C ++?
Peter Bloomfield
En fait, oui. Lorsque j'essaie de compiler le fichier à l'aide de C ++, il y a des erreurs, mais il ne contient aucune erreur en C. L'erreur est causée par les lignes: const void *c_ptret const uint8_t *c = c_ptr;. Le message d'erreur mentionne une conversion non valide entre les types.
user_name
4
Pourriez-vous s'il vous plaît publier les 2 fichiers de code (ou une version minimale simplifiée d'entre eux) qui produisent l'erreur, et copier-coller le message d'erreur dans son intégralité?
drodri
Les messages d'erreur ne sont pas si jolis: 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

Réponses:

10

Vous pouvez extern "C" #include comme suit:

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

void setup(){
}

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

Et le fichier crc16.h pourrait être (quelques corrections mineures, le #pragma une fois, un cast):

#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
la source
Merci, ça fonctionne très bien maintenant. Pourriez-vous s'il vous plaît expliquer le besoin du pragma?
user_name
1
Bien sûr, c'est une bonne pratique, bien qu'elle ne soit pas nécessaire dans votre exemple. Cela évite que le même fichier d'en-tête soit inclus deux fois dans un fichier de compilation. Imaginez a.cpp -> (bh et ch) et bh-> ch Cela dupliquera le contenu de ch lors de la compilation de a.cpp. Le #pragma évite une fois cela. Les directives de garde #ifndef _MY_FILE_H_INCLUDED #define _MY_FILE_H_INCLUDED sont également courantes pour cela. Notez cependant que, comme le souligne Peter R. Bloomfield, il serait préférable de placer l'implémentation de CalculateCRC16 dans un fichier cpp et de ne laisser que la déclaration dans le fichier d'en-tête.
drodri
Ok, je peux voir que cela devient un problème lorsque le code devient de plus en plus compliqué. Merci pour le conseil.
user_name
4

Votre fonction CRC peut facilement être convertie en C ++ afin qu'elle puisse aller dans un fichier * .cpp. Tout ce que vous devez faire est d'utiliser une distribution explicite lorsque vous initialisez votre cpointeur. Voici la manière «appropriée» de le faire en C ++:

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

Cependant, un ancien casting de style C fonctionnerait également:

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

Le problème est que C peut être un peu plus permissif pour vous permettre de convertir implicitement des pointeurs entre types. Pour le faire en C ++, vous devez dire explicitement au compilateur que la conversion est intentionnelle.

Peter Bloomfield
la source
1

Oui, copiez simplement sa ligne de déclaration dans votre croquis:

extern "C" {
    void myfunction(int arg);
}
jfpoilpret
la source