ArduinoスケッチからC関数を呼び出す方法は?


10

Arduinoのスケッチを使用してCファイルに含まれている関数を呼び出す方法があるかどうか知りたいのですが?

私の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;
}

ファイルでC ++ではなくCを使用する必要がある理由はありますか?
Peter Bloomfield

実はそうです。私はC ++を使用してファイルをコンパイルしようとすると、そこにエラーがありますが、それはエラーがラインによって引き起こされるC.にエラーフリーである:const void *c_ptrconst uint8_t *c = c_ptr;。エラーメッセージは、タイプ間の無効な変換について言及しています。
user_name 2014年

4
エラーを生成する2つのコードファイル(またはそれらの簡略化された最小バージョン)を投稿して、エラーメッセージ全体をコピーして貼り付けてもらえますか?
drodri 2014年

エラーメッセージはそれほどきれいではありません In function uint16_t CalculateCRC16(uint16_t, const void*, size_t)': 46 invalid conversion from 。constvoid * '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できます。

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

void setup(){
}

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

そして、crc16.hファイルは次のようになります(いくつかのマイナーな修正、#pragma 1回、キャスト):

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

おかげで、今は問題なく動作します。プラグマの必要性について説明していただけますか?
user_name 2014年

1
確かに、これは良い例ですが、例では必要ありません。同じヘッダーファイルがコンパイルファイルに2回含まれるのを防ぎます。a.cpp->(bh and ch)とbh-> chを想像してください。これは、a.cppのコンパイル中にchの内容を複製します。#pragmaはこれを回避します。また、ガードディレクティブ#ifndef _MY_FILE_H_INCLUDED #define _MY_FILE_H_INCLUDEDが一般的です。ただし、Peter R. Bloomfieldが指摘しているように、CalculateCRC16の実装をcppファイルに入れ、宣言だけをヘッダーファイルに残した方がよい場合があることに注意してください。
drodri 2014年

OK、コードがますます複雑になると問題になることがわかります。アドバイスありがとうございます。
user_name 2014年

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);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.