Сборка ESP32 в Arduino IDE: неопределенная ссылка на ошибку `CLASS :: function '

Я попытался написать библиотеку для датчика потока Sensirion SFM3000 в среде Arduino IDE для ESP32. Пока это был один набросок, все работало. Но когда я попытался разделить его на файлы .h и .cpp и реализовать его как класс, я получаю странную ошибку, когда пытаюсь скомпилировать скетч.

sketch\SFM3019_HSKA.cpp.o:(.literal._ZN12SFM3019_HSKA17i2c_read_flow_CRCEv+0x4): undefined reference to `SFM3019_HSKA::crc8(unsigned char, unsigned char)'
sketch\SFM3019_HSKA.cpp.o: In function `SFM3019_HSKA::i2c_read_flow_CRC()':
sketch/SFM3019_HSKA.cpp:124: undefined reference to `SFM3019_HSKA::crc8(unsigned char, unsigned char)'
sketch/SFM3019_HSKA.cpp:128: undefined reference to `SFM3019_HSKA::crc8(unsigned char, unsigned char)'
collect2.exe: error: ld returned 1 exit status
exit status 1
Fehler beim Kompilieren für das Board ESP32 Dev Module.

Насколько я понимаю, сообщение об ошибке возникает, когда метод i2c_read_flow_CRC () вызывает метод crc8 () в последней трети файла SFM3019_HSKA.cpp. К настоящему времени я не вижу ошибок в синтаксисе. Но у меня также нет другого представления о том, как продолжить отладку ...

Это основной код, в котором я пытаюсь использовать библиотеку:

#include "SFM3019_HSKA.h"
#include <Wire.h>


SFM3019_HSKA::SensVal_s SensVal = {0, 0, 0};

SFM3019_HSKA SFM3019(0x2E); //Generate Object SFM3019 of class SFM3019_HSKA
 
void setup() {
  // put your setup code here, to run once:
  Serial.begin (115200);
  delay(100);  
  Wire.begin (21, 22);   // for ESP32: SDA= GPIO_21 /SCL= GPIO_22

  SFM3019.i2c_device_check();  //checks if I2C device is available
  SFM3019.i2c_write(0x3608); //write 2Byte to start continuous measurement
  delay(100);
}

void loop() {
  // put your main code here, to run repeatedly:

  
  SensVal.flow = SFM3019.i2c_read_flow_CRC();  //read only Flow Bytes
  Serial.println(SensVal.flow, 10);
  delay(100);
  SensVal = SFM3019.i2c_read_all();  //read all Sensor Bytes
  Serial.print("Flow: ");
  if (SensVal.flow >= 0) Serial.print(" "); //just for beauty reasons
  Serial.print(SensVal.flow,10);
  Serial.print("  Temp: ");
  Serial.print(SensVal.temp,3);
  Serial.print("  Statusword: ");
  Serial.print(SensVal.statusword, HEX);
  delay(400);
  Serial.println();
}

и это файлы библиотеки: SFM3019_HSKA.h

#ifndef SFM3019_HSKA_H  // include guard
#define SFM3019_HSKA_H  

#include "Arduino.h"



    class SFM3019_HSKA {
      
    public: //can be accessed public

        SFM3019_HSKA(uint8_t i2cAddress); //Constructor
    
        //may be nicer in private if it works anyway
        typedef struct {float flow; float temp; int16_t statusword;} SensVal_s; //Struct for complete Sensor Readout
        SensVal_s SensVal = {0, 0, 0};  //initialize with 0

        int8_t i2c_device_check(); //function for Initialisation
        int8_t i2c_write(const uint16_t SendData); //function to write 16Bit Data to sensor
        SensVal_s i2c_read_all();  //function to read Flow, Temperature and Statusword
        float i2c_read_flow(); //function to only read Flow
        float i2c_read_flow_CRC(); //function to only read Flow with CRC check



    private:  //can only be accessed by functions oh same object
        
        uint8_t SFM3019addr = 46; //SFM3019 I2C Adress: 46 / 0x2E
        uint8_t crc8(const uint8_t data, uint8_t crc);  //fuction for CRC confirmation
    };

#endif

и файл C ++, приводящий к ошибке: SFM3019_HSKA.cpp:

#include "SFM3019_HSKA.h" //when placed in same folder
//#include <SFM3019_HSKA.h> //when placed in standard library folder
#include <Wire.h>

//  some values needed for calculation of physical flow and temperature values
#define SFM3019Offset 24576
#define SFM3019ScaleFactorFlow 170.0 //needs to be a float, otherwise it will not calculate in float
#define SFM3019ScaleFactorTemp 200.0 //needs to be a float, otherwise it will not calculate in float


SFM3019_HSKA::SFM3019_HSKA(uint8_t i2cAddress)  //constructor
{
  //: mI2cAddress(i2cAddress)
  SFM3019addr = i2cAddress;
}


/*  checks if a Device at the desired address is responding with an ACK */
int8_t SFM3019_HSKA::i2c_device_check(){
  Wire.beginTransmission(SFM3019addr);    // Begin I2C transmission Address (i)
  if (Wire.endTransmission() == 0)  // Receive 0 = success (ACK response) 
    {
      Serial.print ("Found Seosor at address");
      Serial.print (SFM3019addr, DEC);
      Serial.print (" (0x");
      Serial.print (SFM3019addr, HEX);     // 7 bit address
      Serial.println (")");
      return 0;                        //0=device sent ACK
      
    }else{
      
      Serial.print ("Did not receive Acknowledge from I2C address ");
      Serial.print (SFM3019addr, DEC);
      Serial.print (" (0x");
      Serial.print (SFM3019addr, HEX);     // 7 bit address
      Serial.println (")");
      return 1;                        //no ACK received
    }
}



/*  writes a 16bit "SendData" to I2C Bus Device "address" */
int8_t SFM3019_HSKA::i2c_write(const uint16_t SendData) {
    Wire.beginTransmission(SFM3019addr);
    //fill I2C outbuffer
    Wire.write((SendData>>8)& 0xFF); //isolate HighByte
    Wire.write(SendData & 0xFF); //isolate LowByte
    //send I2C outbuffer
    Wire.endTransmission();

    return 0;
}



/*  reads all 9 measurement bytes for flow, temp and status */
SFM3019_HSKA::SensVal_s SFM3019_HSKA::i2c_read_all(){
    SensVal_s SensVal = {0};  //create empty struct
    Wire.requestFrom(SFM3019addr, 9, true); // Request 9byte (3x16bit + CRC) from the sensor
   //while(Wire.available()<3){};  //wait for all the data to be received //ATTENTION may be critical loop forever, however not using this may lead to an error, as the Buffer may be processed faster, then the input is read on I2C
    
    //get Flow Bytes
    int16_t flow = Wire.read()<<8;  //get Highbyte and shift 8bit to 8MSB
    flow = flow | Wire.read();      //get Lowbyte 8LSB
    byte CRCflow = Wire.read();         //get CRC Check Byte (you could do a data validy check with that)    
    //Serial.println(flow, HEX);    //raw values for debugging
    SensVal.flow = (flow + SFM3019Offset) / SFM3019ScaleFactorFlow; //calculate the flow in slm as Datasheet mentions        

    //get Temperature Bytes
    int16_t temp = Wire.read()<<8;  //get Highbyte and shift 8bit to 8MSB
    temp = temp | Wire.read();      //get Lowbyte 8LSB
    byte CRCtemp = Wire.read();         //get CRC Check Byte (you could do a data validy check with that)    
    //Serial.println(temp, HEX);    //raw values for debugging
    SensVal.temp = temp / SFM3019ScaleFactorTemp; //calculate the flow in slm as Datasheet mentions        

    //get StatusWord Bytes
    int16_t stat = Wire.read()<<8;  //get Highbyte and shift 8bit to 8MSB
    stat = stat | Wire.read();      //get Lowbyte 8LSB
    byte CRCstat = Wire.read();         //get CRC Check Byte (you could do a data validy check with that)    
    //Serial.println(stat, HEX);    //raw values for debugging
    SensVal.statusword = temp / SFM3019ScaleFactorTemp; //calculate the flow in slm as Datasheet mentions        

    //return all data
    return SensVal;
    
}



/*  reads only first 3 bytes for flow and does NO CRC!*/
float SFM3019_HSKA::i2c_read_flow(){
    Wire.requestFrom(SFM3019addr, 3, true); // Request 9byte (2x16bit + CRC) from the sensor
    //while(Wire.available()<3){};  //wait for all the data to be received //ATTENTION may be critical loop forever, however not using this may lead to an error, as the Buffer may be processed faster, then the input is read on I2C
    int16_t flow = Wire.read()<<8;  //get Highbyte and shift 8bit to 8MSB
    flow = flow | Wire.read();      //get Lowbyte 8LSB
    byte CRC = Wire.read();         //get CRC Check Byte (you could do a data validy check with that)    
    //Serial.println(flow, HEX);    //raw values for debugging
    return (flow + SFM3019Offset) / SFM3019ScaleFactorFlow; //calculate the flow in slm as Datasheet mentions  
}

/*  reads only first 3 bytes for flow and DOES CRC*/
float SFM3019_HSKA::i2c_read_flow_CRC(){
    Wire.requestFrom(SFM3019addr, 3, true); // Request 9byte (2x16bit + CRC) from the sensor
    //while(Wire.available()<3){};  //wait for all the data to be received //ATTENTION may be critical loop forever, however not using this may lead to an error, as the Buffer may be processed faster, then the input is read on I2C
    uint8_t Highbyte = Wire.read();    //get Highbyte 8MSB
    uint8_t Lowbyte =  Wire.read();      //get Lowbyte 8LSB
    uint8_t CRC = Wire.read();         //get CRC Check Byte

    //Confirm CRC
    uint8_t mycrc = 0xFF; // initialize crc variable
    mycrc = crc8(Highbyte, mycrc); // let first byte through CRC calculation
    mycrc = crc8(Lowbyte, mycrc); // and the second byte too
    if (mycrc != CRC) { // check if the calculated and the received CRC byte matches
      //Serial.println("Error: wrong CRC");
      return -10000;  //extreme low value, so user knows somethig is wrong
    } else {
      //Serial.println("Success: identical CRC");
      int16_t flow = (Highbyte<<8) | Lowbyte; //stack the to bytes together as signed int16
      return (flow + SFM3019Offset) / SFM3019ScaleFactorFlow; //calculate the flow in slm as Datasheet mentions  
    }
}

/*  calculate a CRC Byte, (Cyclic Redundancy Check) */
uint8_t crc8(const uint8_t data, uint8_t crc)
{
     crc ^= data;                     //crc XOR data
     for ( uint8_t i = 8; i; --i ) {
       crc = ( crc & 0x80 )           
       ? (crc << 1) ^ 0x31
       : (crc << 1);
    }
  return crc;
}

Я был бы очень благодарен за любую идею, как продолжить ...


person Uwe    schedule 18.09.2020    source источник


Ответы (1)


/*  calculate a CRC Byte, (Cyclic Redundancy Check) */
uint8_t crc8(const uint8_t data, uint8_t crc)
{
     crc ^= data;                     //crc XOR data
     for ( uint8_t i = 8; i; --i ) {
       crc = ( crc & 0x80 )           
       ? (crc << 1) ^ 0x31
       : (crc << 1);
    }
  return crc;
}

Должно быть:

/*  calculate a CRC Byte, (Cyclic Redundancy Check) */
uint8_t SFM3019_HSKA::crc8(const uint8_t data, uint8_t crc)
{
     crc ^= data;                     //crc XOR data
     for ( uint8_t i = 8; i; --i ) {
       crc = ( crc & 0x80 )           
       ? (crc << 1) ^ 0x31
       : (crc << 1);
    }
  return crc;
}

Вы просто забыли отметить определенный метод как часть класса. Простая опечатка.

person Delta_G    schedule 18.09.2020
comment
О, черт побери, большое спасибо. Не видеть леса со всеми деревьями вокруг. Ты спас мои выходные! :) - person Uwe; 18.09.2020