Using structures

I am trying to understand structures.
The attached sketch flashes a LED on pin 13.

I initially thought line 51 should have been:
boolean CheckTime(makeTimer *thisTimer)
Why does this not work?

This makes it work:
boolean CheckTime(struct timer *thisTimer) //<<<<<<<<<<<<<<< LINE 51 >>>>>>>>>>>>

//Blink without Delay skeleton (using structures)  
//LarryD
typedef struct timer
{
  unsigned long lastMillis; 
  unsigned long waitMillis; 
  boolean       restart; 
  boolean       enableFlag;
}makeTimer;
makeTimer pin13 = 
{
  0, 200, true, true
};

//**********************************************************************

void setup()
{
  pinMode(13, OUTPUT);

} //  >>>>>>>>>>>>>> E N D  O F  s e t u p ( ) <<<<<<<<<<<<<<<<<


void loop()
{
  //***************************
  //toggle pin 13 200ms
  if (CheckTime(&pin13))
  {
    //toggle pin 13
    digitalWrite(13,!digitalRead(13));

    //if you only want this section of code to happen once
    //uncomment the next line 
    //pin13.enableFlag = false;
  }

} //  >>>>>>>>>>>>>> E N D  O F  l o o p ( ) <<<<<<<<<<<<<<<<<


//======================================================================
//                      F U N C T I O N S
//======================================================================

//**********************************************************************
//Delay time expired function
//lastMillis = time we started
//waitMillis = delay in mS
//restart    = do we start again  
//enableFlag = is this timer enabled
boolean CheckTime(struct timer *thisTimer)   //<<<<<<<<<<<<<<< LINE 51 >>>>>>>>>>>>
{
  //is the time up for this task?
  if (thisTimer->enableFlag && millis() - thisTimer->lastMillis >= thisTimer->waitMillis) 
  {
    //should this start again? 
    if(thisTimer->restart)
    {
      //get ready for the next iteration
      thisTimer->lastMillis += thisTimer->waitMillis;  //get ready for the next iteration
    }
    return true;
  }

  return false;

} // END of CheckTime()


//**********************************************************************

//======================================================================
//                      E N D  O F  C O D E
//======================================================================

When you make up a name : int numberOfGreenApples = 9 ;
Then the 'int' is the type and the 'numberOfGreenApples' is the name of the variable.

For prototyping you can use 'int', but not 'numberOfGreenApples'.
This is good prototyping : void MakeAppleSauce ( int x ) ;
This is wrong prototyping : void MakeAppleSauce ( numberOfGreenApples x ) ;

To avoid confusion, I like to add 'STRUCT' after the type of the struct.

struct myTimerSTRUCT
{
  unsigned long lastMillis;
  unsigned long waitMillis;
  boolean       restart;
  boolean       enableFlag;
} myTimer;

The 'myTimerSTRUCT' is the type, it can be used just as an 'int' or 'float'.
The 'myTimer' is the name of a variable that you make up yourself.

The "typedef" keyword is no longer needed for a struct. It is automatically assumed that 'myTimerSTRUCT' is a typedef.

When you do this prototyping : boolean CheckTime(makeTimer *thisTimer) ;
It is the same as : boolean CheckTime ( numberOfGreenApples * thisTimer ) ;
They are both wrong of course.

You know that structures can have methodes just like classes?
You can get rid of all the thisTimer-> stuff.

typedef struct timer
{
  unsigned long lastMillis;
  unsigned long waitMillis;
  boolean       restart;
  boolean       enableFlag;
  boolean       CheckTime();
} makeTimer;

boolean timer::CheckTime()
{
  //is the time up for this task?
  if (enableFlag && millis() - lastMillis >= waitMillis)
  {
    //should this start again?
    if (restart)
    {
      //get ready for the next iteration
      lastMillis += waitMillis;  //get ready for the next iteration
    }
    return true;
  }
  return false;
}
  if (pin13.CheckTime())

You know that structures can have methodes just like classes?

Yes.
The only real difference between a class and a struct is that by default in a class, members are private, but in a struct they're public.

Groove:
Yes.
The only real difference between a class and a struct is that by default in a class, members are private, but in a struct they're public.

Did not know that.

You know that structures can have methodes just like classes?

Once you do that, I fail to see the benefit of keeping with the struct concept. If you want a class (data and methods), make a class. If you want a struct (data only), make a struct.

LarryD's problem would go away if the struct was properly defined in a header file.

Thanks for all the replies.
Very much appreciated.

I was trying to use a struct with data only in my example.
I have "A Book on C" page 410 that states:

typedef struct {
float re;
float im;
} complex;

complex a, b, c[100];

I took this to mean complex was a/the new type and a tag name after struct was not needed.
complex a, b, c[100];
would be similar to
int a, b, c[100];

My guess is things have changed and the book is no longer accurate.

@Whandall
I had thought C struct was for data only and it was C++ that introduced methods to data to create class.
Perhaps that's the way it was in the original version form K&R.
Time to get a C++ book.

LarryD:
Thanks for all the replies.
Very much appreciated.

I was trying to use a struct with data only in my example.
I have "A Book on C" page 410 that states:

typedef struct {
float re;
float im;
} complex;

complex a, b, c[100];

I took this to mean complex was a/the new type and a tag name after struct was not needed.
complex a, b, c[100];
would be similar to
int a, b, c[100];

My guess is things have changed and the book is no longer accurate.

@Whandall
I had thought C struct was for data only and it was C++ that introduced methods to data to create class.
Perhaps that's the way it was in the original version form K&R.
Time to get a C++ book.

