Как вызвать функции C из скриншота Arduino?

10

Я хотел бы знать, есть ли способ вызова функций, которые содержатся в файлах C, используя эскиз Arduino?

Мой C-файл объявляет и определяет функцию. Чтобы не вносить грязное определение функции в мой эскиз Arduino, я бы хотел вызвать функцию прямо из эскиза.

Есть ли стандартный способ сделать это, используя Arduino и C? Вот эскиз:

#include "crc16.h";

void setup(){

}

void loop(){

  CalculateCRC16("<09M", 4);

}

и это урезанный файл 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;
}
user_name
источник
Есть ли причина, по которой ваш файл должен использовать C вместо C ++?
Питер Блумфилд,
На самом деле да. Когда я пытаюсь скомпилировать файл с использованием C ++, возникают ошибки, но он не содержит ошибок в C. Ошибка вызвана строками: const void *c_ptrи const uint8_t *c = c_ptr;. В сообщении об ошибке упоминается недопустимое преобразование между типами.
user_name
4
Не могли бы вы опубликовать 2 файла кода (или их упрощенную минимальную версию), которые вызывают ошибку, и скопировать и вставить сообщение об ошибке полностью?
Дродри
Сообщения об ошибках не такие красивые: 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

Ответы:

10

Вы можете ввести "C" #include следующим образом:

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

void setup(){
}

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

И файл crc16.h может быть (некоторые мелкие исправления, однажды #pragma, приведение):

#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
источник
Спасибо, теперь все работает отлично. Не могли бы вы объяснить необходимость прагмы?
user_name
1
Конечно, это хорошая практика, хотя в вашем примере она не нужна. Это позволяет избежать включения одного и того же заголовочного файла дважды в файл компиляции. Представьте себе a.cpp -> (bh и ch) и bh-> ch, которые будут дублировать содержимое ch при компиляции a.cpp. Однажды #pragma этого избежать. Также для этого распространены защитные директивы #ifndef _MY_FILE_H_INCLUDED #define _MY_FILE_H_INCLUDED. Однако обратите внимание, что, как указывает Питер Р. Блумфилд, было бы лучше поместить реализацию CalculateCRC16 в файл cpp и оставить только объявление в заголовочном файле.
Дродри
Хорошо, я вижу, что это становится проблемой, когда код становится все более и более сложным. Спасибо за совет.
user_name
4

Ваша функция CRC может быть легко преобразована в C ++, чтобы она могла перейти в файл * .cpp. Все, что вам нужно сделать, это использовать явное приведение при инициализации cуказателя. Вот «правильный» C ++ способ сделать это:

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

Тем не менее, старый C-стиль также будет работать:

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

Проблема в основном в том, что C может позволить вам неявно преобразовывать указатели между типами. Чтобы сделать это в C ++, вам нужно явно указать компилятору, что преобразование является преднамеренным.

Питер Блумфилд
источник
1

Да, просто скопируйте строку декларации в свой эскиз:

extern "C" {
    void myfunction(int arg);
}
jfpoilpret
источник