Passing an I2C object to a library

I've been trying to get this to work for quite some time now, and still don't see the light at the end of the tunnel. And since i'm not the sharpest tool in the shed, i'm happy to ask the silly questions as i'm sure i'm not the only tool needing help :wink:

quick overview:
I'm trying to make my arduino do everything over I2C. I'm using the LiquidCrystal_I2C library for the display (working fine). But now I want to use a TC74A* temperature sensor to get the temp. Since I want a few of them I decided to write a little library for them myself. And I want to initialize them in the main program using something like

TC74A_Control tSens = TC74A_Control(??, address)

I've been playing around with my library so it's far from good, i'm just trying to get the passing of the I2C part to work. Here it is...

the TC74A_Control.h file

#ifndef TC74A_Control_h
#define TC74A_control_h

#include "Arduino.h"
#include "Wire.h"
#include "Stream.h"

class TC74A_Control
{
  public:
    //TC74A_Control(Stream& s, int sensAdr):draad(s){}
    TC74A_Control(Stream& s, int sensAdr);
    int readTemp();

  private:
    int _SENSOR_ADDRESS;
    Stream& draad;

};

#endif

and the TC74A_Control.cpp file:

#include "Arduino.h"
#include "Wire.h"
#include "Stream.h"

#include "TC74A_Control.h"


TC74A_Control::TC74A_Control(Stream& s, int sensAdr)
{
  draad(s);
  _SENSOR_ADDRESS = sensAdr;
}

/*
 * Public functies
 */

int TC74A_Control::readTemp()
{
  draad.beginTransmission(_SENSOR_ADDRESS);
  draad.write(0);
  draad.endTransmission();
  draad.requestFrom(_SENSOR_ADDRESS, 1);

  while(draad.available() == 0);

  int t = draad.read();

  return t;
}

but when i compile this, well, it all goes pear shaped.
trying to figure out the error messages, but if anyone has any input, it would be greatly appreciated...

trying to figure out the error messages, but if anyone has any input, it would be greatly appreciated..

So, in addition to guessing what the sketch looks like, you want us to guess what the errors are and what they mean. Not me. I hate guessing games.

I don't understand what passing a Stream object to the constructor has to do with I2C.

i'm happy to oblige if you want to see it in a sketch:

#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
#include "timerControl.h"
#include "TC74A_Control.h"

LiquidCrystal_I2C lcd(0x20,16,2);  // set the LCD address to 0x20 for a 16 chars and 2 line display

timerControl LCD_timer = timerControl(1000);

//TC74A_Control tempSens = TC74A_Control();

void setup()
{
  //Serial.begin(9600);
  lcd.init();                      // initialize the lcd 
 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.print("Hello, world!");
  LCD_timer.startTimer();

  Wire.begin();
  TC74A_Control tempSens = TC74A_Control(Wire, 72);
}

void loop()
{
  if(LCD_timer.timerAfgelopen())
    refreshLcd();
}

void refreshLcd()
{
  lcd.clear();
  lcd.print("Timer done");
}

and the error messages are:

TC74A_Control.cpp: In constructor 'TC74A_Control::TC74A_Control(Stream&, int)':
TC74A_Control.cpp:8: error: uninitialized reference member 'TC74A_Control::draad' [-fpermissive]
 TC74A_Control::TC74A_Control(Stream& s, int sensAdr)
 ^
TC74A_Control.cpp:10: error: no match for call to '(Stream) (Stream&)'
   draad(s);
          ^
TC74A_Control.cpp: In member function 'int TC74A_Control::readTemp()':
TC74A_Control.cpp:20: error: 'class Stream' has no member named 'beginTransmission'
   draad.beginTransmission(_SENSOR_ADDRESS);
         ^
TC74A_Control.cpp:21: error: call of overloaded 'write(int)' is ambiguous
   draad.write(0);
                ^
TC74A_Control.cpp:21:16: note: candidates are:
In file included from d:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Stream.h:26:0,
                 from d:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/HardwareSerial.h:29,
                 from d:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Arduino.h:224,
                 from TC74A_Control.cpp:1:
d:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:48:20: note: virtual size_t Print::write(uint8_t)
     virtual size_t write(uint8_t) = 0;
                    ^
d:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino/Print.h:49:12: note: size_t Print::write(const char*)
     size_t write(const char *str) {
            ^
TC74A_Control.cpp:22: error: 'class Stream' has no member named 'endTransmission'
   draad.endTransmission();
         ^
TC74A_Control.cpp:23: error: 'class Stream' has no member named 'requestFrom'
   draad.requestFrom(_SENSOR_ADDRESS, 1);
         ^
uninitialized reference member 'TC74A_Control::draad' [-fpermissive]

but in essence it doesn't even matter. Can I pass an I2C bus that I initialize in the main program with Wire.begin(); to another library? Or shouldn't I see this as something that can be passed around and just pass the address of the thing i'm trying to reach to the library?
And i'm sorry if I'm not using the correct terminology, I tend to mix the terms up.

I see that you basically ignored the important second paragraph of reply #1.

I thought Wire was part of stream, my bad.

Oh and people, relax, take a deep breath. I'm doing this for fun... remember fun? :slight_smile: I was curious about something and couldn't find a straight forward answer, so I thought i'd try here. This being a Question forum and all. Anyway, i'll just pass the address.

  TC74A_Control tempSens = TC74A_Control(Wire, 72);

It's pointless to create a local variable that immediately goes out of scope.

Still missing the point, put it wherever you want, that's not the issue here

This is one of those things where the Arduino environment is unhelpful. When your object is initialized, how do you know that the Stream object was initialized first? It actually tries to call the constructor for Stream "inside" your constructor, which fails. There are ways to tell it the right way to do it but usually it's easier to work around the problem.

Look at how the LCD library works. I bet it doesn't take an argument to tell it which instance of Wire to use. This means that it can't be used on Wire1 on a Due or Teensy without modifying the library.

Either you never run this on the 2nd I2C port or you do a #define above the #include for your library to tell it which one to use.

simon_theys:
Can I pass an I2C bus that I initialize in the main program with Wire.begin(); to another library?

Wire is global, so there's really no need to "pass it around" - any code, anywhere in the program has access to it. But there is nothing wrong with passing a pointer or reference to Wire, Wire1, Serial, or any other class to anywhere you want to, as long as the object being referenced isn't destroyed using delete.

Regards,
Ray L.

I just read a good explanation about the dangers of linkage between different classes. And why keeping it to a minimum is a good thing. So I guess I'll end up just passing along the address instead.

But you make an excellent point as well, how to differentiate between I2C ports when you were to use them in a function in a different library? How would the syntax look like when you'd like to pass a pointer to the constructor (or function) of said library?

Oh yeah, I looked around in the I2C LCD library i'm using and it does indeed presume you only have one I2C port to work with. So having 2 screens on two ports would require a bit of library tweaking :slight_smile:

Anyway, thanks for the excellent feedback so far y'all!