Create Object in Class from other class .

Hello community,

First, I apologize about my bad English writing and my low level in C . I’m french and use rarely English

So , my project !

I would like play with a 4 characters Digital Display. ( it’s probably from à alarm clock )
On the board, with Digital displays, we see two chips “Shift register” ( MC74HC595 ).
We can drive it with 3 pins , datas, shift, and latch .
To have a correct result , we must send 16 bits datas , each bit enabled with the shift pin and finally validate with latch pin.

So, I must create a “serial” interface or something like this.

I created a class Named “Serialise” who send a sequence.
(Source is more interesting)

Serialise.cpp

#include "Serialise.h"
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

Serialise::Serialise( uint8_t pin_data, uint8_t pin_clock,  uint8_t pin_latch ,uint8_t nb_bits ,long tmp_delay)
{
    init(pin_data,pin_clock,pin_latch,nb_bits,tmp_delay);
}
void Serialise::init( uint8_t pin_data, uint8_t pin_clock,  uint8_t pin_latch ,uint8_t nb_bits ,long tmp_delay)
{
  pinMode(pin_data, OUTPUT);
  pinMode(pin_clock, OUTPUT);
  pinMode(pin_latch, OUTPUT);
  PIN_DATA = pin_data;
  PIN_CLOCK = pin_clock;
  PIN_LATCH = pin_latch; 
  NB_BITS = nb_bits;
  TMP_DELAY = tmp_delay;
}
void Serialise::clear()
{
  digitalWrite(PIN_DATA, LOW);
  delayMicroseconds(TMP_DELAY);
  digitalWrite(PIN_CLOCK, LOW);
  delayMicroseconds(TMP_DELAY);
  digitalWrite(PIN_LATCH, LOW);
  delayMicroseconds(TMP_DELAY);
}
void Serialise::send(long datas)
{
  clear();  
  for (int i = NB_BITS-1 ; i>= 0 ; i--)
  {
    // clock LOW  
    digitalWrite(PIN_CLOCK, LOW);
    delayMicroseconds(TMP_DELAY);  
    // data 
    digitalWrite(PIN_DATA, bitRead(datas, i)) ;
    delayMicroseconds(TMP_DELAY);
    // clock HIGH 
    digitalWrite(PIN_CLOCK, HIGH);
    delayMicroseconds(TMP_DELAY);
  }
  // latch HIGH 
  digitalWrite(PIN_LATCH, HIGH);
  delayMicroseconds(TMP_DELAY);
  
}

Serialise.h

#ifndef Serialise_h
#define Serialise_h
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif

class Serialise
{
public:
    
Serialise(uint8_t pin_data, uint8_t pin_shift,  uint8_t pin_latch, uint8_t nbBits , long tmp_delay);
void init(uint8_t pin_data, uint8_t pin_shift,  uint8_t pin_latch, uint8_t nbBits , long tmp_delay);
void send(long datas);
void clear();

private:
byte PIN_DATA ;
byte PIN_CLOCK ;
byte PIN_LATCH ; 
int NB_BITS;
long TMP_DELAY;
};

#endif

“Serialise” works perfectly at this level. :slight_smile:
(certainly not the best way, but working)

For exemple I can run this in main :

#include <Serialise.h>

byte pin_data = 11 ;
byte pin_shift = 12;
byte pin_latch = 13;
int nbBits =16;
long tmp_delay = 1;

Serialise transmiter(pin_data,pin_shift,pin_latch, nbBits , tmp_delay);
void setup() 
{
}
void loop() 
{
transmiter.send(4);
}

It display four “8” without points.
If I send “2526” , display show this : 1_ 1 ("" as empty)
Other , I send “2522” , display show this : 1_.:_.1.

Right , we can continue.

I decide to create one other class, who calculate the right bit code to send.
Now, it’s going worse and worse.

DigitalTimer.cpp

#include "DigitalTimer.h"
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "String.h"
#include <C:\Arduino\libraries\Serialise\Serialise.h>

DigitalTimer::DigitalTimer(int data, int clock,  int latch ) 
{ 
  init(data, clock, latch );
}


