DISCLAIMER: I haven't tested the code in this answer, but I hope there are no problems.
Your code has a major problem: what happens when one gate is moving and you trigger another movement? (reply: something bad). This design issue can be solved by using a standard way of designing these kind of state machine.
In your case a small state machine is what best fits your problem. Better give your states a meaningful name, no?
Ok, so just to start, let's define the states and how to transition through them.
You have basically an idle state, open gate, close gate, open garage door, close garage door. What should you do in these states, both when entering the state and during the time you are in the state? Here is a table to summarize
State | Enter | During time
----------------------------------------------
Idle | Stop motors | -
OpenGate | Start A dir 1 | -
CloseGate | Start A dir 2 | -
OpenGarage | Start B dir 1 | -
CloseGarage | Start B dir 2 | -
The transitions are pretty straightforward. Exit from idle when you receive a (valid) command, exit from the others when you reach the endstop.
The implementation is pretty standard:
// Motor for Gate (MotorA)
const byte IN1 = 2;
const byte IN2 = 3;
const byte EnableMotorA = 9;
// Motor for Garage Door (MotorB)
const byte IN3 = 4;
const byte IN4 = 5;
const byte EnableMotorB = 10;
const byte LimitSwitch1 = A1;
const byte LimitSwitch2 = A2;
const byte LimitSwitch3 = A3;
const byte LimitSwitch4 = A4;
const byte State_Idle = 0;
const byte State_OpenGate = 1;
const byte State_CloseGate = 2;
const byte State_OpenGarage = 3;
const byte State_CloseGarage = 4;
byte currentState;
void setup(){
pinMode(IN1,OUTPUT);
pinMode(IN2,OUTPUT);
pinMode(EnableMotorA,OUTPUT);
pinMode(IN3,OUTPUT);
pinMode(IN4,OUTPUT);
pinMode(EnableMotorB,OUTPUT);
pinMode(LimitSwitch1, INPUT);
pinMode(LimitSwitch2, INPUT);
pinMode(LimitSwitch3, INPUT);
pinMode(LimitSwitch4, INPUT);
Serial.begin(9600);
currentState = 0xFF; // Force a change to enter the idle state
}
void loop(){
// Check if we need to change state
byte nextState = currentState;
switch (currentState)
{
case State_Idle:
{ // If we received a valid command, start the operation
if(Serial.available() > 0)
{
switch (Serial.read())
{
case 'A':
nextState = State_OpenGate;
break;
case 'B':
nextState = State_CloseGate;
break;
case 'C':
nextState = State_OpenGarage;
break;
case 'D':
nextState = State_CloseGarage;
break;
default:
// Here you can notify that there was a bad command
break;
}
}
}
break;
case State_OpenGate:
if(digitalRead(LimitSwitch2)) // == HIGH is not necessary
nextState = State_Idle;
break;
case State_CloseGate:
if(digitalRead(LimitSwitch1)) // == HIGH is not necessary
nextState = State_Idle;
break;
case State_OpenGarage:
if(digitalRead(LimitSwitch4)) // == HIGH is not necessary
nextState = State_Idle;
break;
case State_CloseGarage:
if(digitalRead(LimitSwitch3)) // == HIGH is not necessary
nextState = State_Idle;
break;
default:
nextState = State_Idle;
break;
}
// If there was a change, switch state and trigger enter condition
if (nextState != currentState)
{
currentState = nextState; // Move in the new state
switch (currentState)
{ // Entering the new state
case State_Idle:
// Stop motor A
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
analogWrite(EnableMotorA, 0);
// Stop motor B
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
analogWrite(EnableMotorB, 0);
break;
case State_OpenGate:
// Start motor A
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
analogWrite(EnableMotorA, 250);
break;
case State_CloseGate:
// Start motor A
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
analogWrite(EnableMotorA, 250);
break;
case State_OpenGarage:
// Start motor B
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
analogWrite(EnableMotorB, 250);
break;
case State_CloseGarage:
// Start motor B
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
analogWrite(EnableMotorB, 250);
break;
}
}
}
(Note: I changed some types because your poor 8-bit uC asked me to avoid complicating its calculations unnecessarily)
One modification to your algorithm is to detach the two loops, since they seem, well, detached.
// Motor for Gate (MotorA)
const byte IN1 = 2;
const byte IN2 = 3;
const byte EnableMotorA = 9;
// Motor for Garage Door (MotorB)
const byte IN3 = 4;
const byte IN4 = 5;
const byte EnableMotorB = 10;
const byte LimitSwitch1 = A1;
const byte LimitSwitch2 = A2;
const byte LimitSwitch3 = A3;
const byte LimitSwitch4 = A4;
const byte StateA_Idle = 0;
const byte StateA_Open = 1;
const byte StateA_Close = 2;
byte currentStateA;
const byte StateB_Idle = 0;
const byte StateB_Open = 1;
const byte StateB_Close = 2;
byte currentStateB;
void setup(){
pinMode(IN1,OUTPUT);
pinMode(IN2,OUTPUT);
pinMode(EnableMotorA,OUTPUT);
pinMode(IN3,OUTPUT);
pinMode(IN4,OUTPUT);
pinMode(EnableMotorB,OUTPUT);
pinMode(LimitSwitch1, INPUT);
pinMode(LimitSwitch2, INPUT);
pinMode(LimitSwitch3, INPUT);
pinMode(LimitSwitch4, INPUT);
Serial.begin(9600);
currentStateA = 0xFF; // Force a change to enter the idle state
currentStateB = 0xFF; // Force a change to enter the idle state
}
void loop()
{
byte readChar = 0;
if(Serial.available() > 0)
readChar = Serial.read();
stateMachineA(readChar);
stateMachineB(readChar);
}
void stateMachineA(byte readChar)
{
// Check if we need to change state
byte nextState = currentStateA;
switch (currentStateA)
{
case StateA_Idle:
{ // If we received a valid command, start the operation
if(readChar > 0)
{
switch (readChar)
{
case 'A':
nextState = StateA_Open;
break;
case 'B':
nextState = StateA_Close;
break;
default:
// Here you can notify that there was a bad command
break;
}
}
}
break;
case StateA_Open:
if(digitalRead(LimitSwitch2)) // == HIGH is not necessary
nextState = StateA_Idle;
break;
case StateA_Close:
if(digitalRead(LimitSwitch1)) // == HIGH is not necessary
nextState = StateA_Idle;
break;
default:
nextState = StateA_Idle;
break;
}
// If there was a change, switch state and trigger enter condition
if (nextState != currentStateA)
{
currentStateA = nextState; // Move in the new state
switch (currentStateA)
{ // Entering the new state
case StateA_Idle:
// Stop motor A
digitalWrite(IN1, LOW);
digitalWrite(IN2, LOW);
analogWrite(EnableMotorA, 0);
break;
case StateA_Open:
// Start motor A
digitalWrite(IN1, LOW);
digitalWrite(IN2, HIGH);
analogWrite(EnableMotorA, 250);
break;
case StateA_Close:
// Start motor A
digitalWrite(IN1, HIGH);
digitalWrite(IN2, LOW);
analogWrite(EnableMotorA, 250);
break;
}
}
}
void stateMachineB(byte readChar)
{
// Check if we need to change state
byte nextState = currentStateB;
switch (currentStateB)
{
case StateB_Idle:
{ // If we received a valid command, start the operation
if(readChar > 0)
{
switch (readChar)
{
case 'C':
nextState = StateB_Open;
break;
case 'D':
nextState = StateB_Close;
break;
default:
// Here you can notify that there was a bad command
break;
}
}
}
break;
case StateB_Open:
if(digitalRead(LimitSwitch4)) // == HIGH is not necessary
nextState = StateB_Idle;
break;
case StateB_Close:
if(digitalRead(LimitSwitch3)) // == HIGH is not necessary
nextState = StateB_Idle;
break;
default:
nextState = StateB_Idle;
break;
}
// If there was a change, switch state and trigger enter condition
if (nextState != currentStateB)
{
currentStateB = nextState; // Move in the new state
switch (currentStateB)
{ // Entering the new state
case StateB_Idle:
// Stop motor B
digitalWrite(IN3, LOW);
digitalWrite(IN4, LOW);
analogWrite(EnableMotorB, 0);
break;
case StateB_Open:
// Start motor B
digitalWrite(IN3, LOW);
digitalWrite(IN4, HIGH);
analogWrite(EnableMotorB, 250);
break;
case StateB_Close:
// Start motor B
digitalWrite(IN3, HIGH);
digitalWrite(IN4, LOW);
analogWrite(EnableMotorB, 250);
break;
}
}
}
This second implementation has two parallel state machines (sharing only the serial input). This will allow you to control both gates at the same time (for instance when the gate is closin you can open the garage)
state E --- status: everything stopped .... enter from state B when limit switch is activated (and from others)
– jsotola Dec 14 '17 at 7:57stop
states ... door open, door closed, door stop at opening, door stop at closing. .... do a web search aboutstate machine
orarduino state machine
– jsotola Dec 14 '17 at 8:06