//
// Relay Contactors
//================================================^================================================
// T o p O f S k e t c h
//
//
// https://forum.arduino.cc/t/it-is-about-controlling-2-no-relay-contactors-based-on-inputs-and-feedbacks/1274658
//
// HLD
//
// Version YY/MM/DD Comments
// ======= ======== ========================================================================
// 1.00 24/06/23 Started writing sketch
// M A C R O S
//================================================^================================================
#define LEDon HIGH //PIN---[220R]---A[LED]K---GND
#define LEDoff LOW
#define PRESSED LOW //+5V---[Internal 50k]---PIN---[Switch]---GND
#define RELEASED HIGH
#define CLOSED HIGH
#define OPENED LOW
#define ENABLED true
#define DISABLED false
//======================================================================== <-------<<<<<<<
//these macros are used for debug purposes
//
//comment next line to stop printing to the Serial Monitor,
//#define DEBUG
//debug Macros
//========================
#ifdef DEBUG
#define SERIALBEGIN(...) Serial.begin(__VA_ARGS__)
#define DPRINT(...) Serial.print(__VA_ARGS__)
#define DPRINTLN(...) Serial.println(__VA_ARGS__)
#define DPRINTF(...) Serial.print(F(__VA_ARGS__)) //for text only, using the F macro
#define DPRINTLNF(...) Serial.println(F(__VA_ARGS__)) //for text only, using the F macro plus new line
#else
#define SERIALBEGIN(...)
#define DPRINT(...)
#define DPRINTLN(...)
#define DPRINTF(...)
#define DPRINTLNF(...)
#endif
//Arduino UNO, produce a 62ns pulse on D13
#define PULSE62Heartbeat cli(); PINB = bit(PINB5); PINB = bit(PINB5); sei()
//Example: PULSE62Heartbeat;
// G P I O s
//================================================^================================================
//
//a structure to define input objects, switches or sensors
struct makeInput
{
const byte pin; //the digital input pin number
unsigned long switchTime; //the time the switch was closed
byte lastState; //the state the input was last in
byte counter; //a counter used to validate a switch change in state
}; //END of struct makeInput
const byte inputPins[] = {2, 3, 4};
//Digital Inputs
//define the input connected to a PB switch
//========================
makeInput buttonPin1 =
{
2, 0, OPENED, 0 //pin, switchTime, lastState, counter
};
//========================
makeInput buttonPin2 =
{
3, 0, OPENED, 0 //pin, switchTime, lastState, counter
};
//========================
makeInput buttonPin3 =
{
4, 0, OPENED, 0 //pin, switchTime, lastState, counter
};
//========================
byte filter = 10;
//TIMER "switches" runs every 5ms.
//5ms * 10 = 50ms is needed to validate a switch change in state.
//A switch change in state is valid "only after" 10 identical changes are detected.
//This is used to filter out EMI noise in the system
//OUTPUTS
//===================================
const byte outputPins[] = {11, 12, 8};
const byte buttonLED1 = 11;
const byte buttonLED2 = 12;
const byte blinkLED = 8;
// V A R I A B L E S
//================================================^================================================
//
//================================================^================================================
// millis() / micros() B a s e d T I M E R S
//================================================^================================================
//TIMER objects are non-blocking
struct makeTIMER
{
#define MILLIS 1
#define MICROS 1000 //we can use this value to divide into a variable to get milliseconds
#define ENABLED true
#define DISABLED false
#define YES true
#define NO false
#define STILLtiming 0
#define EXPIRED 1
#define TIMERdisabled 2
//these are the bare minimum "members" needed when defining a TIMER
int TimerType; //what kind of TIMER is this? MILLIS/MICROS
unsigned long Time; //when the TIMER started
unsigned long Interval; //delay time which we are looking for
bool TimerFlag; //is the TIMER enabled ? ENABLED/DISABLED
bool Restart; //do we restart this TIMER ? YES/NO
//================================================
//condition returned: STILLtiming (0), EXPIRED (1) or TIMERdisabled (2)
//function to check the state of our TIMER ex: if(myTimer.checkTIMER() == EXPIRED);
byte checkTIMER()
{
//========================
//is this TIMER enabled ?
if (TimerFlag == ENABLED)
{
//========================
//has this TIMER expired ?
if (getTime() - Time >= Interval)
{
//========================
//should this TIMER restart again?
if (Restart == YES)
{
//restart this TIMER
Time = getTime();
}
//this TIMER has expired
return EXPIRED;
}
//========================
else
{
//this TIMER has not expired
return STILLtiming;
}
} //END of if (TimerFlag == ENABLED)
//========================
else
{
//this TIMER is disabled
return TIMERdisabled;
}
} //END of checkTime()
//================================================
//function to enable and restart this TIMER ex: myTimer.enableRestartTIMER();
void enableRestartTIMER()
{
TimerFlag = ENABLED;
//restart this TIMER
Time = getTime();
} //END of enableRestartTIMER()
//================================================
//function to disable this TIMER ex: myTimer.disableTIMER();
void disableTIMER()
{
TimerFlag = DISABLED;
} //END of disableTIMER()
//================================================
//function to restart this TIMER ex: myTimer.restartTIMER();
void restartTIMER()
{
Time = getTime();
} //END of restartTIMER()
//================================================
//function to force this TIMER to expire ex: myTimer.expireTimer();
void expireTimer()
{
//force this TIMER to expire
Time = getTime() - Interval;
} //END of expireTimer()
//================================================
//function to set the Interval for this TIMER ex: myTimer.setInterval(100);
void setInterval(unsigned long value)
{
//set the Interval
Interval = value;
} //END of setInterval()
//================================================
//function to return the current time
unsigned long getTime()
{
//return the time i.e. millis() or micros()
//========================
if (TimerType == MILLIS)
{
return millis();
}
//========================
else
{
return micros();
}
} //END of getTime()
}; //END of struct makeTIMER
// D e f i n e a l l t h e T I M E R S
//================================================^================================================
/*example
//========================
makeTIMER toggleLED =
{
MILLIS/MICROS, 0, 500ul, ENABLED/DISABLED, YES/NO //.TimerType, .Time, .Interval, .TimerFlag, .Restart
};
Functions we can access:
toggleLED.checkTIMER();
toggleLED.enableRestartTIMER();
toggleLED.disableTIMER();
toggleLED.expireTimer();
toggleLED.setInterval(100ul);
*/
//========================
makeTIMER heartbeatTIMER =
{
MILLIS, 0, 200ul, ENABLED, YES //.TimerType, .Time, .Interval, .TimerFlag, .Restart
};
//========================
makeTIMER switchesTIMER =
{
MILLIS, 0, 5ul, ENABLED, YES //.TimerType, .Time, .Interval, .TimerFlag, .Restart
};
//========================
makeTIMER machineTIMER =
{
MILLIS, 0, 10ul, ENABLED, YES //.TimerType, .Time, .Interval, .TimerFlag, .Restart
};
// s e t u p ( )
//================================================^================================================
//
void setup()
{
//this delay prevents setup() from running twice when we use the serial monitor
//remove this delay() if the serial monitor is not used.
delay(1000);
SERIALBEGIN(115200);
//Inputs
//======================
//use INPUT_PULLUP so the pin does not float, floating pins can cause faulty readings
//configure the input pins
for (byte x = 0; x < sizeof(inputPins); x++)
{
pinMode(inputPins[x], INPUT_PULLUP);
}
//Outputs
//======================
//configure the output pins
for (byte x = 0; x < sizeof(outputPins); x++)
{
digitalWrite(outputPins[x], LEDoff);
pinMode(outputPins[x], OUTPUT);
}
} //END of setup()
// l o o p ( )
//================================================^================================================
//
void loop()
{
//======================================================================== T I M E R heartbeat
//condition returned: STILLtiming, EXPIRED or TIMERdisabled
//if the TIMER is enabled, is it time to toggle the heartbeat LED ?
if (heartbeatTIMER.checkTIMER() == EXPIRED)
{
//when this TIMER expires, toggle the heartbeat LED
//this LED is a rudimentary way of displaying if the sketch code is blocking or stuttering
//toggle the heartbeat LED
digitalWrite(blinkLED, digitalRead(blinkLED) == HIGH ? LOW : HIGH);
} //END of this TIMER
//======================================================================== T I M E R switches
//condition returned: STILLtiming, EXPIRED or TIMERdisabled
//if the TIMER is enabled, is it time to check our switches ?
if (switchesTIMER.checkTIMER() == EXPIRED)
{
//when this TIMER expires, check if any switch/sensor has changed state
checkSwitches();
} //END of this TIMER
//======================================================================== T I M E R machine
//condition returned: STILLtiming, EXPIRED or TIMERdisabled
//if the TIMER is enabled, is it time to service our State Machines ?
if (machineTIMER.checkTIMER() == EXPIRED)
{
//check all the "State Machines"
checkMachines();
} //END of this TIMER
//=========================================
//other none blocking code goes here
//=========================================
} //END of loop()
// c h e c k S w i t c h e s ( )
//================================================^================================================
//
void checkSwitches()
{
byte currentState;
//======================================================================== buttonPin1.pin
currentState = digitalRead(buttonPin1.pin);
//===================================
//has this switch changed state ?
if (buttonPin1.lastState != currentState)
{
buttonPin1.counter++;
//is this change in state stable ?
if (buttonPin1.counter >= filter)
{
//get ready for the next sequence
buttonPin1.counter = 0;
//update to this new state
buttonPin1.lastState = currentState;
//================================================ buttonPin1 CLOSED ?
//did this switch close ?
if (currentState == CLOSED)
{
DPRINTLNF("buttonPin1 switch closed");
//the time the switch went closed
buttonPin1.switchTime = millis();
}
//========================
//did this switch open ?
else if (currentState == OPENED)
{
DPRINTLNF("buttonPin1 switch opened");
}
}
}
//a valid switch change has not been confirmed
else
{
buttonPin1.counter = 0;
}
//END of buttonPin1.pin
//======================================================================== buttonPin2.pin
currentState = digitalRead(buttonPin2.pin);
//===================================
//has this switch changed state ?
if (buttonPin2.lastState != currentState)
{
buttonPin2.counter++;
//is this change in state stable ?
if (buttonPin2.counter >= filter)
{
//get ready for the next sequence
buttonPin2.counter = 0;
//update to this new state
buttonPin2.lastState = currentState;
//================================================ buttonPin2 CLOSED ?
//did this switch close ?
if (currentState == CLOSED)
{
DPRINTLNF("buttonPin2 switch closed");
//the time the switch went closed
buttonPin2.switchTime = millis();
}
//========================
//did this switch open ?
else if (currentState == OPENED)
{
DPRINTLNF("buttonPin2 switch opened");
}
}
}
//a valid switch change has not been confirmed
else
{
buttonPin2.counter = 0;
}
//END of buttonPin2.pin
//======================================================================== buttonPin3.pin
currentState = digitalRead(buttonPin3.pin);
//===================================
//has this switch changed state ?
if (buttonPin3.lastState != currentState)
{
buttonPin3.counter++;
//is this change in state stable ?
if (buttonPin3.counter >= filter)
{
//get ready for the next sequence
buttonPin3.counter = 0;
//update to this new state
buttonPin3.lastState = currentState;
//================================================ buttonPin3 CLOSED ?
//did this switch close ?
if (currentState == CLOSED)
{
DPRINTLNF("buttonPin3 switch closed");
//the time the switch went closed
buttonPin3.switchTime = millis();
}
//========================
//did this switch open ?
else if (currentState == OPENED)
{
DPRINTLNF("buttonPin3 switch opened");
}
}
}
//a valid switch change has not been confirmed
else
{
buttonPin3.counter = 0;
}
//END of buttonPin3.pin
//===================================
} //END of checkSwitches()
// c h e c k M a c h i n e s ( )
//================================================^================================================
//
void checkMachines()
{
//assemble the one of 8 possible input combinations
byte switchState = buttonPin1.lastState;
switchState = (switchState << 1) + buttonPin2.lastState;
switchState = (switchState << 1) + buttonPin3.lastState;
//DPRINTF("State = ");
//DPRINTLN(switchState);
//======================================================================== switch State Machine
switch (switchState)
{
//==========================
case 0:
{
digitalWrite(buttonLED1, LEDoff);
digitalWrite(buttonLED2, LEDoff);
}
break;
//==========================
case 1:
{
digitalWrite(buttonLED1, LEDoff);
digitalWrite(buttonLED2, LEDon);
}
break;
//==========================
case 2:
{
digitalWrite(buttonLED1, LEDon);
digitalWrite(buttonLED2, LEDoff);
}
break;
//==========================
case 3:
{
digitalWrite(buttonLED1, LEDon);
digitalWrite(buttonLED2, LEDon);
}
break;
//==========================
case 4:
{
digitalWrite(buttonLED1, LEDoff);
digitalWrite(buttonLED2, LEDoff);
}
break;
//==========================
case 5:
{
digitalWrite(buttonLED1, LEDoff);
digitalWrite(buttonLED2, LEDon);
}
break;
//==========================
case 6:
{
digitalWrite(buttonLED1, LEDon);
digitalWrite(buttonLED2, LEDoff);
}
break;
//==========================
case 7:
{
digitalWrite(buttonLED1, LEDon);
digitalWrite(buttonLED2, LEDon);
}
break;
} //END of switch/case
} //END of checkMachines()
//
//================================================^================================================
//
- We really need to see a schematic of the final project.