void DigitalTimer::init(int data, int clock,  int latch )
{
  _Transmitter(data, clock,  latch,16 ,1);
}
void DigitalTimer::clear()
{
  _Transmitter.clear();
}
void  DigitalTimer::write(String string, long refresh)
{
  
  
  int len = string.length() ;            
  char str[len];                           
  string.toCharArray(str,len+1);
  int sizeOfFormat = sizeof(str)-1;
  unsigned long TimerA = millis();
  do 
  {
     for (long j = 0 ; j <= sizeOfFormat ; j++)
     {        
       _Transmitter.send( get_digit_code(str[j]) + get_standard_format_code(j)*bit(8) + point + eclairage + option1 +option2+option3);
     }
  }
  while (TimerA >= millis() -refresh);

}
long DigitalTimer::get_standard_format_code(int index)
{
  long bit_code = 0 ;
  int correct_pos[4] = {1,0,2,3};
  for(int i = 0 ; i<= 3 ; i++)
  {
    if (correct_pos[i]!= index)
    {
      bit_code = bit_code + bit(i);
    }
  }
  return bit_code;
}

int DigitalTimer::get_digit_code(char number)
{
  int sortie = 0 ;
  switch (number)
  {
  case ' ': sortie = 251; break;
  case '0': sortie = 16 ; break;
  case '1': sortie = 218; break; 
  case '2': sortie = 34 ; break; 
  case '3': sortie = 66 ; break; 
  case '4': sortie = 200; break; 
  case '5': sortie = 65 ; break;
  case '6': sortie = 1  ; break; 
  case '7': sortie = 210; break; 
  case '8': sortie = 0  ; break; 
  case '9': sortie = 64 ; break; 
  case 'A': sortie = 128; break;
  case 'C': sortie = 49 ; break;
  case 'E': sortie = 33 ; break;
  case 'F': sortie = 161; break;
  case 'G': sortie = 17 ; break;
  
  default : sortie = 251 ;
  }
  return sortie;
}

DigitalTimer.h

#ifndef DigitalTimer_h
#define DigitalTimer_h
#if ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "String.h";
#include <C:\Arduino\libraries\Serialise\Serialise.h>

#define CFG_POINT 1;
#define CFG_ECLAIRAGE 0;
#define CFG_OPTION1 0;
#define CFG_OPTION2 0;
#define CFG_OPTION3 0;

class DigitalTimer 
{
public:
    
DigitalTimer(int data, int clock,  int latch );
void init(int data, int clock,  int latch );
void clear();
void write(String string, long refresh );

private:

long get_standard_format_code(int index);
int get_digit_code(char number);
int _data_pin; 
int _clock_pin; 
int _latch_pin; 
Serialise _Transmitter;

long point = bit(2) * CFG_POINT;
long eclairage = bit(12) * CFG_ECLAIRAGE;
long option1= bit(13) * CFG_OPTION1;
long option2= bit(14) * CFG_OPTION2;
long option3= bit(15) * CFG_OPTION3;
};

#endif

Main.ino

#include <LiquidCrystal.h>
#include <DigitalTimer.h>

int latchPin = 13; 
int clockPin = 12; 
int dataPin = 11;

DigitalTimer dc(dataPin,clockPin,latchPin);

void setup() 
{
  Serial.begin(9600); 
}

void loop() 
{
dc.clear();
dc.write("1333", 2000);
dc.write("A EF", 2000);
}

As you see, I want use a “Serialise” “object” into the “DigitalTimer” class.
Of course, it returns lot of errors who I dont deciphers.

Errors on windows Arduino IDE 1.6.4

C:\Arduino\libraries\DigitalTimer\DigitalTimer.cpp: In constructor 'DigitalTimer::DigitalTimer(int, int, int)':
C:\Arduino\libraries\DigitalTimer\DigitalTimer.cpp:10:60: error: no matching function for call to 'Serialise::Serialise()'
 DigitalTimer::DigitalTimer(int data, int clock,  int latch ) 
                                                            ^
C:\Arduino\libraries\DigitalTimer\DigitalTimer.cpp:10:60: note: candidates are:
In file included from C:\Arduino\libraries\DigitalTimer\DigitalTimer.h:9:0,
                 from C:\Arduino\libraries\DigitalTimer\DigitalTimer.cpp:1:
C:\Arduino\libraries\Serialise\Serialise.h:13:1: note: Serialise::Serialise(uint8_t, uint8_t, uint8_t, uint8_t, long int)
 Serialise(uint8_t pin_data, uint8_t pin_shift,  uint8_t pin_latch, uint8_t nbBits , long tmp_delay);
 ^
