variable scope in classes

Okay long story short

I'm cleaning up my code, and am trying to break out some of my larger chunks of code into .h files for organization and housekeeping.

This works more or less

My main sketch is passing this onto the header file (at bottom of post)

lcdupdate(printtest, 2, 3, 4, 5, 6, 7);

the function is supposed to compare the inputs with the old input (ex status1 to status1old) and update the lcd if they are different to avoid the LCD from flickering constantly.

Now here's the problem
If I declare my ints under private (or public) the void lcdupdate() wont work saying they aren't in scope.

If I declare them under lcdupdate(), the LCD flickers constantly, since it is declaring the variables every time it called (or so it appears).

so long story short, I'm missing some nuance of scope within .h files or classes that isn't part of the tutorials ive found (first time using both of these) Below is the relevant parts of the .h file (I think)

/*
LCD.h - Update QA machine LCD Display
*/

// ensure this library description is only included once
#ifndef LCD_h
#define LCD_h
// include types & constants of Wiring core API
#include <LiquidCrystal.h>
#include <Arduino.h>
// user-accessible "public" interface

class LCDUPDATE{
public:
void lcdupdate();
void lcdclear();
void lcdbooting();
private:
int status1old;
int status2old;
int status3old;
int status4old;
int hstatusold;
int mstatusold;
int bstatusold;
int test;

};
#endif