No, the book is 100% correct, but you did not duplicate what is given in the example in the book. You defined a struct, while the book defined a typedef - two different things. typedef defines a new type (similar to int, float, etc.). The example in the book defines a new type that happens to be a struct. In general, you're probably better off using typedef when defining structs, so you get the benefits of type-checking and, arguably, cleaner syntax when you use the new type.

Regards,
Ray L.

Thanks Ray
"LarryD's problem would go away if the struct was properly defined in a header file."
Thanks PaulS

OK this works see line 135:
boolean CheckTime(timers *thisTimer)

struct _timers
{
  unsigned long lastMillis; 
  unsigned long waitMillis; 
  bool       restart; 
  bool       enableFlag;
};

typedef struct _timers timers;
//Blink without Delay skeleton (using structures)  
//LarryD
#include "header.h"

timers pin13 = 
{
  0, 200, true, true
};
timers pin12 = 
{
  0, 3000, true, true
};
timers pin11 = 
{
  0, 10000, true, true
};
timers pin10 = 
{
  0, 6000, true, true
};
timers Toggle10 = 
{
  0, 50, true, true
};
timers checkSwitches = 
{
  0, 50, true, true
};

byte lastMySwitchState       = 1;
byte counter                 = 0;

const byte mySwitch = 2;

//**********************************************************************

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

  pinMode(13, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(9,  OUTPUT);

  pinMode(mySwitch, INPUT_PULLUP);


} //  >>>>>>>>>>>>>> E N D  O F  s e t u p ( ) <<<<<<<<<<<<<<<<<


void loop()
{
  //***************************
  //toggle pin 13 200ms
  if (CheckTime(&pin13))
  {
    //toggle pin 13
    digitalWrite(13,!digitalRead(13));

    //if you only want this section of code to happen once
    //uncomment the next line 
    //pin13.enableFlag = false;
  }

  //***************************
  //after 3 seconds, pin 12 goes and stays HIGH 

  if (CheckTime(&pin12))
  {
    //toggle pin 12
    digitalWrite(12,!digitalRead(12));
    pin12.enableFlag = false;
  }

  //***************************
  //pin 11 is HIGH for 10 seconds, then goes and stays LOW
  if (pin11.enableFlag && !CheckTime(&pin11))
  {
    digitalWrite(11,HIGH);
  }
  //10 seconds is now up, go LOW
  else
  {
    digitalWrite(11,LOW);
    //disable above code 
    pin11.enableFlag = false;
  }

  //***************************
  //for 6 seconds, toggle pin 10
  if (pin10.enableFlag && !CheckTime(&pin10))
  {
    //toggle pin 10 every 50mS
    if(CheckTime(&Toggle10))
    {  
      digitalWrite(10,!digitalRead(10));    
    }
  }

  //6 seconds is now up, stop toggling
  else
  {
    digitalWrite(10,LOW);
    //disable 
    pin10.enableFlag = false;
  }

  //***************************
  //is it time to check the switches?
  if (CheckTime(&checkSwitches))
  {
    Switches();      
  } 


  //***************************
  //put other non-blocking stuff here


} //  >>>>>>>>>>>>>> E N D  O F  l o o p ( ) <<<<<<<<<<<<<<<<<


//======================================================================
//                      F U N C T I O N S
//======================================================================

//**********************************************************************
//Delay time expired function
//lastMillis = time we started
//waitMillis = delay in mS
//restart    = do we start again  
//enableFlag = is this timer enabled
boolean CheckTime(timers *thisTimer) // <<<<<<<<<<<<<<   LINE 135  >>>>>>>>>>
{
  //is the time up for this task?
  if (thisTimer->enableFlag && millis() - thisTimer->lastMillis >= thisTimer->waitMillis) 
  {
    //should this start again? 
    if(thisTimer->restart)
    {
      //get ready for the next iteration
      thisTimer->lastMillis += thisTimer->waitMillis;  //get ready for the next iteration
    }
    return true;
  }

  return false;

} // END of CheckTime()


//**********************************************************************
//switches are checked every Switches.waitMillis milli seconds 
//no minimum switch press time is validated with this code (i.e. No glitch filter)
void Switches()  
{
  //re-usable for all the switches  
  boolean thisState;    

  //***************************    
  //check if this switch has changed state
  thisState = digitalRead(mySwitch);
  if (thisState != lastMySwitchState)
  {  
    //update the switch state
    lastMySwitchState = thisState;  

    //this switch position has changed so do some stuff

    //"HIGH condition code"
    //switch goes from LOW to HIGH
    if(thisState == HIGH)        
    {
      //example: LED on pin 9 is Push ON, Push OFF
      digitalWrite(9,!digitalRead(9)); 
    }

    //"LOW condition code"
    //switch goes from HIGH to LOW
    else                          
    {
      //example: display the current switch push count 
      Serial.println(++counter);      
    }

  } //END of mySwitch code

  //***************************  
  //similar code for other switches goes here 

} //END of Switches()

//**********************************************************************

//======================================================================
//                      E N D  O F  C O D E
//======================================================================

The simpler, more concise, more readable way to both declare the structure, and the typedef would be:

typedef struct
{
  unsigned long lastMillis; 
  unsigned long waitMillis; 
  bool       restart; 
  bool       enableFlag;
} timers;

timers pin13 = 
{
  0, 200, true, true
};

Regards,
Ray L.

@RayLivingston
Yes, I would then have to use:
boolean CheckTime(struct timers *thisTimer) // <<<<<<<<<<<<<< LINE 135 >>>>>>>>>>

When I use a header file as in post #8:
typedef struct _timers timers;
I would not need the word "struct" as below
boolean CheckTime(timers *thisTimer) // <<<<<<<<<<<<<< LINE 135 >>>>>>>>>>

I like your suggestion, then I would not need the header file.

Just trying to understand the in and outs :o