Bagaimana cara memanggil fungsi C dari sketsa Arduino?


10

Saya ingin tahu apakah ada cara untuk memanggil fungsi yang terdapat dalam file C menggunakan sketsa Arduino?

File C saya mendeklarasikan dan mendefinisikan suatu fungsi. Untuk menyimpan menempatkan definisi fungsi yang berantakan ke dalam sketsa Arduino saya, saya ingin memanggil fungsi langsung dari sketsa.

Apakah ada cara standar untuk melakukan ini menggunakan Arduino dan C? Ini sketsanya:

#include "crc16.h";

void setup(){

}

void loop(){

  CalculateCRC16("<09M", 4);

}

dan ini adalah file C yang dipangkas:

#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;
}

Apakah ada alasan mengapa file Anda harus menggunakan C bukan C ++?
Peter Bloomfield

Sebenarnya ya. Ketika saya mencoba untuk mengkompilasi file menggunakan C ++, ada kesalahan, tetapi bebas kesalahan dalam C. Kesalahan ini disebabkan oleh baris: const void *c_ptrdan const uint8_t *c = c_ptr;. Pesan kesalahan menyebutkan konversi yang tidak valid antara jenis.
user_name

4
Bisakah Anda memposting 2 file kode (atau versi minimal yang disederhanakan) yang menghasilkan kesalahan, dan menyalin & menempel pesan kesalahan secara penuh?
drodri

Pesan kesalahan tidak begitu cantik: 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

Jawaban:


10

Anda dapat menggunakan "C" #include seperti yang berikut:

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

void setup(){
}

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

Dan file crc16.h bisa berupa (beberapa perbaikan kecil, #pragma sekali, seorang pemain):

#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;
}

Terima kasih, itu berfungsi dengan baik sekarang. Bisakah Anda jelaskan kebutuhan pragma?
user_name

1
Tentu, ini adalah praktik yang baik, meskipun itu tidak diperlukan dalam contoh Anda. Ini menghindari file header yang sama untuk dimasukkan dua kali dalam file kompilasi. Bayangkan a.cpp -> (bh dan ch) dan bh-> ch Itu akan menduplikasi konten ch saat mengkompilasi a.cpp. #Pragma sekali menghindari ini. Juga jaga arahan #jika_MY_FILE_H_INCLUDED #define _MY_FILE_H_INCLUDED adalah umum untuk ini. Namun, perhatikan bahwa seperti yang ditunjukkan oleh Peter R. Bloomfield, mungkin lebih baik untuk meletakkan implementasi CalculateCRC16 dalam file cpp, dan meninggalkan hanya deklarasi dalam file header.
drodri

Oke, saya bisa melihat itu menjadi masalah ketika kode semakin rumit. Terima kasih atas sarannya.
user_name

4

Fungsi CRC Anda dapat dengan mudah dikonversi ke C ++ sehingga dapat masuk ke file * .cpp. Yang perlu Anda lakukan adalah menggunakan gips eksplisit ketika Anda menginisialisasi cpointer Anda . Inilah cara 'pantas' C ++ untuk melakukannya:

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

Namun, pemeran gaya C lama juga akan bekerja:

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

Masalahnya pada dasarnya adalah bahwa C dapat sedikit lebih permisif tentang membiarkan Anda mengkonversi pointer secara implisit antara tipe. Untuk melakukannya di C ++, Anda perlu memberi tahu kompiler secara eksplisit bahwa konversi disengaja.


1

Ya, cukup salin baris deklarasi di sketsa Anda:

extern "C" {
    void myfunction(int arg);
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.