Como chamar funções C do esboço do Arduino?

10

Gostaria de saber se existe uma maneira de chamar funções contidas em arquivos C usando um esboço do Arduino?

Meu arquivo C declara e define uma função. Para poupar a definição da função bagunçada no meu esboço do Arduino, gostaria de chamar a função diretamente do esboço.

Existe uma maneira padrão de fazer isso usando Arduino e C? Aqui está o esboço:

#include "crc16.h";

void setup(){

}

void loop(){

  CalculateCRC16("<09M", 4);

}

e este é o arquivo C aparado:

#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;
}
nome do usuário
fonte
Existe uma razão pela qual seu arquivo precisa usar C em vez de C ++?
Peter Bloomfield
Na verdade sim. Quando tento compilar o arquivo usando C ++, há erros, mas não há erros em C. O erro é causado pelas linhas: const void *c_ptre const uint8_t *c = c_ptr;. A mensagem de erro menciona uma conversão inválida entre tipos.
user_name
4
Você poderia postar os 2 arquivos de código (ou uma versão mínima simplificada deles) que produzem o erro e copiar e colar a mensagem de erro na íntegra?
drodri
As mensagens de erro não são tão bonitas: 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 27/03

Respostas:

10

Você pode incluir "C" externo como o seguinte:

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

void setup(){
}

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

E o arquivo crc16.h pode ser (algumas pequenas correções, o #pragma uma vez, um elenco):

#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
fonte
Obrigado, funciona muito bem agora. Poderia explicar a necessidade do pragma?
user_name
11
Claro, é uma boa prática, embora não seja necessária no seu exemplo. Evita que o mesmo arquivo de cabeçalho seja incluído duas vezes em um arquivo de compilação. Imagine a.cpp -> (bh e ch) e bh-> ch Isso duplicará o conteúdo de ch durante a compilação do a.cpp. O #pragma evita isso uma vez. Também proteja as diretivas #ifndef _MY_FILE_H_INCLUDED #define _MY_FILE_H_INCLUDED são comuns para isso. Observe, no entanto, que, como aponta Peter R. Bloomfield, talvez seja melhor colocar a implementação do CalculateCRC16 em um arquivo cpp e deixar apenas a declaração no arquivo de cabeçalho.
drodri
Ok, posso ver isso se tornando um problema quando o código se torna cada vez mais complicado. Obrigado pelo conselho.
user_name
4

Sua função CRC pode ser facilmente convertida em C ++ para que possa entrar em um arquivo * .cpp. Tudo o que você precisa fazer é usar uma conversão explícita ao inicializar o cponteiro. Aqui está a maneira 'adequada' de C ++ de fazer isso:

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

No entanto, um elenco antigo de estilo C também funcionaria:

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

O problema é basicamente que C pode ser um pouco mais permissivo em permitir converter ponteiros implicitamente entre tipos. Para fazer isso em C ++, você precisa informar explicitamente ao compilador que a conversão é intencional.

Peter Bloomfield
fonte
1

Sim, basta copiar sua linha de declaração no seu esboço:

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