C:\Arduino\libraries\Serialise\Serialise.h:13:1: note:   candidate expects 5 arguments, 0 provided
C:\Arduino\libraries\Serialise\Serialise.h:9:7: note: Serialise::Serialise(const Serialise&)
 class Serialise
       ^
C:\Arduino\libraries\Serialise\Serialise.h:9:7: note:   candidate expects 1 argument, 0 provided
C:\Arduino\libraries\DigitalTimer\DigitalTimer.cpp: In member function 'void DigitalTimer::init(int, int, int)':
C:\Arduino\libraries\DigitalTimer\DigitalTimer.cpp:18:41: error: no match for call to '(Serialise) (int&, int&, int&, int, int)'
   _Transmitter(data, clock,  latch,16 ,1);

Someone have à solution to use class into a class ? Or just help to use a better way to do that ? :fearful:

Thanks for help, :smiley:

Get rid of that obsolete Wprogram.h crap

#include <C:\Arduino\libraries\Serialise\Serialise.h>

This is almost certainly the wrong way to reference a header file. You might need to review your directory scheme.

Your DigitalTimer class includes a private member, _Transmitter, of the serialise class.

Your constructor for DigitalTimer contains no code to also construct a Serialise object. When your main code declares and constructs your DigitalTimer object, there is no explicit call to create the _Transmitter member, therefore there will be a default implicit call to try and create one, using a default constructor method for the Serialise class, with no arguments. i.e. Serialise::Serialise( ). However, your Serialise class doesn’t have a default constructor method which takes no arguments. So, the process fails.

Solutions: (1) In the DigitalTimer construct, add a specific call to Serialise::Serialise( int int int int int ) constructor.

(2) Create a default constructor for the Serialise class.

Thanks michinyon !

Good explains :slight_smile:

  1. I have delete Wprogram.h “crap” . :smiley:

  2. I can’t change “#include <C:\Arduino\libraries\Serialise\Serialise.h>” to “Serialise.h”, it make error: " fatal error: Serialise.h: No such file or directory".

  3. I change _Transmitter in public member

At this step, I’m not sure to do the right things

  1. I prefer yout first solution , I do that :
DigitalTimer::DigitalTimer(int data, int clock,  int latch ) 
{ 
  Serialise::Serialise( data, clock, latch, 16 , 1 ) ;
  init(data, clock, latch );
  
}

and try this 

DigitalTimer::DigitalTimer(int data, int clock,  int latch ) 
{ 
  _Transmitter = Serialise::Serialise( data, clock, latch, 16 , 1 ) ;
  init(data, clock, latch );
  
}

But have some errors , it try again to using a default constructor method ‘Serialise::Serialise()’

Errors on windows Arduino IDE 1.6.4

Les options de compilation ont été modifiées, tout sera recompilé
C:\Arduino\libraries\DigitalTimer\DigitalTimer.cpp: In constructor 'DigitalTimer::DigitalTimer(int, int, int)':
C:\Arduino\libraries\DigitalTimer\DigitalTimer.cpp:6:60: error: no matching function for call to 'Serialise::Serialise()'
 DigitalTimer::DigitalTimer(int data, int clock,  int latch ) 
                                                            ^
C:\Arduino\libraries\DigitalTimer\DigitalTimer.cpp:6:60: note: candidates are:
In file included from C:\Arduino\libraries\DigitalTimer\DigitalTimer.h:5:0,
                 from C:\Arduino\libraries\DigitalTimer\DigitalTimer.cpp:1:
C:\Arduino\libraries\Serialise\Serialise.h:13:1: note: Serialise::Serialise(uint8_t, uint8_t, uint8_t, uint8_t, long int)
 Serialise(uint8_t pin_data, uint8_t pin_shift,  uint8_t pin_latch, uint8_t nbBits , long tmp_delay);
 ^
C:\Arduino\libraries\Serialise\Serialise.h:13:1: note:   candidate expects 5 arguments, 0 provided
C:\Arduino\libraries\Serialise\Serialise.h:9:7: note: Serialise::Serialise(const Serialise&)
 class Serialise
       ^
C:\Arduino\libraries\Serialise\Serialise.h:9:7: note:   candidate expects 1 argument, 0 provided
C:\Arduino\libraries\DigitalTimer\DigitalTimer.cpp:8:67: error: cannot call constructor 'Serialise::Serialise' directly [-fpermissive]
   _Transmitter = Serialise::Serialise( data, clock, latch, 16 , 1 ) ;
                                                                   ^
