¿Cómo llamar a funciones C desde el boceto de Arduino?

10

Me gustaría saber si hay una manera de llamar a las funciones que están contenidas en los archivos C utilizando un boceto Arduino.

Mi archivo C declara y define una función. Para guardar poner la definición de función desordenada en mi boceto Arduino, me gustaría llamar a la función directamente desde el boceto.

¿Hay una forma estándar de hacer esto usando Arduino y C? Aquí está el boceto:

#include "crc16.h";

void setup(){

}

void loop(){

  CalculateCRC16("<09M", 4);

}

y este es el archivo C recortado:

#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;
}
nombre_usuario
fuente
¿Hay alguna razón por la cual su archivo tiene que usar C en lugar de C ++?
Peter Bloomfield
Actualmente, si. Cuando intento compilar el archivo usando C ++, hay errores, pero está libre de errores en C. El error es causado por las líneas: const void *c_ptry const uint8_t *c = c_ptr;. El mensaje de error menciona una conversión no válida entre tipos.
user_name
44
¿Podría publicar los 2 archivos de código (o una versión mínima simplificada de ellos) que producen el error, y copiar y pegar el mensaje de error completo?
drodri
Los mensajes de error no son tan bonitos: 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 el

Respuestas:

10

Puede externar "C" #incluir de la siguiente manera:

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

void setup(){
}

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

Y el archivo crc16.h podría ser (algunas correcciones menores, el #pragma una vez, un reparto):

#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
fuente
Gracias, funciona bien ahora. ¿Podría explicar la necesidad de la pragma?
user_name
1
Claro, es una buena práctica, aunque no es necesaria en su ejemplo. Evita que el mismo archivo de encabezado se incluya dos veces en un archivo de compilación. Imagine a.cpp -> (bh y ch) y bh-> ch Eso duplicará el contenido de ch mientras compila a.cpp. El #pragma una vez evita esto. También las directivas de protección #ifndef _MY_FILE_H_INCLUDED #define _MY_FILE_H_INCLUDED son comunes para esto. Sin embargo, tenga en cuenta que, como señala Peter R. Bloomfield, podría ser mejor poner la implementación de CalculateCRC16 en un archivo cpp y dejar solo la declaración en el archivo de encabezado.
drodri
Ok, puedo ver que esto se convierte en un problema cuando el código se vuelve cada vez más complicado. Gracias por el consejo.
user_name
4

Su función CRC se puede convertir fácilmente a C ++ para que pueda ir a un archivo * .cpp. Todo lo que necesita hacer es usar una conversión explícita cuando inicializa su cpuntero. Aquí está la forma 'adecuada' de C ++ para hacerlo:

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

Sin embargo, un antiguo elenco de estilo C también funcionaría:

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

El problema es básicamente que C puede ser un poco más permisivo al permitirle convertir punteros implícitamente entre tipos. Para hacerlo en C ++, debe decirle explícitamente al compilador que la conversión es intencional.

Peter Bloomfield
fuente
1

Sí, solo copie su línea de declaración en su boceto:

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