1

I am writing a class for a project which will take care of handling any LCD updates for my project. The way I want to handle this is to initialize the LCD object in my main file, and then pass the LCD object on to my own class when initializing it. The LCD object should be declared a private object in my class so several member functions can access it.

The problem is I can't find how to initialize the object correctly in the .h file. Below is what I currently have, but when I try to build it, I get:

LCDController.h:_Clcd1' should be initialized
LCDController.h:_Clcd2' should be initialized

main .ino file:

void setup()
{
  //LiquidCrystal lcd(RS,RW,Enable1,Enable2, data3,data2,data1,data0);
  LiquidCrystal lcd(12, 11, 7, 6, 5, 4);  //declare two LCD's
  LiquidCrystal lcd2(12, 10, 7, 6, 5, 4); // Ths is the second

  LCDController.init(lcd, lcd2);
}

LCDController.h file:

// LCDController.h

#ifndef _LCDCONTROLLER_h
#define _LCDCONTROLLER_h

#if defined(ARDUINO) && ARDUINO >= 100
    #include "Arduino.h"
#else
    #include "WProgram.h"
#endif
#include <LiquidCrystal.h>
class LCDControllerClass
{
 protected:


 public:
    void init(LiquidCrystal& Clcd1, LiquidCrystal& Clcd2);
private:
   void _UpdateLCD(int iLine, int iPosition, String cText);
   LiquidCrystal& _Clcd1;
   LiquidCrystal& _Clcd2;
};

extern LCDControllerClass LCDController;

#endif

LCDController.cpp file:

#include "LCDController.h"
#include <LiquidCrystal.h>

void LCDControllerClass::init(LiquidCrystal& Clcd1, LiquidCrystal& Clcd2)
{
   _Clcd1 = Clcd1;
   _Clcd1.begin(40, 2);
   _Clcd1.clear();

   _Clcd2 = Clcd2;
   _Clcd2.begin(40, 2);
   _Clcd2.clear();

}
1
  • What happens if you move the lcd and lcd2 definitions outside the setup function?
    – rslite
    Commented Mar 14, 2015 at 1:56

1 Answer 1

4

In C++, a class that holds reference members (in your sample, LiquidCrystal& _Clcd1; and LiquidCrystal& _Clcd2;) must ensure these references are initialized at construction time, not later.

This means your void init(LiquidCrystal& Clcd1, LiquidCrystal& Clcd2); method is not the right way to initialize _Clcd1 and _Clcd2 because it will be called after construction time.

You have 2 ways to solve this issue,t hat I will detail further below.

HOWEVER, before we discuss the solutions, you must be aware that your sample code has a huge defect in setup() method code!

void setup()
{
    //LiquidCrystal lcd(RS,RW,Enable1,Enable2, data3,data2,data1,data0);
    LiquidCrystal lcd(12, 11, 7, 6, 5, 4);  //declare two LCD's
    LiquidCrystal lcd2(12, 10, 7, 6, 5, 4); // Ths is the second

    LCDController.init(lcd, lcd2);
}

Here, you create lcd and lcd2 in your setup method, but their life ends at the end of setup(), because they have been allocated on the stack. Using these outside setup() will most likely cause your program to crash as soon as your loop() tries to access lcd or lcd2, indirectly through LCDController method calls.

To remove this defect, you must declare these variables outside setup:

//LiquidCrystal lcd(RS,RW,Enable1,Enable2, data3,data2,data1,data0);
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);  //declare two LCD's
LiquidCrystal lcd2(12, 10, 7, 6, 5, 4); // Ths is the second

void setup()
{
    LCDController.init(lcd, lcd2);
}

Now you can use them anywhere in your program, you are sure they are present and "alive".

Now we can go to the solutions of the original compilation problem.

1. Initialize references at construction by adding a constructor

class LCDControllerClass
{
    public:
    LCDControllerClass(LiquidCrystal& Clcd1, LiquidCrystal& Clcd2)
    : _Clcd1(Clcd1), _Clcd2(Clcd2) {}
    ...
};

You can still keep an void init() method to complete the initialization if you don't want it to occur right at construction time, or you can fully integrate the current init() content into the constructor and re,voe init() altogether:

class LCDControllerClass
{
    public:
    LCDControllerClass(LiquidCrystal& Clcd1, LiquidCrystal& Clcd2)
    : _Clcd1(Clcd1), _Clcd2(Clcd2)
    {
        _Clcd1.begin(40, 2);
        _Clcd1.clear();

        _Clcd2.begin(40, 2);
        _Clcd2.clear();
    }
    ...
};

In anycase, you will have to change the way you instantiate your LCDControllerClass LCDController which you did not show in your sample code, that would be something like this:

LiquidCrystal lcd(...);
LiquidCrystal lcd2(...);
LCDControllerClass LCDController(lcd, lcd2);

That obviously requires that you can instantitate lcd and lcd2 before creating LCDController. If that is not possible for you, then you'll have to use the second way.

2. Replace references with pointers

As mentioned before, in a class reference members MUST be initialized at construction time (moreover, they cannot be changed afterwards, to point somewhere else). This is not the case for pointers however:

class LCDControllerClass
{
    public:
    void init(LiquidCrystal* Clcd1, LiquidCrystal* Clcd2);

    private:
    void _UpdateLCD(int iLine, int iPosition, String cText);
    LiquidCrystal* _Clcd1;
    LiquidCrystal* _Clcd2;
};

void LCDControllerClass::init(LiquidCrystal* Clcd1, LiquidCrystal* Clcd2)
{
   _Clcd1 = Clcd1;
   _Clcd1->begin(40, 2);
   _Clcd1->clear();

   _Clcd2 = Clcd2;
   _Clcd2->begin(40, 2);
   _Clcd2->clear();
}

Note that now, you need to use the arrow notation -> to access _Clcd1 and _Clcd2 members (dot notation cannot work for pointers).

The rest of the code should be slightly modified to reflect this change:

//LiquidCrystal lcd(RS,RW,Enable1,Enable2, data3,data2,data1,data0);
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);  //declare two LCD's
LiquidCrystal lcd2(12, 10, 7, 6, 5, 4); // Ths is the second

void setup()
{
    LCDController.init(&lcd, &lcd2);
}

Note that we now have to pass the address of lcd and lcd2 to init(), by using & before their names.

4
  • Thanks for this great answer! Besides fixing my actual problem, you took the time to explain what was going wrong and I also understand the how and why. Thanks for making StackExchange great!
    – Alex
    Commented Mar 14, 2015 at 9:54
  • Could you also explain how I can later on in another member function of my LCDControllerClass create what I think should be another pointer to either _Clcd1 or _Clcd2? I have another member function should is in charge of putting text on the LCD, and depending on the line number that is passed to it (can be 1 to 4), it either has to update _Clcd1 or _Clcd2. I tried to accomplish this by defining LiquidCrystal* CActiveLCD = &_Clcd1 but this does compile but seems to crash my arduino...
    – Alex
    Commented Mar 14, 2015 at 10:43
  • @Alex I would suggest you post a new question (it is better than mixing several problems in one question) with the updated code, the explanation of what you want to achieve, and the problem you currently have. Cheers!
    – jfpoilpret
    Commented Mar 14, 2015 at 13:12
  • I was actually thinking if I should post a new question or not :) I just posted arduino.stackexchange.com/questions/9319/…, would be great if you could chime in. Thanks again!
    – Alex
    Commented Mar 15, 2015 at 0:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.