Having trouble implementing start & stop buttons *SOLVED*

I have a version of this that works perfectly just using an on-off toggle switch. I'm trying to get it to work using a normally open ,momentary push button as a "Start" and a normally open, latching push button as an "Emergency Stop". I'm missing something but I don't know what. The program compiles and uploads but never starts running. Suggestions? Thank you!

//Welder Version1 Rev0
//Includes relay closure to activate welding cycle
//Includes Serial Counting and Auto Shut off when runSize is reached
//Rev1A  pushbutton start and emergency stop  (NOT FUNCTIONING)


const int SolRelayA        = 2;   // Tip Loading Plate
const int SolRelayB        = 3;   // Activate Loading Cylinder
const int SolRelayC        = 4;   // Welder Clamps
const int SolRelayD        = 5;   // Activate Blade Lift Cyinder
const int WeldRelayA        = 6;   // Activate Welder Circuit
const int switchPin        = 12;  //NO Momentary pushbutton to start
const int estopPin        = 11;  //NO Latching pushbutton Estop Button
unsigned long previousMillis;
unsigned long timeDelay = 100;
unsigned long printMillis = 0;
unsigned long currentMillis = 0;
int CycleStage = 0;
int buttonState = 0;
int estopState = 1;
int CycleCount = 0;
int runSize = 7;//number of cycles to run before stopping
int runState = 0; //has run been turned on. 0=Off, 1=O


void setup() {
  Serial.begin(9600);
  digitalWrite (SolRelayA,   HIGH); //Set Relay Pins High
  digitalWrite (SolRelayB,   HIGH);
  digitalWrite (SolRelayC,   HIGH);
  digitalWrite (SolRelayD,   HIGH);
  digitalWrite (WeldRelayA,   HIGH);
  pinMode (SolRelayA,      OUTPUT); //Set Relay Pins as Outputs
  pinMode (SolRelayB,      OUTPUT);
  pinMode (SolRelayC,      OUTPUT);
  pinMode (SolRelayD,      OUTPUT);
  pinMode (WeldRelayA,      OUTPUT);
  pinMode (switchPin, INPUT_PULLUP);
  pinMode (estopPin, INPUT_PULLUP);
}

void loop() {//open loop

  estopState = digitalRead (estopPin);
  buttonState = digitalRead(switchPin);
  currentMillis = millis();//update every loop

  if (CycleCount < runSize) {

    if ((buttonState == 0) && (estopState = 1)) {
      runState == 1;
    }
    if (estopState = 0) {
      runState == 0;
    }

    if (currentMillis - previousMillis > timeDelay) {
      CycleStage++;
      previousMillis = currentMillis;//reset timer
    }
    else if (buttonState == HIGH) {
      previousMillis = currentMillis;
      timeDelay = 0;
    }

    //  troubleshoot();//hatch this line after testing


    if (runState == 1) {
      switch (CycleStage) {
        case 0:
          break;
        case 1: //Tip Loading Plate to Vertical
          digitalWrite (SolRelayA,   LOW);
          timeDelay = 1500;
          break;
        //Insert Tube into Welder
        case 2://if CycleStage==1 kinda of arguement
          digitalWrite (SolRelayB,   LOW);
          //delay (?);
          timeDelay = 1000;//update timeDelay for next step
          break;
        case 3://Activate Welder Clamps
          digitalWrite (SolRelayC,   LOW);
          // delay (?);
          timeDelay = 200;//update timeDelay for next step
          break;
        case 4://Start Weld Cycle
          digitalWrite (WeldRelayA,   LOW);
          // delay (?);
          timeDelay = 300;//update timeDelay for next step
          break;
        case 5://Extend Insertion Cylinder
          digitalWrite (SolRelayB,   HIGH);
          timeDelay = 500;//update timeDelay for next step
          //delay(?);
          break;
        case 6://Tip Loading Plate to Horizontal
          digitalWrite (SolRelayA,   HIGH);
          // delay(?);
          timeDelay = 1000;//update timeDelay for next step
          break;
        case 7://Extend Hopper Blade
          digitalWrite (SolRelayD,   LOW);
          //delay (?);
          timeDelay = 1000;//update timeDelay for next step
          break;
        case 8://Stop Weld Cycle,Retract Hopper Blade
          digitalWrite (SolRelayC,   HIGH);
          digitalWrite (SolRelayD,   HIGH);
          digitalWrite (WeldRelayA,   HIGH);

          //delay (?);
          timeDelay = 1000;//update timeDelay for next step
          break;
        case 9:
          digitalWrite (SolRelayA,   HIGH);
          digitalWrite (SolRelayB,   HIGH);
          digitalWrite (SolRelayC,   HIGH);
          digitalWrite (SolRelayD,   HIGH);
          digitalWrite (WeldRelayA,   HIGH);
          CycleCount = CycleCount + 1;
          Serial.println(CycleCount);
          timeDelay = 100;//9 is now going to loop back to 1
          CycleStage = 1; //go back to step one
          break;

      }//close switch
      //next line is the close to if (buttonState == LOW)
    } else { //button is not low so must be high
      digitalWrite (SolRelayA,   HIGH);
      digitalWrite (SolRelayB,   HIGH);
      digitalWrite (SolRelayC,   HIGH);
      digitalWrite (SolRelayD,   HIGH);
      digitalWrite (WeldRelayA,   HIGH);
    }

    //back in the main loop
  } //close count if
}//close main loop