C:\Arduino\libraries\DigitalTimer\DigitalTimer.cpp:8:67: error:   for a function-style cast, remove the redundant '::Serialise' [-fpermissive]
C:\Arduino\libraries\DigitalTimer\DigitalTimer.cpp: In member function 'void DigitalTimer::init(int, int, int)':
C:\Arduino\libraries\DigitalTimer\DigitalTimer.cpp:16:41: error: no match for call to '(Serialise) (int&, int&, int&, int, int)'
   _Transmitter(data, clock,  latch,16 ,1);
                                         ^
Erreur lors de la compilation.

Thanks for helps :wink:

I tested the second solution , and I'm not in capacity to solve the errors ...

part of DigitalTimer.cpp

DigitalTimer::DigitalTimer(int data, int clock,  int latch ) 
{ 
  init(data, clock, latch );
}
void DigitalTimer::init(int data, int clock,  int latch )
{
   pinMode(data, OUTPUT);
  pinMode(clock, OUTPUT);
  pinMode(latch, OUTPUT);
  _data_pin = data;
  _clock_pin = clock;
  _latch_pin = latch;   
    
  _Transmitter.init(data, clock,  latch,16 ,1);
}

part of Serialise.cpp

Serialise::Serialise()
{
   
}
Serialise::Serialise( uint8_t pin_data, uint8_t pin_clock,  uint8_t pin_latch ,uint8_t nb_bits ,long tmp_delay)
{
    init(pin_data,pin_clock,pin_latch,nb_bits,tmp_delay);
}

Errors on windows Arduino IDE 1.6.4

DigitalTimer\DigitalTimer.cpp.o: In function `DigitalTimer::init(int, int, int)':
C:\Arduino\libraries\DigitalTimer/DigitalTimer.cpp:23: undefined reference to `Serialise::init(unsigned char, unsigned char, unsigned char, unsigned char, long)'
DigitalTimer\DigitalTimer.cpp.o: In function `DigitalTimer::DigitalTimer(int, int, int)':
C:\Arduino\libraries\DigitalTimer/DigitalTimer.cpp:6: undefined reference to `Serialise::Serialise()'
DigitalTimer\DigitalTimer.cpp.o: In function `DigitalTimer::clear()':
C:\Arduino\libraries\DigitalTimer/DigitalTimer.cpp:9: undefined reference to `Serialise::clear()'
DigitalTimer\DigitalTimer.cpp.o: In function `DigitalTimer::write(String, long)':
C:\Arduino\libraries\DigitalTimer/DigitalTimer.cpp:42: undefined reference to `Serialise::send(long)'
collect2.exe: error: ld returned 1 exit status
Erreur lors de la compilation.

Sorry , I'm not the best with C ... :-*

Someone have fonctionnal and short exemple ? Thanks :)

I have make a test with a sample code found on internet. And it could be that I have a problem with my IDE .

Sample code :

main

#include <First.h>

First thing(1);

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  Serial.print("Object's Number: ");
  Serial.print(thing.getNumber());
  Serial.println();
  
  Serial.print("Object's total Numbers: ");
  Serial.print(thing.getSumOfNumbers());
  Serial.println(); 
  Serial.println(); 
  delay(1000);
}

First.cpp

#include "First.h"
#include <Arduino.h>

First::First(int newNumber) : widget(2)
{
  itsNumber = newNumber;
}

int First::getNumber()
{
  return itsNumber;
}

int First::getNumberOfSecond()
{
  return (widget.getNumber());
}

int First::getSumOfNumbers()
{
  return (itsNumber + getNumberOfSecond());
}

First.h

#ifndef First_h
#define First_h

#include <Second.h>

class First
{
  public:
    First(int newNumber);
    int getNumber();
    int getNumberOfSecond();
    int getSumOfNumbers();
  private:
    int itsNumber;
    Second widget;
};
#endif

Second.cpp

#include "Second.h"
Second::Second(int newNumber)
{
  itsNumber = newNumber;
}

int Second::getNumber()
{
  return itsNumber;
}

Second.h

#ifndef Second_h
#define Second_h

class Second
{
  public:
    Second(int newNumber);
    int getNumber();
  private:
    int itsNumber;
};
#endif

Then error :