//==== UPDATE LCD FUNCTION
void lcdupdate(int status1, int status2, int status3, int status4, int hstatus, int mstatus, int bstatus)
{
// update
if (hstatus != hstatusold) {
if (hstatus == 1) {
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 0);
lcd.print(" Boot Complete ");
}

Yeah, sorry that just gives "LCD.h:58: error: prototype for 'void LCDUPDATE::lcdupdate(int, int, int, int, int, int, int)' does not match any in class 'LCDUPDATE'"

The tutorial I was following was: https://www.arduino.cc/en/Hacking/LibraryTutorial which also has the :: but I guess I'm not understanding what is going on here.

I'm assuming that by not using :: I actually had the lcdupdate function off on its own and not in the LCDUPDATE class, right?

ah, so up in the:

class LCDUPDATE{
public:
void lcdupdate();
void lcdclear();
void lcdbooting();

It needs to match where it is being used, so it would read:

class LCDUPDATE{
public:
void lcdupdate();
void lcdclear();
void lcdupdate(int status1, int status2, int status3, int status4, int hstatus, int mstatus, int bstatus)

?

Alright I've hit my head against this again for an hour or so, and still can't figure out whats going on

There error I'm now getting is "cannot call member function 'void LCDUPDATE::lcdupdate(int, int, int, int, int, int, int)' without object" in the main sketch

Everything else Ive tried gives me "has not been declared" or out of scope, what am I missing here now that I've corrected the void to LCDUPDATE::lcdupdate

printtest = 1;
LCDUPDATE::lcdupdate(printtest, 2, 3, 4, 5, 6, 7);
/*
  LCD.h - Update QA machine LCD Display
*/

// ensure this library description is only included once
#ifndef LCD_h
#define LCD_h
// include types & constants of Wiring core API
#include <LiquidCrystal.h>
#include <Arduino.h>
  // user-accessible "public" interface

class LCDUPDATE{ 
  public:
    void LCDUPDATE::lcdupdate(int status1, int status2, int status3, int status4, int hstatus, int mstatus, int bstatus);
    void lcdclear();
    void lcdbooting();
  private:
    int status1old;
    int status2old;
    int status3old;
    int status4old;
    int hstatusold;
    int mstatusold;
    int bstatusold;
    int test;

};
  #endif

  //==== UPDATE LCD FUNCTION
  void LCDUPDATE::lcdupdate(int status1, int status2, int status3, int status4, int hstatus, int mstatus, int bstatus)
  {
// update
 if (hstatus != hstatusold) {
    if (hstatus == 1) {
      lcd.setCursor(0, 0);
      lcd.print("                    ");
      lcd.setCursor(0, 0);
      lcd.print("   Boot Complete    ");
    }
}

is this supposed to be your constructor?

void LCDUPDATE::lcdupdate(int status1, int status2, int status3, int status4, int hstatus, int mstatus, int bstatus);

if so it ought to look more like this in your header:

LCDUPDATE(int status1, int status2, int status3, int status4, int hstatus, int mstatus, int bstatus);

and this in its implementation:

LCDUPDATE::LCDUPDATE(int status1, int status2, int status3, int status4, int hstatus, int mstatus, int bstatus)
{
  // and so on
{

That appears to just hand off the inputs to the class, not the function, which I kind of expected since you changed them to be named the same thing.

In file included from H:\Project files\QA machine\Arduino\Main Arduino\V9_Arrays\V9_Arrays.ino:5:0:

sketch\LCD.h:13:7: note: LCDUPDATE::LCDUPDATE()

class LCDUPDATE{

^

sketch\LCD.h:13:7: note: candidate expects 0 arguments, 7 provided

sketch\LCD.h:13:7: note: constexpr LCDUPDATE::LCDUPDATE(const LCDUPDATE&)

sketch\LCD.h:13:7: note: candidate expects 1 argument, 7 provided

sketch\LCD.h:13:7: note: constexpr LCDUPDATE::LCDUPDATE(LCDUPDATE&&)

sketch\LCD.h:13:7: note: candidate expects 1 argument, 7 provided

exit status 1
no matching function for call to 'LCDUPDATE::LCDUPDATE(int&, int, int, int, int, int, int)'

EDIT>it looks like you may be using the same name for a function as you are for your constuuctor, but <EDIT you haven't posted enough code for me to really see what's wrong, but I believe you want to do something like this:

#include <LiquidCrystal.h>
#include <Arduino.h>

class LCDUPDATE {
  public:
    LCDUPDATE(int status1, int status2, int status3, int status4, int hstatus, int mstatus, int bstatus);
    void lcdclear();
    void lcdbooting();
  private:
    int status1old;
    int status2old;
    int status3old;
    int status4old;
    int hstatusold;
    int mstatusold;
    int bstatusold;
    int test;

};

LCDUPDATE::LCDUPDATE(int status1, int status2, int status3, int status4, int hstatus, int mstatus, int bstatus)
{
  if (hstatus != hstatusold)
  {
    if (hstatus == 1)
    {
      //      lcd.setCursor(0, 0);
      //      lcd.print("                    ");
      //      lcd.setCursor(0, 0);
      //      lcd.print("   Boot Complete    ");
    }
  }
}

LCDUPDATE myObject(0,0,0,0,0,0,0);

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

}

PS if your class is using the LCD library, you ought to look at inheritance...

Okay, well here is the full code I have done at this point, much of it should be irrelevent

Main sketch:

//include required libraries
#include <SoftwareSerial.h>
#include <LiquidCrystal.h>
#include <Stepper.h>
#include "LCD.h"
;





//===CONSTANTS and variables (buttons and pins)
const int buttonPin = 9;    // start button
const int estopbutton = 8;  //estop button
const int indexswitch = 7;  //table index switch
const int indexmotor = 6;   //table stepper motor
const int indexdir = 10;    //table stepper direction pin
//===== LED PINS
const int stn1good = 50;         //50
const int stn1bad = 52;          //52
const int stn2good = 46;         //46
const int stn2bad = 48;          //48
//===== STEPPER PINS
const int stepsPerRevolution = 200;
Stepper myStepper(stepsPerRevolution, 42, 40, 38, 36);
int stepspeed = 10;
//ALSO SEE myStepper.setSpeed(100);
//==== LCD Variable

int LCDtest = 0;
int printtest;

void setup()
{   
  lcd.begin(20, 4);  // SET LCD CONTRAST
  lcdclear();
  lcdbooting();
  }


void loop()
{

printtest = 1;
LCDUPDATE::lcdupdate(printtest, 2, 3, 4, 5, 6, 7);

  // TEST CYCLE 
}

LCD.H

/*
  LCD.h - Update QA machine LCD Display
*/

// ensure this library description is only included once
#ifndef LCD_h
#define LCD_h
// include types & constants of Wiring core API
#include <LiquidCrystal.h>
#include <Arduino.h>
  // user-accessible "public" interface

class LCDUPDATE{ 
  public:
    void lcdupdate(int status1, int status2, int status3, int status4, int hstatus, int mstatus, int bstatus);
    void lcdclear();
    void lcdbooting();
  private:
    int status1old;
    int status2old;
    int status3old;
    int status4old;
    int hstatusold;
    int mstatusold;
    int bstatusold;
    int test;

};
  #endif

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);



//==== CLEAR THAT LCD
  void lcdclear()
   {
      lcd.setCursor(0, 0);
      lcd.print("                        ");
      lcd.setCursor(0, 1);
      lcd.print("                        ");
      lcd.setCursor(0, 2);
      lcd.print("                        ");
      lcd.setCursor(0, 3);
      lcd.print("                        ");
   }

  void lcdbooting()
  {
      lcd.setCursor(0, 0);
      lcd.print("   Booting!    ");
      lcd.setCursor(0, 1);
      lcd.print("1:B 2:B 3:B 4:B");
  }


  //==== UPDATE LCD FUNCTION
  void LCDUPDATE::lcdupdate(int status1, int status2, int status3, int status4, int hstatus, int mstatus, int bstatus)
  {
// update
 if (hstatus != hstatusold) {
    if (hstatus == 1) {
      lcd.setCursor(0, 0);
      lcd.print("                    ");
      lcd.setCursor(0, 0);
      lcd.print("   Boot Complete    ");
    }
    if (hstatus == 2) {
      lcd.setCursor(0, 0);
      lcd.print("                    ");
      lcd.setCursor(0, 0);
      lcd.print("  Ready For Start  ");
    }
    if (hstatus == 3) {
      lcd.setCursor(0, 0);
      lcd.print("                    ");
      lcd.setCursor(0, 0);
      lcd.print("   Indexing Table   ");
    }
    if (hstatus == 4) {
      lcd.setCursor(0, 0);
      lcd.print("                    ");
      lcd.setCursor(0, 0);
      lcd.print("  Process Stopped  ");
    }
    if (hstatus == 5) {
      lcd.setCursor(0, 0);
      lcd.print("                    ");
      lcd.setCursor(0, 0);
      lcd.print("    Table Indexed   ");
    }
    if (hstatus == 6) {
      lcd.setCursor(0, 0);
      lcd.print("                    ");
      lcd.setCursor(0, 0);
      lcd.print("Waiting for Stations");
    }
    if (hstatus == 7) {
      lcd.setCursor(0, 0);
      lcd.print("                    ");
      lcd.setCursor(0, 0);
      lcd.print("Stations Timeout!");
    }
        if (hstatus == 8) {
      lcd.setCursor(0, 0);
      lcd.print("                    ");
      lcd.setCursor(0, 0);
      lcd.print("QA Success Indexing");
    }
            if (hstatus == 9) {
      lcd.setCursor(0, 0);
      lcd.print("                    ");
      lcd.setCursor(0, 0);
      lcd.print("Process Failure ");
    }
    hstatus = hstatusold;
  }//END hstatus UPDATE


//== MSTATUS UPDATE
  if (mstatus != mstatusold) {
    if (mstatus == 1) {
      lcd.setCursor(0, 2);
      lcd.print("                    ");
    }
    if (mstatus == 2) {
      lcd.setCursor(0, 2);
      lcd.print("                    ");
      lcd.setCursor(0, 2);
      lcd.print("Ready for start");
    }
    if (mstatus == 3) {
      lcd.setCursor(0, 2);
      lcd.print("                    ");
      lcd.setCursor(0, 2);
      lcd.print("Waiting for Stations");
    }

    if (mstatus == 4) {
      lcd.setCursor(0, 2);
      lcd.print("                    ");
      lcd.setCursor(0, 2);
      lcd.print("Index Stage 1");
    }

    if (mstatus == 5) {
      lcd.setCursor(0, 2);
      lcd.print("                    ");
      lcd.setCursor(0, 2);
      lcd.print("Index Stage 2");
    }
    if (mstatus == 6) {
      lcd.setCursor(0, 2);
      lcd.print("                    ");
      lcd.setCursor(0, 2);
      lcd.print("Index Stage 3");
    }
    if (mstatus == 7) {
      lcd.setCursor(0, 2);
      lcd.print("                    ");
      lcd.setCursor(0, 2);
      lcd.print("Index Completed");
    }
    mstatusold = mstatus;

  if (status1 != status1old) {
    if (status1 == 1) {
      lcd.setCursor(2, 1);
      lcd.print("R");
      status1 = status1old;
    }
    if (status1 == 2) {
      lcd.setCursor(2, 1);
      lcd.print("P");
      status1 = status1old;
    }
    if (status1 == 3) {
      lcd.setCursor(2, 1);
      lcd.print("F");
      status1 = status1old;
    }
    if (status1 == 4) {
      lcd.setCursor(2, 1);
      lcd.print("T");
      status1 = status1old;
    }
  }
  }//END STATUS1 UPDATE
  if (status2 != status2old) {
    if (status2 == 1) {
      lcd.setCursor(6, 1);
      lcd.print("R");
    }
    if (status2 == 2) {
      lcd.setCursor(6, 1);
      lcd.print("P");
    }
    if (status2 == 3) {
      lcd.setCursor(6, 1);
      lcd.print("F");
    }
    if (status2 == 4) {
      lcd.setCursor(6, 1);
      lcd.print("T");
    }
    status2 = status2old;
  }//END status2 UPDATE
  if (status3 != status3old) {
    if (status3 == 1) {
      lcd.setCursor(10, 1);
      lcd.print("R");
    }
    if (status3 == 2) {
      lcd.setCursor(10, 1);
      lcd.print("P");
    }
    if (status3 == 3) {
      lcd.setCursor(10, 1);
      lcd.print("F");
    }
    if (status3 == 4) {
      lcd.setCursor(10, 1);
      lcd.print("T");
    }
    status3 = status3old;
  }//END status3 UPDATE
  if (status4 != status4old) {
    if (status4 = 1) {
      lcd.setCursor(14, 1);
      lcd.print("R");
      status4 = status4old;
    }
    if (status4 == 2) {
      lcd.setCursor(14, 1);
      lcd.print("P");
      status4 = status4old;
    }
    if (status4 == 3) {
      lcd.setCursor(14, 1);
      lcd.print("F");
      status4 = status4old;
    }
    if (status4 == 4) {
      lcd.setCursor(14, 1);
      lcd.print("T");
      status4 = status4old;
    }
  }//END status4 UPDATE
  if (bstatus != bstatusold) {
    if (bstatus == 1) {
      lcd.setCursor(0, 3);
      lcd.print("                    ");
    }

    if (bstatus == 2) {
      lcd.setCursor(0, 3);
      lcd.print("                    ");
      lcd.setCursor(0, 3);
      lcd.print("Moving Table CW");

    }
    if (bstatus == 3) {
      lcd.setCursor(0, 3);
      lcd.print("                    ");
      lcd.setCursor(0, 3);
      lcd.print("Moving Table CCW");
    }
    if (bstatus == 4) {
      lcd.setCursor(0, 3);
      lcd.print("                    ");
      lcd.setCursor(0, 3);
      lcd.print("Station Timeout: ");
    }
    bstatusold = bstatus;
  }//END bstatus UPDATE

  //====start stationtimer for bstatus == 4
 // if (stationtimerstart != 0) {
 //   if (stationtimerstart == 2) {
 //     timer = stationtimer();
 //     if (timer != timerold) {
 //       lcd.setCursor(17, 3);
 //       lcd.print(timer);
 //     }
 //   }
 // }

  }

Could you point me at a resource to better explain that since google doesn't seem to come up with much relevant and I have no idea what you are talking about.

in the arduino playground:

but C++ classes are explained all over the web

BulldogLowell:
in the arduino playground:

https://www.arduino.cc/en/Hacking/LibraryTutorial

but C++ classes are explained all over the web

Yeah the best part being that the code posted doesn't seem work, even removing the wprogram.h which is apparently antiquated so without something that works to work from and figure out it hasn't been particularly useful.

I'll keep googling.

yeah, in that example they are initializing the hardware (i.e. pinMode) in the constructor, which is not reliable.

this should work and be a better model for you.

class Morse
{
  public:
    Morse(int pin);
    void begin();
    void dot();
    void dash();
  private:
    int _pin;
};

Morse::Morse(int pin) // constructor - this one takes exactly one parameter
{
  //pinMode(pin, OUTPUT);
  _pin = pin;
}

void Morse::begin()  // definition of member function, note the namespace notation
{
  pinMode(_pin, OUTPUT);
}

void Morse::dot()
{
  digitalWrite(_pin, HIGH);
  delay(250);
  digitalWrite(_pin, LOW);
  delay(250);  
}

void Morse::dash()
{
  digitalWrite(_pin, HIGH);
  delay(1000);
  digitalWrite(_pin, LOW);
  delay(250);
}

Morse myObject(13);  // calling the constructor with the on-board pin as its argument

void setup() 
{
  myObject.begin();
}

void loop() 
{
  myObject.dot(); myObject.dot(); myObject.dot();     // S
  myObject.dash(); myObject.dash(); myObject.dash();  // O
  myObject.dot(); myObject.dot(); myObject.dot();     // S
  delay(3000);
}

my advice is to develop your class in your .ino file (as I showed you here). Then, when when it works the way you want, decide if you need it to actually be a library. If it is never used on another project, well, you don't need a library.

Knowing how classes work is an important next step. Get familiar with that in simple examples like the Morse thingy, first. It shows you how to set up a constructor, private and public class members and (like you learned) when to properly set up the hardware!!

Yeah I kind of want to compartmentalize the bigger/obnoxious functions, and the station functions so I can swap in/out those files when I change what parts the machine will be working on, as I learn this stuff it just seems better to "box off" each big role of the code from each other role so something like a missed bracket doesn't detonate code and report an error thousands of lines away.

I did find this tutorial though and am making headway now: A classy solution | Multi-tasking the Arduino - Part 1 | Adafruit Learning System

The only issue I appear to still be running into is with the liquidcrystal library and the header file not being able to use lcd.begin (not a type) so now i'm investigating what you said earlier.

metalmm:
The only issue I appear to still be running into is with the liquidcrystal library and the header file not being able to use lcd.begin (not a type) so now i'm investigating what you said earlier.

something like this:

#include <LiquidCrystal.h>

class Morse
{
  public:
    Morse(int pin);
    void begin();
    void dot();
    void dash();
  private:
    int _pin;
    LiquidCrystal* lcd;
};

Morse::Morse(int pin)
{
  _pin = pin;
}

void Morse::begin()
{
  pinMode(_pin, OUTPUT);
  lcd  = new LiquidCrystal(12, 11, 5, 4, 3, 2);
  lcd->begin(20,4);  //edited for your display size...
  lcd->print("hello, world!");
}

void Morse::dot()
{
  digitalWrite(_pin, HIGH);
  delay(250);
  digitalWrite(_pin, LOW);
  delay(250);  
}

void Morse::dash()
{
  digitalWrite(_pin, HIGH);
  delay(1000);
  digitalWrite(_pin, LOW);
  delay(250);
}

Morse myObject(13);

void setup() 
{
  myObject.begin();
}

void loop() 
{
  myObject.dot(); myObject.dot(); myObject.dot();
  myObject.dash(); myObject.dash(); myObject.dash();
  myObject.dot(); myObject.dot(); myObject.dot();
  delay(3000);
}

The problem I'm seeing is it doesn't recognize the lcd.begin command that tells the library how many rows and columns your lcd has, it works fine without it but It would be a pain in the ass

So its a little confusing as to what is up with that one

exit status 1
'lcd' does not name a type

#ifndef LCD_h
#define LCD_h
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
  lcd.begin(20, 4);
  int status1; 
  int status2;
  int status3;
  int status4;
  int status1old;
  int status2old;
  int status3old;
  int status4old;
  int hstatus;    // header
  int mstatus;    // Middle status        1= Startup 2=Ready 3=Waiting for STN 4 index stg 1
  int bstatus;    // Bottom status
  int hstatusold;
  int mstatusold;
  int bstatusold;
  int feedback;       // lcd feedback print
  int feedbackold;
class LCDUPDATE
{
  // all LCDUPDATE variables and shit go here
  // https://learn.adafruit.com/multi-tasking-the-arduino-part-1/a-classy-solution


  // Constructor

  
  public:
  LCDUPDATE(int status1, int status2, int status3, int status4, int hstatus, int mstatus, int bstatus)
  {
  if (hstatus != hstatusold) {
    if (hstatus == 1) {
      lcd.setCursor(0, 0);
      lcd.print("                    ");
      lcd.setCursor(0, 0);
      lcd.print("   Boot Complete    ");
    }
        hstatusold = hstatus;
        delay(100);
      lcd.setCursor(2, 2);
      lcd.print(hstatus);
      lcd.setCursor(3, 3);
      lcd.print(hstatusold);
  }

}
};



#endif

metalmm:
The problem I'm seeing is ...

did you try the example I gave you?

Well I did try to replace the lcd.begin with lcd->begin with the same result, not the whole thing

metalmm:
Well I did try to replace the lcd.begin with lcd->begin with the same result, not the whole thing

you can certainly continue trying random cut/paste and eventually you will get it (1000 monkeys behind 1000 typewriters analogy).

Or, you can just start over and learn how a class is created and used.

Forget about creating a library, the .h and .cpp files until you have code that actually works, or you fully understand the use of the #include guards and how the library (literally) gets pasted into your .ino file.

You mean like the code I have which actually works when in the sketch but then does not when moved to the header file and I can't identify why as stated above?

metalmm:
You mean like the code I have which actually works when in the sketch but then does not when moved to the header file and I can't identify why as stated above?

exactly! because you haven't yet learned how to create and implement a class.