//void troubleshoot() {

//  if (currentMillis - printMillis > 250L) {
//    Serial.print("buttonstate : ");
//    Serial.print(buttonState);
//    Serial.println(" 0=on 1=off");//new line
//    Serial.print("CycleStage : ");
//    Serial.print(CycleStage);
//    Serial.print(" timer set point : ");
//    Serial.println(timeDelay);//new line
//    long time = currentMillis - previousMillis;
//    time = timeDelay - time;
//    Serial.print("CycleStage : ");
//    Serial.print(" timer left: ");
//    Serial.println(time);
//    Serial.println(" ");
//    printMillis = currentMillis;
//  }
//}
 runState == 1;
 runState == 0;

Oops.

Try replacing:

if ((buttonState == 0) && (estopState = 1)) {
      runState == 1;
    }

with

if ((buttonState == 0) && (estopState == 1)) {
      runState = 1;
    }

EDIT:
and:

if (estopState = 0) {
      runState == 0;
    }

with:

if (estopState == 0) {
      runState = 0;
    }

Thank you both for the input, the little syntax things are tripping me up. I made the changes indicated but I still have a problem. When I run serial monitor it begins with buttonState = 1, estopState = 1, and runState = 0. When I press the start button buttonState = 0 (as long as the button is down) and runState = 1. So all of that seems to be working correctly however the program does not run through the cycles. As I mentioned earlier the program worked correctly with a toggle switch to start and stop the cycles. The previous version had

 if (buttonState == LOW) {
      switch (CycleStage) {
        case 0:
          break;

which I replaced with

 if (runState == 1) {
      switch (CycleStage) {
        case 0:
          break;

So I don't understand why, if it ran with the buttonState LOW previously, why it isn't running with the runState equalling 1 now.

The one other change I just tried is switching

 else if (buttonState == HIGH) {
      previousMillis = currentMillis;
      timeDelay = 0;
    }

to

 else if (runState == 0) {
      previousMillis = currentMillis;
      timeDelay = 0;
    }

But that didn't fix the problem. I'm stumped!

Post. Your. Code.

BillMurphy:
But that didn't fix the problem. I'm stumped!

Post the complete code for your latest version.

...R

The most recent code

//Welder Version1 Rev0
//Includes relay closure to activate welding cycle
//Includes Serial Counting and Auto Shut off when runSize is reached
//Rev1A  pushbutton start and emergency stop  (NOT FUNCTIONING)


const int SolRelayA        = 2;   // Tip Loading Plate
const int SolRelayB        = 3;   // Activate Loading Cylinder
const int SolRelayC        = 4;   // Welder Clamps
const int SolRelayD        = 5;   // Activate Blade Lift Cyinder
const int WeldRelayA        = 6;   // Activate Welder Circuit
const int switchPin        = 12;  //NO Momentary pushbutton to start
const int estopPin        = 11;  //NO Latching pushbutton Estop Button
unsigned long previousMillis;
unsigned long timeDelay = 6000;
unsigned long printMillis = 0;
unsigned long currentMillis = 0;
int CycleStage = 0;
int buttonState = 1;
int estopState = 1;
int CycleCount = 0;
int runSize = 7;//number of cycles to run before stopping
int runState = 0; //has run been turned on. 0=Off, 1=O


void setup() {
  Serial.begin(9600);
  digitalWrite (SolRelayA,   HIGH); //Set Relay Pins High
  digitalWrite (SolRelayB,   HIGH);
  digitalWrite (SolRelayC,   HIGH);
  digitalWrite (SolRelayD,   HIGH);
  digitalWrite (WeldRelayA,   HIGH);
  pinMode (SolRelayA,      OUTPUT); //Set Relay Pins as Outputs
  pinMode (SolRelayB,      OUTPUT);
  pinMode (SolRelayC,      OUTPUT);
  pinMode (SolRelayD,      OUTPUT);
  pinMode (WeldRelayA,      OUTPUT);
  pinMode (switchPin, INPUT_PULLUP);
  pinMode (estopPin, INPUT_PULLUP);
}

void loop() {//open loop


  Serial.println("buttonState");
  Serial.println(buttonState);
  Serial.println("estopState");
  Serial.println(estopState);
  Serial.println("runState");
  Serial.println(runState);

  estopState = digitalRead (estopPin);
  buttonState = digitalRead(switchPin);
  currentMillis = millis();//update every loop

  if (CycleCount < runSize) {

    if ((buttonState == 0) && (estopState == 1)) {
      runState = 1;
    }
    if (estopState ==   0) {
      runState = 0;
    }

    if (currentMillis - previousMillis > timeDelay) {
      CycleStage++;
      previousMillis = currentMillis;//reset timer
    }
    else if (runState == 0) {
      previousMillis = currentMillis;
      timeDelay = 0;
    }



    if (runState == 1) {
      switch (CycleStage) {
        case 0:
          break;
        case 1: //Tip Loading Plate to Vertical
          digitalWrite (SolRelayA,   LOW);
          timeDelay = 1500;
          break;
        //Insert Tube into Welder
        case 2://if CycleStage==1 kinda of arguement
          digitalWrite (SolRelayB,   LOW);
          //delay (?);
          timeDelay = 1000;//update timeDelay for next step
          break;
        case 3://Activate Welder Clamps
          digitalWrite (SolRelayC,   LOW);
          // delay (?);
          timeDelay = 200;//update timeDelay for next step
          break;
        case 4://Start Weld Cycle
          digitalWrite (WeldRelayA,   LOW);
          // delay (?);
          timeDelay = 300;//update timeDelay for next step
          break;
        case 5://Extend Insertion Cylinder
          digitalWrite (SolRelayB,   HIGH);
          timeDelay = 500;//update timeDelay for next step
          //delay(?);
          break;
        case 6://Tip Loading Plate to Horizontal
          digitalWrite (SolRelayA,   HIGH);
          // delay(?);
          timeDelay = 1000;//update timeDelay for next step
          break;
        case 7://Extend Hopper Blade
          digitalWrite (SolRelayD,   LOW);
          //delay (?);
          timeDelay = 1000;//update timeDelay for next step
          break;
        case 8://Stop Weld Cycle,Retract Hopper Blade
          digitalWrite (SolRelayC,   HIGH);
          digitalWrite (SolRelayD,   HIGH);
          digitalWrite (WeldRelayA,   HIGH);

          //delay (?);
          timeDelay = 1000;//update timeDelay for next step
          break;
        case 9:
          digitalWrite (SolRelayA,   HIGH);
          digitalWrite (SolRelayB,   HIGH);
          digitalWrite (SolRelayC,   HIGH);
          digitalWrite (SolRelayD,   HIGH);
          digitalWrite (WeldRelayA,   HIGH);
          CycleCount = CycleCount + 1;
          Serial.println(CycleCount);
          timeDelay = 100;//9 is now going to loop back to 1
          CycleStage = 1; //go back to step one
          break;

      }//close switch
      //next line is the close to if (buttonState == LOW)
    } else { //button is not low so must be high
      digitalWrite (SolRelayA,   HIGH);
      digitalWrite (SolRelayB,   HIGH);
      digitalWrite (SolRelayC,   HIGH);
      digitalWrite (SolRelayD,   HIGH);
      digitalWrite (WeldRelayA,   HIGH);
    }

    //back in the main loop
  } //close count if
}//close main loop

I think the logic would be clearer if this

if ((buttonState == 0) && (estopState == 1)) {
 runState = 1;
}
if (estopState ==   0) {
 runState = 0;
}

was written like this

if (estopState ==   0) {
 runState = 0;
}
else {
 if ((buttonState == 0) {
 runState = 1;
 }
}

It looks like the only way to stop the system is to press the eStop button - is that correct ?

None of this may have a bearing on your problem. However as you did not explain how the latest code works (or doesn't) I can' figure out what the problem might be.

Robin you are correct, the intention is that the eStop would be pressed to stop the system. The problem is that the button portion of the code seems to function correctly in the sense that, when I view serial monitor the runState is at 0 until I press the start button, at which time it switches to 1. And, as expected, it stays at 1 even after the start button is released. So that should trigger the

if (runState == 1) {
switch (CycleStage) {
case 0:

and the machine cycles should begin. However, even though serial monitor is showing me that the runState is at 1 nothing happens. The system does not start cycling, it just sits there just as it does prior to the button being pushed. I know you advocate for building a program incrementally and proving out each area separately. The system works when I run the version of the sketch that uses a toggle on/off switch and the if statement that starts the SwitchCase section of code was looking for (buttonState == Low) And now the push button setup seems to change the runState correctly and I've changed if (buttonState == Low) to if (runState == 1) but, as stated above, nothing happens.

All I can think of is to print runState, CycleStage and put a Serial.println("stageX") in each of the SWITCH sections so you can see what happens - or doesn't.

The concept should work. The problem will be in some detail.

I'm not sure if this does anything useful - and it might be a problem

    else if (runState == 0) {
      previousMillis = currentMillis;
      timeDelay = 0;
    }

It is not really an alternative to the IF that precedes it - why do you need it ?

The way your code is written the code (for example)

        case 1: //Tip Loading Plate to Vertical
          digitalWrite (SolRelayA,   LOW);
          timeDelay = 1500;
          break;

will be called over and over until the time expires. I think it really only needs to run once for every interval and if so it could usefully be put in a function that is called like this

    if (currentMillis - previousMillis > timeDelay) {
      CycleStage++;
      previousMillis = currentMillis;//reset timer
      mySwitchFunction();
    }

and obviously choose a more meaningful name for the function :slight_smile:

...R

Thank you Robin. The main part of the code was suggested to me, I couldn't have done this myself yet, so I'm not sure what the "else if" does. I do know that all I changed in it was buttonState to runState after changing my on/off switch configuration (and I tested both ways with no apparent difference). I think I need to print both codes and look at them side by side to see if I've missed something but I believe if I had you would have picked up on it.

Regarding your suggested method I'm afraid that's over my head right now but I do aspire to learn all the options so I'll get there eventually. :slight_smile:

BillMurphy:
to see if I've missed something but I believe if I had you would have picked up on it.

Bad assumption. I'm not good at that.

if you don't want to try the other changes just add the extra print statements I suggested and report back.

...R

I will most definitely add the print statements and let you know what I find. I've taken the project home for the past three weekends but forced myself to leave it at work this weekend so I couldn't spend the whole weekend working on it. Monday morning I'll go back to troubleshooting.

ok bill try this. looks like you and robin fixed the main problems with the code but the logical order seemed messy.
Ive made a few changes to names as I couldn't follow the code based on the descriptions. I know that the switch was replaced with buttons but for some reason I just couldn't follow the logic with out changing the names to buttons.

Serial prints have been added and the program runs correctly in serial monitor.

@ robin. The base code I wrote for bill a while back was a simple way to get around using delays. As only one step runs at any time the previous case in the switch controlling the steps just writes a new time delay to the millis timer so each step has a crude time control (crude as a few millis is nothing to worry about)

//Welder Version1 Rev0
//Includes relay closure to activate welding cycle
//Includes Serial Counting and Auto Shut off when runSize is reached
//Rev1A  pushbutton start and emergency stop  (NOT FUNCTIONING)


const int SolRelayA        = 2;   // Tip Loading Plate
const int SolRelayB        = 3;   // Activate Loading Cylinder
const int SolRelayC        = 4;   // Welder Clamps
const int SolRelayD        = 5;   // Activate Blade Lift Cyinder
const int WeldRelayA        = 6;   // Activate Welder Circuit
const int pushButtonStart        = 12;  //NO Momentary pushbutton to start
const int pushButtonStop        = 11;  //NO Latching pushbutton Estop Button
unsigned long previousMillis;
unsigned long timeDelay = 6000;
unsigned long printMillis = 0;
unsigned long currentMillis = 0;
int CycleStage = 0;
int startButton = 1;
int estopPushButton = 1;
int CycleCount = 0;
int runSize = 7;//number of cycles to run before stopping
int runState = 0; //has run been turned on. 0=Off, 1=O


void setup() {
  Serial.begin(9600);
  digitalWrite (SolRelayA,   HIGH); //Set Relay Pins High
  digitalWrite (SolRelayB,   HIGH);
  digitalWrite (SolRelayC,   HIGH);
  digitalWrite (SolRelayD,   HIGH);
  digitalWrite (WeldRelayA,   HIGH);
  pinMode (SolRelayA,      OUTPUT); //Set Relay Pins as Outputs
  pinMode (SolRelayB,      OUTPUT);
  pinMode (SolRelayC,      OUTPUT);
  pinMode (SolRelayD,      OUTPUT);
  pinMode (WeldRelayA,      OUTPUT);
  pinMode (pushButtonStart, INPUT_PULLUP);
  pinMode (pushButtonStop, INPUT_PULLUP);
}

void loop() {//open loop

  //if you // the next line then serial print will not be called
  //left in it will call the serial print lines used for diagnostics
  serialHelper();


  estopPushButton = digitalRead (pushButtonStop);
  startButton = digitalRead(pushButtonStart);
  currentMillis = millis();//update every loop



  if (estopPushButton == 0) {
    runState = 0;
  } else if ((startButton == 0) && (estopPushButton == 1)) {
    runState = 1;
  }

  if (runState == 1) {
    if (currentMillis - previousMillis > timeDelay) {
      CycleStage++;
      previousMillis = currentMillis;//reset timer
    }
    if (CycleCount >= runSize) {
      CycleStage = 0;
    }

    switch (CycleStage) {
      case 0:
        break;
      case 1: //Tip Loading Plate to Vertical
        digitalWrite (SolRelayA,   LOW);
        timeDelay = 1500;
        break;
      //Insert Tube into Welder
      case 2://if CycleStage==1 kinda of arguement
        digitalWrite (SolRelayB,   LOW);
        //delay (?);
        timeDelay = 1000;//update timeDelay for next step
        break;
      case 3://Activate Welder Clamps
        digitalWrite (SolRelayC,   LOW);
        // delay (?);
        timeDelay = 200;//update timeDelay for next step
        break;
      case 4://Start Weld Cycle
        digitalWrite (WeldRelayA,   LOW);
        // delay (?);
        timeDelay = 300;//update timeDelay for next step
        break;
      case 5://Extend Insertion Cylinder
        digitalWrite (SolRelayB,   HIGH);
        timeDelay = 500;//update timeDelay for next step
        //delay(?);
        break;
      case 6://Tip Loading Plate to Horizontal
        digitalWrite (SolRelayA,   HIGH);
        // delay(?);
        timeDelay = 1000;//update timeDelay for next step
        break;
      case 7://Extend Hopper Blade
        digitalWrite (SolRelayD,   LOW);
        //delay (?);
        timeDelay = 1000;//update timeDelay for next step
        break;
      case 8://Stop Weld Cycle,Retract Hopper Blade
        digitalWrite (SolRelayC,   HIGH);
        digitalWrite (SolRelayD,   HIGH);
        digitalWrite (WeldRelayA,   HIGH);

        //delay (?);
        timeDelay = 1000;//update timeDelay for next step
        break;
      case 9:
        digitalWrite (SolRelayA,   HIGH);
        digitalWrite (SolRelayB,   HIGH);
        digitalWrite (SolRelayC,   HIGH);
        digitalWrite (SolRelayD,   HIGH);
        digitalWrite (WeldRelayA,   HIGH);
        CycleCount = CycleCount + 1;
        timeDelay = 100;//9 is now going to loop back to 1
        CycleStage = 1; //go back to step one
        break;

    }//close switch

  } else { //runState == 0
    digitalWrite (SolRelayA,   HIGH);
    digitalWrite (SolRelayB,   HIGH);
    digitalWrite (SolRelayC,   HIGH);
    digitalWrite (SolRelayD,   HIGH);
    digitalWrite (WeldRelayA,   HIGH);
    previousMillis = currentMillis;//reset timer
  }
  //back in the main loop
}//close main loop

void serialHelper() {
  //timer is used to slow the prints to make reading easier on the eyes
  if (currentMillis - printMillis > 600) {
    Serial.print("startButton ");
    Serial.println(startButton);
    Serial.print("estopPushButton ");
    Serial.println(estopPushButton);
    Serial.print("runState ");
    Serial.println(runState);
    Serial.print("CycleStage ");
    Serial.println(CycleStage);
    Serial.print("delay ");
    Serial.println(timeDelay);
    Serial.print("CycleCount ");
    Serial.println(CycleCount);
    Serial.print("runSize ");
    Serial.println(runSize);
    Serial.println(" ");


    printMillis = currentMillis;//reset timer
  }
}

as always if you don't understand something or why it was done this way just post the section of code and someone will help you.

I didn't add this but I would consider using

if (CycleCount >= runSize) {
      CycleStage = 0;
      runState = 0;
    }

this way the welder is not only held from running any more parts but also turns the machine to off.

Thank you SO much! I'm tempted to run into work right now to try this but I think my wife would kill me! lol I'll test the first thing tomorrow and report back.

One question....serialHelper is a function, correct? And am I correct that you are using that, instead of putting the serial.print commands in the middle of the code like I did, just to keep the main code cleaner ?

BillMurphy:
Thank you SO much! I'm tempted to run into work right now to try this but I think my wife would kill me! lol I'll test the first thing tomorrow and report back.

One question....serialHelper is a function, correct? And am I correct that you are using that, instead of putting the serial.print commands in the middle of the code like I did, just to keep the main code cleaner ?

Its easier to disable a function then it is to find and disable each print. none of the prints are require to run in any special order so it was easier to put them in a function out of the way. I would still add serial prints to certain parts of the code when testing.

gpop1:
I would still add serial prints to certain parts of the code when testing.

I'm assuming to make sure that particular area of code was being accessed and run by the program?

Okay...it's been an extremely frustrating day so far! Gpop1 your code appears to work great but I seem to be having weird hardware problems since implementing it. This makes no sense to me but the stop switch seems to be "killing" pins. When I first hooked everything up this morning and loaded the new code it ran fine for a while then I couldn't get it to run reliably. It would do nothing or trip a few air cylinders then stop. Eventually I moved the stop button to pin 10 (instead of 11), changed the code, and everything functioned normally again....for a while. Then it went back to having the same issues as it did on pin 11. Now I'm on pin 9 and the cycle has repeated. If I disconnect the stop button lead from the pin and press start the program, which is currently set to cycle 25 times, runs reliably. If I plug anything into the stop button pin, even a jumper with nothing on the other end, it prevents the system from cycling. I'm considering putting in a new uno and trying from scratch. I admit when I was testing this morning I wasn't diligent about powering down before inserting or removing jumpers so possibly I've damaged the board? But I have been careful since swapping pins and each one seems to work for a while then stop. Does this make sense to anyone?

A little more info.....this is turning into a hardware problem rather than programming so if you think I should start a new thread please let me know. Here are the scenarios I've tested after replacing the Uno:

With only the processor powered by the usb (connected to my laptop) and both the start and stop buttons hooked up, and no 12 volt to the relays, everything appears to function correctly. The start button will start the system and the leds on the relays confirm the correct sequencing. Pressing the stop button will stop the system. All is right with the world except, of course, the solenoids and air cylinders aren't doing anything.

With the processor and the relays powered by my 12 volt power supply and the stop button disconnected from the pin (currently pin 9) the start button starts the system and the relays, solenoids, and air cylinders all function correctly. The system will run the programmed number of cycles (currently 25) and then stop.

With the processor and the relays powered by my 12 volt power supply and the stop button connected to the pin (currently pin 9) the start button starts the system then random things happen. Typically it runs part of a cycle, firing a couple of cylinders, then stops. Pressing reset then start yields similar, but not necessarily exactly the same, results. It will run anywhere for a partial to full cycle then stop. I've confirmed the stop switch is not faulty and have even disconnect the other side of it from ground and get the same results. Going a step further simply plugging a jumper into pin 9, with nothing connected to or touching the other end, causes the same results.

And I have the same results as the last paragraph if I power the processor from the laptop and the relays from the 12 volt supply.

In case any of this matter the power supply is supplying 12.27 volts and the Uno is connected to, in addition to the the start and stop buttons, 5 channels of an 8 channel relay board.