I found a really nice 24 bit I2C adc which was fairly cheap as well (ADS1219) but as far as I could tell there are no libraries for it so I decided to make my own. I have managed to write functions and get everything working on the arduino itself but I've been having massive issues with converting it into a library. So I tried a very basic sketch to see if I can do something as simple as printing hello world using the library. Here is my ADS1219.h file:
#ifndef ADS1219
#define ADS1219
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
class ADS1219{
public:
ADS1219();
void begin();
void printHello();
};
#endif
And the ADS1219.cpp:
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include
ADS1219::ADS1219{
Serial.println("New object created!");
}
void ADS1219::begin(){
Serial.begin(9600);
}
void ADS1219::printHello(){
Serial.println("Hello World");
}
and my main sketch:
#include
ads = new ADS1219;
void setup() {
Serial.begin(9600);
ads.begin();
}
void loop() {
ads.printHello();
delay(2000);
}
but I get this really long error which basically says I've failed with creating the ads object. I tried ADS1219 ads; as well but same error ... not sure what's wrong tbh.
Arduino: 1.8.8 (Windows 10), Board: "Arduino Nano, ATmega328P (Old Bootloader)"
In file included from sketchADS1219.cpp:7:0:
ADS1219.h:14:11: error: expected unqualified-id before ')' token
ADS1219();
^
ADS1219.h:12:14: error: an anonymous struct cannot have function members
class ADS1219{
^
ADS1219.h:18:1: error: abstract declarator '' used as declaration
};
^
ADS1219.cpp:9:17: error: expected id-expression before '{' token
ADS1219::ADS1219{
^
ADS1219.cpp:13:21: error: explicit qualification in declaration of 'void begin()'
void ADS1219::begin(){
^
ADS1219.cpp:17:26: error: explicit qualification in declaration of 'void printHello()'
void ADS1219::printHello(){
^
In file included from C:UsersOM222ODesktopadslibadslib.ino:1:0:
ADS1219.h:14:11: error: expected unqualified-id before ')' token
ADS1219();
^
ADS1219.h:12:14: error: an anonymous struct cannot have function members
class ADS1219{
^
ADS1219.h:18:1: error: abstract declarator '' used as declaration
};
^
adslib:3:1: error: 'ads' does not name a type
ads = new ADS1219;
^
C:UsersOM222ODesktopadslibadslib.ino: In function 'void setup()':
adslib:7:3: error: 'ads' was not declared in this scope
ads.begin();
^
C:UsersOM222ODesktopadslibadslib.ino: In function 'void loop()':
adslib:11:3: error: 'ads' was not declared in this scope
ads.printHello();
^
exit status 1
expected unqualified-id before ')' token
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
3 Answers 3
Your problem stems from this line:
#define ADS1219
You define the macro ADS1219 as empty. From that point on all references to ADS1219 get replaced with nothing. For example:
class ADS1219{
public:
ADS1219();
void begin();
void printHello();
};
becomes:
class {
public:
();
void begin();
void printHello();
};
And
void ADS1219::begin(){
Serial.begin(9600);
}
becomes:
void ::begin(){
Serial.begin(9600);
}
By using the same name in your header guard as your class name you screw everything else up.
I always use strict rules for header guard macros to ensure that they never conflict with anything else. You should change yours to read something else. I would use:
#ifndef _ADS1219_H
#define _ADS1219_H
// ... content
#endif
You are also lacking the parenthesis in the constructor implementation:
ADS1219::ADS1219{
Serial.println("New object created!");
}
should read:
ADS1219::ADS1219(){
Serial.println("New object created!");
}
And you don't give your ads
variable a type and you don't want to use new:
ads = new ADS1219;
should read:
ADS1219 ads;
-
Also in the cpp file he should not include again the Arduino.h file, but rather include only the library file (ADS1219.h). Moreover, in my libraries I stopped including WProgram.h. Do you think it is still required?frarugi87– frarugi872018年12月27日 10:25:24 +00:00Commented Dec 27, 2018 at 10:25
-
I haven't included wprogram.h for ages. It doesn't hurt to include a file multiple times as headers should include header guards.Majenko– Majenko2018年12月27日 10:34:54 +00:00Commented Dec 27, 2018 at 10:34
-
thanks this has fixed my issue for now :D I will try to finis the rest on my own but I still might need some help.I'll publish it as soon as I finishedOM222O– OM222O2018年12月27日 12:28:03 +00:00Commented Dec 27, 2018 at 12:28
Are you sure you're compiling this for C++ and not C?
In any case, you're defining
#define ADS1219
I'm not sure what that does to your class name. Have you tried to
#define ADS1219_H // <- Standard include guard
instead? Does this yield different results.
-
arduino is C itself but the file extension is cpp (c plus plus) so I'm a bit confused myself. Changing it to ADS1219_H yields the same error message.OM222O– OM222O2018年12月26日 21:35:18 +00:00Commented Dec 26, 2018 at 21:35
-
Considering that the class keyword only makes sense in a C++ environment it should be C++ and the compiler should be configured as such. To me, this looks like you're already doing that in the Arduino IDE so it should be configured correctly. Unfortunately I'm out of luck here. Just one sidenote (not related to your issue): You're missing the parantheses on the line where you instantiate your object (the one with the new keyword)Tom L.– Tom L.2018年12月26日 21:48:39 +00:00Commented Dec 26, 2018 at 21:48
-
thanks for pointing that out and yes, I am using the IDE. I'm pretty sure it uses GCC linker and is already configured correctly.OM222O– OM222O2018年12月26日 22:02:48 +00:00Commented Dec 26, 2018 at 22:02
-
Standard include guard
- isnt' that what#pragma once
is used for?Jaromanda X– Jaromanda X2018年12月27日 03:23:28 +00:00Commented Dec 27, 2018 at 3:23 -
1
I have made a lot of progress and almost everything works fine ... except I initially used strings in switch case for setting up the voltage reference and conversion modes ... it did not like it at all. I instead aimed to use enums for the same purpose but I'm getting this error now:
Arduino: 1.8.8 (Windows 10), Board: "Arduino Nano, ATmega328P (Old Bootloader)"
In file included from sketch\LibraryExample1.ino.cpp:1:0:
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:81:18: error: expected identifier before numeric constant
#define INTERNAL 3
^
C:\Users\OM222O\Documents\Arduino\libraries\ADS1219/ADS1219.h:49:3: note: in expansion of macro 'INTERNAL'
INTERNAL = VREF_INTERNAL,
^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:81:18: error: expected '}' before numeric constant
#define INTERNAL 3
^
C:\Users\OM222O\Documents\Arduino\libraries\ADS1219/ADS1219.h:49:3: note: in expansion of macro 'INTERNAL'
INTERNAL = VREF_INTERNAL,
^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:81:18: error: expected unqualified-id before numeric constant
#define INTERNAL 3
^
C:\Users\OM222O\Documents\Arduino\libraries\ADS1219/ADS1219.h:49:3: note: in expansion of macro 'INTERNAL'
INTERNAL = VREF_INTERNAL,
^
In file included from C:\Users\OM222O\Desktop\LibraryExample1\LibraryExample1.ino:2:0:
C:\Users\OM222O\Documents\Arduino\libraries\ADS1219/ADS1219.h:51:1: error: expected declaration before '}' token
}adsRef_t;
^
exit status 1
Error compiling for board Arduino Nano.
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
my ADS1219.h file is:
#ifndef ADS1219_H
#define ADS1219_H
#if (ARDUINO >=100)
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <Wire.h>
#define CONFIG_REGISTER_ADDRESS 0x20
#define STATUS_REGISTER_ADDRESS 0x24
#define MUX_MASK 0x1F
#define MUX_DIFF_0_1 0x00
#define MUX_DIFF_2_3 0x20
#define MUX_DIFF_1_2 0x40
#define MUX_SINGLE_0 0x60
#define MUX_SINGLE_1 0x80
#define MUX_SINGLE_2 0xA0
#define MUX_SINGLE_3 0xC0
#define MUX_SHORTED 0xE0
#define GAIN_MASK 0xEF
#define GAIN_ONE 0x00
#define GAIN_FOUR 0x10
#define DATA_RATE_MASK 0xF3
#define DATA_RATE_20 0x00
#define DATA_RATE_90 0x04
#define DATA_RATE_330 0x08
#define DATA_RATE_1000 0x0c
#define MODE_MASK 0xFD
#define MODE_SINGLE_SHOT 0x00
#define MODE_CONTINUOUS 0x02
#define VREF_MASK 0xFE
#define VREF_INTERNAL 0x00
#define VREF_EXTERNAL 0x01
typedef enum{
ONE = GAIN_ONE,
FOUR = GAIN_FOUR
}adsGain_t;
typedef enum{
INTERNAL = VREF_INTERNAL,
EXTERNAL = VREF_EXTERNAL
}adsRef_t;
typedef enum{
SINGLE_SHOT = MODE_SINGLE_SHOT,
CONTINUOUS = MODE_CONTINUOUS
}adsMode_t;
class ADS1219 {
protected:
uint8_t address;
public:
// Constructor
ADS1219(int drdy, uint8_t addr = 0x40);
// Methods
void begin();
void resetConfig();
long readSingleEnded(int channel);
long readDifferential_0_1();
long readDifferential_2_3();
long readDifferential_1_2();
long readShorted();
void setGain(adsGain_t gain);
void setDataRate(int rate);
void setConversionMode(adsMode_t mode);
void setVoltageReference(adsRef_t vref);
private:
void writeRegister(uint8_t data);
uint8_t readRegister(uint8_t reg);
long readConversionResult();
uint8_t config;
int data_ready;
};
#endif
and my cpp file is:
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <Wire.h>
#include "ADS1219.h"
static uint8_t i2cRead(void) {
#if ARDUINO >= 100
return Wire.read();
#else
return Wire.receive();
#endif
}
static void i2cWrite(uint8_t x) {
#if ARDUINO >= 100
Wire.write(x);
#else
Wire.send(x);
#endif
}
ADS1219::ADS1219(int drdy, uint8_t addr) {
data_ready = drdy;
address = addr;
config = 0x00;
}
void ADS1219::begin() {
Wire.begin();
}
uint8_t ADS1219::readRegister(uint8_t reg){
Wire.beginTransmission(address);
i2cWrite(reg);
Wire.endTransmission();
Wire.requestFrom((uint8_t)address,(uint8_t)1);
return i2cRead();
}
void ADS1219::writeRegister(uint8_t data){
Wire.beginTransmission(address);
i2cWrite(CONFIG_REGISTER_ADDRESS);
i2cWrite(data);
Wire.endTransmission();
}
long ADS1219::readConversionResult(){
Wire.beginTransmission(address);
i2cWrite(0x10);
Wire.endTransmission();
Wire.requestFrom((uint8_t)address,(uint8_t)3);
byte dataMSB = i2cRead();
byte data = i2cRead();
byte dataLSB = i2cRead();
long data32 = dataMSB;
data32 <<= 8;
data32 |= data;
data32 <<= 8;
data32 |= dataLSB;
return (data32 << 8) >> 8;
}
void ADS1219::resetConfig(){
writeRegister(0x00);
}
long ADS1219::readSingleEnded(int channel){
if (channel > 3) return 0;
config &= MUX_MASK;
switch (channel){
case (0):
config |= MUX_SINGLE_0;
break;
case (1):
config |= MUX_SINGLE_1;
break;
case (2):
config |= MUX_SINGLE_2;
break;
case (3):
config |= MUX_SINGLE_3;
break;
default:
break;
}
writeRegister(config);
while(digitalRead(data_ready)==1);
return readConversionResult();
}
long ADS1219::readDifferential_0_1(){
config &= MUX_MASK;
config |= MUX_DIFF_0_1;
writeRegister(config);
while(digitalRead(data_ready)==1);
return readConversionResult();
}
long ADS1219::readDifferential_2_3(){
config &= MUX_MASK;
config |= MUX_DIFF_2_3;
writeRegister(config);
while(digitalRead(data_ready)==1);
return readConversionResult();
}
long ADS1219::readDifferential_1_2(){
config &= MUX_MASK;
config |= MUX_DIFF_1_2;
writeRegister(config);
while(digitalRead(data_ready)==1);
return readConversionResult();
}
long ADS1219::readShorted(){
config &= MUX_MASK;
config |= MUX_SHORTED;
writeRegister(config);
while(digitalRead(data_ready)==1);
return readConversionResult();
}
void ADS1219::setGain(adsGain_t gain){
config &= GAIN_MASK;
config |= gain;
writeRegister(config);
}
void ADS1219::setDataRate(int rate){
config &= DATA_RATE_MASK;
switch (rate){
case (20):
config |= DATA_RATE_20;
break;
case (90):
config |= DATA_RATE_90;
break;
case (330):
config |= DATA_RATE_330;
break;
case (1000):
config |= DATA_RATE_1000;
break;
default:
break;
}
writeRegister(config);
}
void ADS1219::setConversionMode(adsMode_t mode){
config &= MODE_MASK;
config |= mode;
writeRegister(config);
}
void ADS1219::setVoltageReference(adsRef_t vref){
config &= VREF_MASK;
config |= vref;
writeRegister(config);
}
it seems to be passing Gain (or maybe hasn't compiled that yet) but failing on the reference selection ... I don't know what I should change in order to fix the issue.
Edit: I'm really hoping it's not another naming convention thing ... if it is, I'm sorry but C++ seems to waaaaayyyy too picky about names in general
-
Hint: Use a private enum for all the control codes etc. Using #define is old-school and actually the root-cause of many of the issues. C++ allow namespaces, private, const, etc, which is much more semantic rich. Here is an example to help you along; github.com/mikaelpatel/Cosa/blob/master/libraries/ADXL345/…Mikael Patel– Mikael Patel2018年12月27日 18:39:30 +00:00Commented Dec 27, 2018 at 18:39
-
Hint: To avoid some of the constants, masks, etc, it is possible to use bit-fields in struct's. Here is an example: github.com/mikaelpatel/Cosa/blob/master/libraries/DS2482/…Mikael Patel– Mikael Patel2018年12月27日 18:43:33 +00:00Commented Dec 27, 2018 at 18:43
-
thanks a lot! I'll have a look. I'm most of the way finished with the program :DOM222O– OM222O2018年12月27日 18:49:05 +00:00Commented Dec 27, 2018 at 18:49
#include
without specifying which file to include? In the sketch aads ADS1219;
is enough. Github is full of arduino libraries, you can find many examples there, for example: github.com/Locoduino/SlowMotionServo/tree/master/src and github.com/winlinvip/SimpleDHT (just two random chosen libraries, there must be hundreds of them).