#include <Servo.h>
/**************************************************************************************************
Lesson 5 - restructuring our data
- using clearer data types
- creating functions
**************************************************************************************************/
const bool HOME = 0; //alleviates having to think about ones and zeros when evaluating logic
const bool THROWN = 1; //
struct TURNOUTS { //values that are static and must be stored for use after next reset/power up
uint8_t servoPin; //where we send the pulse to position the servo
uint8_t buttonPin; //where we get the setting for the servo from(i.e. the Touch Toggle connection)
uint16_t homePosition; //the angle needed for 'homing' the turnout
uint16_t thrownPosition; //the angle needed for 'throwing' the turnout
};
struct TURNOUTV { //values that are volatile, initialized after every reset/power up
bool state; //commanded state of the servo (Touch Toggle
Servo ourServo; //a holder for the instance of the servo
};
struct TURNOUT {
TURNOUTS S; //static
TURNOUTV V; //volatile
};
TURNOUT Turnouts[] = {
{{2, 3, 45, 135}, {}}, //a servo on pin 2, button on pin 3; moves from 45 to 135; note the volatile elements don't get initialized
{{4, 5, 35, 145}, {}}, //a servo on pin 4, button on pin 5, with different angles
};
int NumTurnouts = sizeof(Turnouts) / sizeof(TURNOUT); //all this says is "tell me the size of that turnout array(in bytes), and divide that by the size of the TURNOUT structure, to arrive at the number of turnouts represented in the array
int PresTurnout = 0; //counter used to indicate which turnout is presently active
void setup() { //of course now, we need to handle both turnouts, so we'll add a for loop to work on each one
for (int i = 0; i < NumTurnouts;) { //so, for each turnout in the array, do the following actions
Turnouts[i].V.state = THROWN; //the button will read as 'HOME' in update, so pre-force state to 'THROWN' to trigger an update
i = updateTurnout(i); //call the update function
if (i == 0) break; //since update is doing the incrementing of i, we need to break the loop when i wraps around to zero.
}//end of for loop
}//end of setup()
void loop() {//note how, since loop repeats endlessly, we don't need a for loop in loop.
PresTurnout = updateTurnout(PresTurnout);//updateTurnout will return the same turnout number if it's not done with the update, else it returns the next turnout to be managed
}
int updateTurnout(int t) { //this function will get much more complex, but this is it's essence
bool oldState = Turnouts[t].V.state; //to remember where we were
Turnouts[t].V.state = digitalRead(Turnouts[t].S.buttonPin); //find out what position the switch is in
if (Turnouts[t].V.state != oldState) { //if the button has changed, do update
if (Turnouts[t].V.state == HOME) {
Turnouts[t].V.ourServo.write(Turnouts[t].S.homePosition); //set position
} else {
Turnouts[t].V.ourServo.write(Turnouts[t].S.thrownPosition); //set position
}
Turnouts[t].V.ourServo.attach(Turnouts[t].S.servoPin); //tells ourServo what pin to send signal on
delay(1000); //must presume servo misaligned, wait for it to finish; may need tuning
Turnouts[t].V.ourServo.detach(); //must leave servo detached for power conservation
}//end of change code
return (t + 1) % NumTurnouts; //select next turnout, automatically wrap around if at end of array
} //end of updateTurnout