c++ - ESP32 build in Arduino IDE: undefined reference to `CLASS::function' 错误
问题描述
我尝试在 Arduino IDE 中为 ESP32 的 Sensirion SFM3000 流量传感器编写一个库。只要是一张草图,一切都会奏效。但是当我试图将它分离成一个 .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() 方法在 SFM3019_HSKA.cpp 文件的最后三分之一中调用 crc8() 方法时。到目前为止,我没有看到语法错误。但我对如何继续调试也没有其他想法......
这是我尝试在以下位置使用库的主要代码:
#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;
}
我会非常感谢任何关于如何继续的想法......
解决方案
/* 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;
}
您只是忘记将定义的方法标记为类的一部分。简单的拼写错误。
推荐阅读
- html - 将 iframe 与其他元素内联对齐
- html - Building HTML emails in 2019, can I put styles in the header section or do I still have to use inline styles?
- c# - 带有 Google 存储的 C# - 带有客户加密密钥的签名 URL
- tensorflow - TFLITE python example label_image.py How to run with custom SSD_Inceptionv2 Model?
- git - Cannot Clone Git project From TFS to Ubuntu , Error : fatal: Authentication failed for
- jax-rs - Add annotation to programmatically added child resource via resource builder
- bootstrap-4 - Bootstrap 4 - 网格问题 - 它没有在我期望的地方开始一个新行
- python - Which Python libraries to use for analyzing doc and docx files?
- php - using php file in html
- node.js - An HTML picture src is showing on my live site but not local or in my code