using a library in a class

Greeting teachers,

I'm attempting to create a class that updates a 16x2 LCD across an i2c connection displaying
elapse time since Arduino starttup in hours and minutes (hh:mm).

I need to include the "Adafruit_LiquidCrystal" library in this class. I've done many hours
of research and have gotten the sketch down to three errors and haven't been able to make
any more progress.

I'm on the steep side of the C++ curve without a doubt. Your patience is greatly appreciated.

Setup and wire connection list:

Pro Mini to i2c/SPI character LCD backpack
(Adafruit ID:292)

Processor:

ATmega328P, Arduino Pro Mini, 5V, 16MHz

Pro Mini LCD backpack
pin pin Signal description


A4 SDA i2c Serial Data
A5 SCK i2c Serial Clock

Here's the sketch


#include<Adafruit_LiquidCrystal.h>
/* Connect via i2c, default address #0 (A0-A2 not jumpered) */
Adafruit_LiquidCrystal lcd(0);


class Display_update
{
  // Class member variables that are initiated at startup.  

  int m;  // minutes
  int h;  // hours
  unsigned long currentMillis;
  unsigned long previousMillis;

  // Constructor - creates a Display_update instance, machine state can be passed
  // to the subroutine in the constructor.
  public:
  Display_update(int mm, int hh, unsigned long current, unsigned long previous ) 
  {
    m = mm;
    h = hh;
    currentMillis = current;
    previousMillis = previous;
  };
  
  void Update()
  {
    Serial.println("inside of the Update() method"); /// debug code ////
      
    // Update HH:MM LCD display field
    currentMillis = (millis()/500);  ///////// clock speed is set here ////
    
    
    delay(750);   /////// delay for serial monitor debug purposes /////////////
    Serial.println("Step 1"); //////////////// debug code ////
    Serial.print(currentMillis, DEC); //////// debug code ////
    Serial.print("     ");//////////////////// debug code ////
    Serial.println(previousMillis, DEC);////// debug code ////
 
    if((currentMillis - previousMillis) >= 1) {

      Serial.println("Step 2"); ////////////// debug code ////
      
      m=m+1;
      Serial.println(m);
      previousMillis = currentMillis;

      Serial.println("Step 3"); ////////////// debug code ////
      
      lcd.clear();

      Serial.println("Step 4"); ////////////// debug code ////

      if(h==0) {
        Serial.println("Step 5"); //////////// debug code ////
        lcd.setCursor(13,0);
        goto Bailout;
      }

      if((h>0) && (h < 10)) {
        Serial.println("Step 6"); //////////// debug code ////
        lcd.setCursor(12,0);
        lcd.print(h, DEC);
        goto Bailout;
      }

      if(h > 9) {
        lcd.setCursor(11,0);
        lcd.print(h, DEC);
        goto Bailout;
      }

    Bailout:
    lcd.print(":");

    if(m < 10) {
      lcd.setCursor(14,0);
      lcd.print("0");
    }else{
      lcd.setCursor(14,0);
    }

    lcd.print(m, DEC);
    
    Serial.print(h, DEC);
    Serial.print("0");
    Serial.print(m, DEC);

    if(m == 59) {
      h=h+1;
      m = 0;
    }
   }  ///////////// end of if(currentMillis... ////    
  } /////////////// end of Update /////////////////  
};  /////////////// end of class //////////////////


Display_update LCD(0, 0, 0, 0);


void setup() 
{
  Serial.begin(9600);
} ////////////////// end of Setup ///////////////////
void loop()
{
  LCD.Update();
  delay(1010);
} ////////////////// end of Loop ////////////////////


void Display_update::lcd.clear()
{
  lcd.clear()=Adafruit_LiquidCrystal::lcd.clear();
}  

void Display_update::lcd.setCursor()
{
  lcd.setCursor()=Adafruit_LiquidCrystal::lcd.setCursor();
}

void Display_update::lcd.print()
{ 
  lcd.print()=Adafruit_LiquidCrystal::lcd.print();
}

In the hours that I have poured into this project I haven't been able to execute any of the methods in the
Adafruit_LiquidCrystal library (lcd.clear, lcd.setCursor and lcd.print).

Here is the error report.


 TimerDisplayDev_initial_e:138: error: expected initializer before '.' token
 void Display_update::lcd.clear()
                         ^
TimerDisplayDev_initial_e:143: error: expected initializer before '.' token
 void Display_update::lcd.setCursor()
                         ^
TimerDisplayDev_initial_e:148: error: expected initializer before '.' token
 void Display_update::lcd.print()
                         ^
exit status 1
expected initializer before '.' token

I don't have the words to tell how much I appreciate your help.
Many Thanks
Richard

It's not entirely clear what you wanted those three functions (that were not declared in your class) to do. They are not used anywhere. My guess was that you wanted LCD.clear() to call lcd.clear() and similar for the other two. The 'setCursor() needs to pass arguments and lcd.print() doesn't exist so I don't know what LCD.print() is supposed to call.

Anyway, here is how you would add those methods to your class:

#include<Adafruit_LiquidCrystal.h>
/* Connect via i2c, default address #0 (A0-A2 not jumpered) */
Adafruit_LiquidCrystal lcd(0);


class Display_update
{
    // Class member variables that are initiated at startup.

    int m;  // minutes
    int h;  // hours
    unsigned long currentMillis;
    unsigned long previousMillis;

    // Constructor - creates a Display_update instance, machine state can be passed
    // to the subroutine in the constructor.
  public:
    Display_update(int mm, int hh, unsigned long current, unsigned long previous )
    {
      m = mm;
      h = hh;
      currentMillis = current;
      previousMillis = previous;
    };

