วิธีการเรียกฟังก์ชั่น 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;
}

มีเหตุผลทำไมไฟล์ของคุณต้องใช้ C แทน C ++?
Peter Bloomfield

จริง ๆ แล้วใช่ เมื่อฉันพยายามที่จะรวบรวมไฟล์โดยใช้ C ++ มีข้อผิดพลาด แต่มันเป็นข้อผิดพลาดใน C. ข้อผิดพลาดที่เกิดจากเส้น: และconst void *c_ptr const uint8_t *c = c_ptr;ข้อความแสดงข้อผิดพลาดกล่าวถึงการแปลงที่ไม่ถูกต้องระหว่างประเภท
user_name

4
คุณช่วยกรุณาโพสต์ไฟล์รหัส 2 ไฟล์ (หรือเวอร์ชั่นขั้นต่ำสุดของพวกมัน) ที่ทำให้เกิดข้อผิดพลาดและคัดลอกและวางข้อความแสดงข้อผิดพลาดได้ไหม?
drodri

ข้อความแสดงข้อผิดพลาดไม่ได้สวยมาก: 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" # รวมเช่นต่อไปนี้:

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

ขอบคุณมันใช้งานได้ดีตอนนี้ คุณช่วยอธิบายความจำเป็นของการใช้ pragma ได้ไหม?
user_name

1
แน่นอนว่ามันเป็นวิธีปฏิบัติที่ดีแม้ว่าจะไม่จำเป็นในตัวอย่างของคุณ มันหลีกเลี่ยงไฟล์ส่วนหัวเดียวกันที่จะรวมสองครั้งในไฟล์รวบรวม ลองนึกภาพ a.cpp -> (bh และ ch) และ bh-> ch นั่นจะทำซ้ำเนื้อหาของ ch ในขณะที่คอมไพล์ a.cpp #pragma หลีกเลี่ยงสิ่งนี้ครั้งเดียว และปกป้องคำสั่ง #ifndef _MY_FILE_H_INCLUDED #define _MY_FILE_H_INCLUDED เป็นเรื่องปกติ อย่างไรก็ตามโปรดทราบว่าตามที่ Peter R. Bloomfield ชี้ให้เห็นอาจเป็นการดีกว่าที่จะนำการใช้งาน CalculateCRC16 ไปใช้ในไฟล์ cpp และปล่อยให้การประกาศในไฟล์ส่วนหัวนั้นดีกว่า
drodri

ตกลงฉันจะเห็นว่าเป็นปัญหาเมื่อรหัสมีความซับซ้อนมากขึ้น ขอบคุณสำหรับคำแนะนำ.
user_name

4

ฟังก์ชัน CRC ของคุณสามารถแปลงเป็น C ++ ได้อย่างง่ายดายเพื่อให้สามารถเข้าไปในไฟล์ * .cpp สิ่งที่คุณต้องทำคือใช้ตัวละครที่ชัดเจนเมื่อคุณเริ่มต้นcตัวชี้ของคุณ นี่คือวิธี 'ถูกต้อง' ในการทำ C ++:

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

อย่างไรก็ตามตัวละคร C-style แบบเก่าก็ยังใช้งานได้:

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.