In file included from First.cpp:1:0:
First.h:4:20: fatal error: Second.h: No such file or directory
 #include <Second.h>
                    ^
compilation terminated.
Erreur lors de la compilation.

If I change the includes “Second.h” to “C:\Arduino\libraries\Second\Second.h”

First\First.cpp.o: In function `First::First(int)':
C:\Arduino\libraries\First/First.cpp:4: undefined reference to `Second::Second(int)'
First\First.cpp.o: In function `First::getNumberOfSecond()':
C:\Arduino\libraries\First/First.cpp:16: undefined reference to `Second::getNumber()'
collect2.exe: error: ld returned 1 exit status
Erreur lors de la compilation.

We can see same errors as my code …

Are they in all in one folder?
I usually do
#include “…/second/second.h”

The<> is saved for system libraries generally. “” for custom libraries.

mistergreen:
Are they in all in one folder?
I usually do
#include “…/second/second.h”

The<> is saved for system libraries generally. “” for custom libraries.

Get rid of that obsolete Wprogram.h crap

Please revise you posts to reflect facts and not fiction.

Vaclav, when quoting other posts it's polite to include the attribution correctly. You have quotes from two people attributed to just one.

Please edit your post to correct this.

mistergreen:
Are they in all in one folder?
I usually do
#include “…/second/second.h”

The<> is saved for system libraries generally. “” for custom libraries.

Thanks for help mistergreen :wink:

They are not in the same folder . I would to use my custom library.

Have created 2 Folders in my library folder, who are named “First” and “Second” , they contain :

“libraries\First\First.h”
“libraries\First\First.cpp”
“libraries\Second\Second.h”
“libraries\Second\Second.cpp”

First::First(int newNumber) : widget(2)

Also, is this normal usage for inheritance?

I usually inherit the class by calling the constructor not the object First.h

Class First : public Second

First.cpp

First::First(int newNumber) : Second()

OK I found !!!

Error : C:\Arduino\libraries\First/First.cpp:4: undefined reference to `Second::Second(int)'

When i use two folders for two libraries , like this :

..\Second\Second.h ..\Second\Second.cpp ..\First\First.h ..\First\First.cpp

with #include "..\Second\Second.h" into first.h

Solution to resolve this problem, I put "Second" files into the "First" Folder , like this :

..\First\First.h ..\First\First.cpp ..\First\Second.h ..\First\Second.cpp

So, it"s seems impossible to use two differents(separate) libraries when we use a classe within classe.

Thanks for help MisterGreen ! Your other method dont work with two differents libraries , but I have not tested either with files in the same folder.

When you include a library in your sketch, any library used inside this lib must also be included in the sketch.

So your sketch must include both first.h and second.h

It should fix this error:

In file included from First.cpp:1:0:
First.h:4:20: fatal error: Second.h: No such file or directory
#include <Second.h>
^
compilation terminated.
Erreur lors de la compilation.

This is a problem that is getting fixed, but has been the staple way of doing things for years.

Thanks pYro_65 ! It works perfectly !

No worries, here is a bit more on the topic if you're interested: What does the IDE change in my sketch?

And from the github wiki: https://github.com/arduino/Arduino/wiki/Build-Process

I prefer to tackle one " problem " at a time , so here is a small addendum.

Let’s agree to call these files “headers”, which in not exactly correct because they can be just blocks of any code.

It is very common that header files are nested and as long as they are still seen by the compiler in correct order, they are still just chunks of code conveniently separated.

Things get interesting when such nesting results in DUPLICATES, and compiler will let you know about it pretty fast.

Than the “cool” feature of the language - called preprocessor directives comes to the rescue.

In an essence - when the header file is FIRST included preprocessor lets you set a flag ( #define )
so when it is by accident or as a part of unrelated usage included again the preprocessor skips the #include and optionally the actual body of the attached code using #if / #endif . Cool.

So put something like this as first lines of the header file:

#ifndef HEADER_H           // check the flag - if defined skip what is inside #if / #endif block 

#define HEADER_H          // first pass - define the flag 
#include <header.h>        // do the include  
#pragma message( "Including header.h version x ")  // optional - message is output by compiler so you know  
it got included for sure,   by itself not much but when you have several versions of the header.h it helps 

[b]optionally the body of the code goes here [/b]


#endif                          // end of preprocessor directive code block

And if you forget the closing #endif the compiler will tell you about it!