    void clear()
    {
      lcd.clear();
    }

    void setCursor(int column, int row)
    {
      lcd.setCursor(column, row);
    }

    void print()
    {
      // lcd.print();  // No such function in Adafruit_LiquidCrystal::
    }


    void Update();
};  /////////////// end of class //////////////////


void Display_update::Update()
{
  Serial.println("inside of the Update() method"); /// debug code ////

  // Update HH:MM LCD display field
  currentMillis = (millis() / 500); ///////// clock speed is set here ////


  delay(750);   /////// delay for serial monitor debug purposes /////////////
  Serial.println("Step 1"); //////////////// debug code ////
  Serial.print(currentMillis, DEC); //////// debug code ////
  Serial.print("     ");//////////////////// debug code ////
  Serial.println(previousMillis, DEC);////// debug code ////

  if ((currentMillis - previousMillis) >= 1)
  {

    Serial.println("Step 2"); ////////////// debug code ////

    m = m + 1;
    Serial.println(m);
    previousMillis = currentMillis;

    Serial.println("Step 3"); ////////////// debug code ////

    lcd.clear();

    Serial.println("Step 4"); ////////////// debug code ////

    if (h == 0)
    {
      Serial.println("Step 5"); //////////// debug code ////
      lcd.setCursor(13, 0);
      goto Bailout;
    }

    if ((h > 0) && (h < 10))
    {
      Serial.println("Step 6"); //////////// debug code ////
      lcd.setCursor(12, 0);
      lcd.print(h, DEC);
      goto Bailout;
    }

    if (h > 9)
    {
      lcd.setCursor(11, 0);
      lcd.print(h, DEC);
      goto Bailout;
    }

Bailout:
    lcd.print(":");

    if (m < 10)
    {
      lcd.setCursor(14, 0);
      lcd.print("0");
    }
    else
    {
      lcd.setCursor(14, 0);
    }

    lcd.print(m, DEC);

    Serial.print(h, DEC);
    Serial.print("0");
    Serial.print(m, DEC);

    if (m == 59)
    {
      h = h + 1;
      m = 0;
    }
  }  ///////////// end of if(currentMillis... ////
} /////////////// end of Update /////////////////


Display_update LCD(0, 0, 0, 0);


void setup()
{
  Serial.begin(9600);
} ////////////////// end of Setup ///////////////////

void loop()
{
  LCD.Update();
  delay(1010);
} ////////////////// end of Loop ////////////////////

If you delete everything after "end of loop" the code will compile. It looks like you are trying to define methods for the Display_update class that will call methods in the Adafruit class. This is unnecessary since the methods are called directly in the Update method of Display_update.

I think the proper way to do what you wanted to do is like this:

    Display_update(int mm, int hh, unsigned long current, unsigned long previous )
    {
      m = mm;
      h = hh;
      currentMillis = current;
      previousMillis = previous;
      lcd.begin(16, 2);
    }

    void Display_update::clear()
    {
      lcd.clear();
    }
    void Display_update::setCursor(uint8_t col, uint8_t row)
    {
      lcd.setCursor(col, row);
    }

    void Display_update::print(char *str)
    {
      lcd.print(str);
    }

If you did that you could change the calls to Adafruit methods within your class:

lcd.clear();       // calls Adafruit directly
clear();           // calls Adafruit through Display_update method
this->clear();  // same as above

Notice that I added a call to the Adafruit begin() method in your constructor.

Notice that I added a call to the Adafruit begin() method in your constructor.

Which was a bad idea, as the hardware is not ready when the constructor is called.

If a class is instantiating a hardware-dependent class, that has a begin() method, the class doing the instantiating needs a begin() method, too.

Display_update(), which presumably updates a display, is NOT the place to call begin() for the display.

So, it looks to me like you’re trying to provide an update() method for the lcd. If that’s the case, then you should perhaps consider using inheritance. See below for an outline of the technique. I didn’t try to reproduce the functionality of your original update() method -- mostly because it was so convoluted and ugly. But, I did put in an example that you can change. But, don’t use the goto function again, it’s an abomination. This isn’t the early 1970s and you’re not programming in BASIC.

#include<Adafruit_LiquidCrystal.h>

class Display_update : public Adafruit_LiquidCrystal {
  private:
    uint16_t m;
    uint16_t h;
    uint32_t previousMillis;

  public:
    Display_update(uint16_t mm, uint16_t hh, uint32_t previous ) :
      Adafruit_LiquidCrystal(0), m(mm), h(hh), previousMillis(previous) {}

    void update();
};

void Display_update::update() {
  uint32_t currentMillis;

  currentMillis = millis();
  if (currentMillis - previousMillis >= 60000) {
    m++;
    if (m >= 60) {
      m = 0;
      h++;
      if (h >= 24) {
        h = 0;
      }
    }
    setCursor(10, 0);
    if (h < 10) {
      print("0");
    }
    print(h);
    print(":");
    if (m < 10) {
      print("0");
    }
    print(m);
    previousMillis = currentMillis;
  }
}

Display_update LCD(0, 0, 0);

void setup() {
  Serial.begin(115200);
  delay(2000);
  LCD.begin(16, 2);
  LCD.clear();
  LCD.setCursor(10, 0);
  LCD.print("00:00");
}

void loop() {
  LCD.update();
}

johnwasser
Blue Eyes
PaulS
gfvalvo

ThankYouThankYouThankYou,
I must print all of this code and study it. I'm sure it will substantially increase my understanding of the C++ class code structure.

Your time and effort on my behave is greatly appreciated.
I will report the coding technique that I used once it is working to my satisfaction.

Many thanks again.
Richard