Need help with Millis controlling cycles

I'm working on an automation program that will cycle 4 air cylinders with some of the cycles overlapping. I've managed to get it to run the proper sequence and timing using delays but I would like to convert to the "right" way by using millis timing the cycles. I believe my actual problem is with the connection between the timing and the command to increase the cycle count. I'm only implementing this on the first cycle change right now, the rest of it still uses delays, and will add it between each cycle once I get it right. What is happening is that when the switch is turned "on" (closed) both cycle 1 and cycle 2 start simultaneously, instead of cycle 2 starting after the six second delay. Any help would be appreciated! An overview of the project is at New to Arduino, is this feasible? - Project Guidance - Arduino Forum

// set pin configuration
const int SolRelayA        = 1;   // Extend Tipping Cylinder
const int SolRelayB        = 2;   // Extend Loading Cylinder
const int SolRelayC        = 3;   // Start Welding Cycle
const int SolRelayD        = 4;   // Extend Blade Lift Cyinder
const int switchPin        = 12;
unsigned long CycleStart1;
unsigned long CycleTime1;
unsigned long CycleStart2;
unsigned long CycleTime2;
unsigned long CycleStart3;
unsigned long CycleTime3;
unsigned long CycleStart4;
unsigned long CycleTime4;
int CycleStage              = 0;
int buttonState              = 1;


void setup() {
  // Set the pins and relay states
  digitalWrite (SolRelayA,   HIGH); //Set Relay Pins High
  digitalWrite (SolRelayB,   HIGH);
  digitalWrite (SolRelayC,   HIGH);
  digitalWrite (SolRelayD,   HIGH);
  pinMode (SolRelayA,      OUTPUT); //Set Relay Pins as Outputs
  pinMode (SolRelayB,      OUTPUT);
  pinMode (SolRelayC,      OUTPUT);
  pinMode (SolRelayD,      OUTPUT);
  pinMode (switchPin, INPUT_PULLUP);

}
void loop()
{
  // put your main code here, to run repeatedly:
  buttonState = digitalRead(switchPin);

  if (CycleStage == 0) {
    if (buttonState == LOW) {
      digitalWrite (SolRelayA,   LOW);
      CycleStart1 = millis();
      if (CycleTime1 - CycleStart1 >= 6000); {
      CycleStage = CycleStage + 1;

      if (CycleStage == 1) {
        digitalWrite (SolRelayB,   LOW);
        delay (5000);
        digitalWrite (SolRelayC,   LOW);
        delay (500);
        digitalWrite (SolRelayB,   HIGH);
        delay(500);
        digitalWrite (SolRelayA,   HIGH);
        delay(4000);
        digitalWrite (SolRelayC,   HIGH);
        digitalWrite (SolRelayD,   LOW);
        delay (1000);
        digitalWrite (SolRelayD,   HIGH);
      }
      CycleStage = 0;
    }
    }
    else {
      digitalWrite (SolRelayA,   HIGH);
      digitalWrite (SolRelayB,   HIGH);
      digitalWrite (SolRelayC,   HIGH);
      digitalWrite (SolRelayD,   HIGH);
    }

  }
}

you seemed to have missed the basic concept of the {} brackets

if (question){//open switch
answer is true ....do this
}//close switch
else{//open switch
//answer is false...do this
}//close switch

this line starts the timer it needs to be blocked once started or it will just reset on the next loop around
code says while button state is low keep resetting the timer

 if (buttonState == LOW) {
      digitalWrite (SolRelayA,   LOW);
      CycleStart1 = millis();

next line will not work as required as you have a ; after the )

if (CycleTime1 - CycleStart1 >= 6000); {
      CycleStage = CycleStage + 1;

You are absolutely correct that I'm lost on the syntax aspect. I'm looking at codes that do bits and pieces of what I'm trying to accomplish and trying to piece them together but having trouble following some of the logic. The code I had ran, although not correctly. When I try to make the corrections suggested (admittedly possibly incorrectly) I'm getting multiple errors when I verify the code. Seems I'm getting farther away, not closer.

BillMurphy:
You are absolutely correct that I'm lost on the syntax aspect. I'm looking at codes that do bits and pieces of what I'm trying to accomplish and trying to piece them together but having trouble following some of the logic. The code I had ran, although not correctly. When I try to make the corrections suggested (admittedly possibly incorrectly) I'm getting multiple errors when I verify the code. Seems I'm getting farther away, not closer.

nope just means you are learning.

when you get errors always scroll up to the first one.

the error includes a number that is the line reference. either look at the bottom right corner of the screen which will tell you the mouse position or turn on line number in the program to assist you in finding the line its complaining about.

Haha. Tonight it means I have a headache from banging my head against the table in frustration! No progress to report. I took the switch code out to try and simplify things for now but still get the a & b relays turing on at the same time and then they shut off 5 sec. (b) and 5.5 sec (a) later. So somehow I'm still missing the concept of timing with millis and moving to the next cycle. ARGH!

PS...thanks for the tip on the line counter. I hadn't seen it hiding down there (although it's on the left for me)

I really didn't want to give you a working code but I couldn't think of anyway of showing you how things work. I hope the code doesn't do everything you wanted then at least im showing you how rather than doing the programming for you. read the code and you will see I changed your pin numbers

if theres anything you don't understand post back

//never use pin 0 or 1 unless you have no other option
//your usb is kinda using the pins

const int SolRelayA        = 2;   // changed this to diffrent pin
const int SolRelayB        = 3;   // Extend Loading Cylinder
const int SolRelayC        = 4;   // Start Welding Cycle
const int SolRelayD        = 5;   // Extend Blade Lift Cyinder
const int switchPin        = 12;
unsigned long previousMillis;
unsigned long timeDelay = 0;

int CycleStage = 0;
int buttonState = 0;


void setup() {
  Serial.begin(9600);//this allows printing to the plc to see
  //whats really happening in the code
  //also the reason not to use pin0 and pin1

  //i would put pinmode first but compiler seems happy to do it this way

  digitalWrite (SolRelayA,   HIGH); //Set Relay Pins High
  digitalWrite (SolRelayB,   HIGH);
  digitalWrite (SolRelayC,   HIGH);
  digitalWrite (SolRelayD,   HIGH);
  pinMode (SolRelayA,      OUTPUT); //Set Relay Pins as Outputs
  pinMode (SolRelayB,      OUTPUT);
  pinMode (SolRelayC,      OUTPUT);
  pinMode (SolRelayD,      OUTPUT);
  pinMode (switchPin, INPUT_PULLUP);
}

void loop() {//open loop

  unsigned long currentMillis = millis();//update every loop

  // what i think you are trying to program
  //when i press the button run 7 steps in sequence. add timing
  //between the steps, first step is instant


  //next line says have you pressed the button and is the timer done
  //first press has no delay. time delay was set to 0 on start up
  if ((buttonState == LOW) && (currentMillis - previousMillis > timeDelay)) {//open if
    //if true then change CycleStage and reset timer
    CycleStage++;//++means add one same as CycleStage=CycleStage+1
    previousMillis = currentMillis;//reset timer
    // prevmillis=currentmillis really means reset timer
  } //close if
  //else keeps the next if linked to the first if
  else if (buttonState == HIGH) {//open else if
    //what to do if some one lets go off button
    previousMillis = currentMillis;//reset timer
    timeDelay = 0; //reset to default for step one which is no timer
    CycleStage = 7;//im guessing go to last step to stop everything
  }//close else if

  // back in the main loop


  //7 is the shut down step
  if ( CycleStage >= 7) {//open if
    //CycleStage counts higher than 7 stop it at 7
    CycleStage = 7;
  }//close if
  //7 is the shut down step


  //back in the main loop

  switch (CycleStage) {//look up switch its just a fancy if statement
    //if CycleStage==? kinda of arguement its a better way of writing it

    case 0://if CycleStage==0 kinda of arguement
      digitalWrite (SolRelayA,   LOW);
      timeDelay = 6000;//now you need to understand that i only wrote one timer
      //the timer is being used 7 times so after it done it job i have
      //to tell it what the next job is
      //first job was timedelay==0 as i didnt want it to delay
      //next step i want it to wait for 6 seconds
      //its not perfect timing but this timing doesnt need it

      break;//this allows the processor to get out of the switch after
    //doing what ever is in the case that way it doesnt have to look at
    //the rest of the code in the cases


    case 1://if CycleStage==1 kinda of arguement
      digitalWrite (SolRelayB,   LOW);
      //delay (5000);
      timeDelay = 5000;//update timeDelay for next step
      break;
    case 2:
      digitalWrite (SolRelayC,   LOW);
      // delay (500);
      timeDelay = 500;//update timeDelay for next step
      break;
    case 3:
      digitalWrite (SolRelayB,   HIGH);
      timeDelay = 500;//update timeDelay for next step
      //delay(500);
      break;
    case 4:
      digitalWrite (SolRelayA,   HIGH);
      // delay(4000);
      timeDelay = 4000;//update timeDelay for next step
      break;
    case 5:
      digitalWrite (SolRelayC,   HIGH);
      digitalWrite (SolRelayD,   LOW);
      //delay (1000);
      timeDelay = 1000;//update timeDelay for next step
      break;
    case 6:
      digitalWrite (SolRelayD,   HIGH);
      timeDelay = 6000;//update timeDelay for next step
      break;
    case 7:
      digitalWrite (SolRelayA,   HIGH);
      digitalWrite (SolRelayB,   HIGH);
      digitalWrite (SolRelayC,   HIGH);
      digitalWrite (SolRelayD,   HIGH);
      timeDelay = 0;//there are no further steps so the op has
      //to release the button
      //remember further up we are saying if step 7 stay at step 7
      //next step would be to start the sequence so no time delay
      break;

  }//close switch

  //back in the main loop

}//close main loop

Have a look at planning and implementing a program and especially how it uses functions to separate the action from the logic. By using small single-purpose functions you can test the code in pieces. When a function works properly you can treat it like a black box and just call on it when needed.

For example you could create a global variable to hold the duration for the relay to be on and use this function to start it and stop it

The code might be like this

// globals
unsigned long durationAAMillis;
boolean relayAAstart = false;
boolean relayAAOn = false;

void loop() {
  if (xyz) {  // whatever decision starts the relay
     durationAAMillis = 3000;
     relayAAstart = true;
  }
  relayAA(); // note that this is called with every iteration of loop()
}

void relayAA() {
   static unsigned long startAAMillis;

   if (relayAAstart == true) { // assumes relayAAOn is a global variable
      relayAAstart = false;
      startAAMillis = millis();
      digitalWrite(relayAApin, HIGH);
      relayAAOn = true;
   }
   else {
      if (millis() - startAAMillis >=  durationAAMillis) {
         digitalWrite(relayAApin, LOW);
         relayAAOn = false;
      }
   }
}

Not tested, and could probably be neater

If you need other devices to trigger at times related to the progress of this timer you could make startAAmillis a global variable.

...R

const int SolRelayA        = 1;   // Extend Tipping Cylinder
const int SolRelayB        = 2;   // Extend Loading Cylinder
const int SolRelayC        = 3;   // Start Welding Cycle
const int SolRelayD        = 4;   // Extend Blade Lift Cyinder

If you used names that made sense, the comments would not be necessary AND one would not need a cheat sheet to know which name to use later.

First a sincere Thank You for the input! I know I can get this figured out eventually but it's been frustrating. That's what I get for jumping right into a complicated project with zero experience. I've managed to teach myself both html coding and cnc (g,m code) programming by looking at examples and seeing what they do then "reverse engineering" by trial and error until I understood how to do it myself. That is a little more daunting with this programming, in part because there seems to typically be several approaches to accomplishing the same objective. As I mentioned in a previous post I can make this do exactly what I want it to (as far as sequencing the air cylinders) using delays. My only concern with that is that turning the switch to "off" would have no effect until the entire cycle was completed. While in some sense that it good it would be problematic if an emergency stop was required which is why I'm where I'm at with the cycle timing.

Paul, I realize this is subjective but the names (SolRelayA, SolRelayB, etc) make perfect sense to me. for example SolRelayA is the relay which controls the solenoid valves to open and close the first air cylinder. The comments are for showing the code to others. :slight_smile:

Robin, I've been going over the planning and implementation post for a couple of days. It's helped but I just haven't reach that "lightbulb moment" where I can translate the examples to my project Right now global variables is "a bridge too far" as my brain is already turning to mush. lol I can certainly see their usefulness but figure I should be able to write a program that opens and closes 4 air cylinders without it getting too complicated. Or at least I thought that before yesterday! :wink:

Gpop1, thank you for the assistance. Rest assured that even if your code does everything I need it's not going to stop my quest to understand the why and how. Discovering the Arduino has opened up so many possibilities for projects similar to this. I'm just getting started! FYI the reason that the pinmode is set after the pins are set high is because the relays are activated by a low signal. If during power on a signal went low it would extend an air cylinder when it wasn't supposed to. I believe it was PaulS who suggested that fix to me.

If you require an emergency stop to protect human life and limb, it should operate independently from the microprocessor (for example, by cutting power to the actuators or dumping the air).

Gpop1 I uploaded and ran the sketch. The timing seems perfect but there is an issue with the start button. I'm trying to figure it out on my own but so far I'm stumped. Basically the button has no effect and the sketch runs one sequence on loading and then stops, In order to get it to run I have to press the reset button and then it runs one more sequence and stops. My goal is the following.....turning switch on (latching) completes a circuit and as long as that circuit is intact the program will continue to run (loop). Turning that switch "Off" opens the circuit, stopping the program. My current switch set up, which worked with my sketch that had delays in it, completes a circuit between pin 12 and ground. If I understand this correctly by using the pullup on pin 12 it is normally high and connecting it to ground brings it low. And the program should run when pin 12 is low. Now I just did a comparison and saw that in my "delay example" I had used this...buttonState = digitalRead(switchPin);....(possibly incorrectly) to set the buttonState to Low right at the start of the loop. I believe that would keep the buttonState in the run (low) setting until the start switch was turned off. Then the....buttonState = digitalRead(switchPin);..... would read the pin high, set the buttonState high, and the sequence would stop. Is that an acceptable procedure? I'm going to try to put it into your code to see what happens.

aarg.......you are absolutely correct and I will be adding that feature but expect it will be done outside of the program just as you suggested so I haven't brought it up here. In this application it would be more to protect against bent parts and machine damage than life and limb but important none the less. I realize that by doing this I can run my original program with the delays but I'm sure I will have other applications in the future where delays aren't desirable thus my quest to "do it right". :slight_smile:

BillMurphy:
Gpop1 I uploaded and ran the sketch. The timing seems perfect but there is an issue with the start button. I'm trying to figure it out on my own but so far I'm stumped. Basically the button has no effect and the sketch runs one sequence on loading and then stops, In order to get it to run I have to press the reset button and then it runs one more sequence and stops. My goal is the following.....turning switch on (latching) completes a circuit and as long as that circuit is intact the program will continue to run (loop). Turning that switch "Off" opens the circuit, stopping the program. My current switch set up, which worked with my sketch that had delays in it, completes a circuit between pin 12 and ground. If I understand this correctly by using the pullup on pin 12 it is normally high and connecting it to ground brings it low. And the program should run when pin 12 is low. Now I just did a comparison and saw that in my "delay example" I had used this...buttonState = digitalRead(switchPin);....(possibly incorrectly) to set the buttonState to Low right at the start of the loop. I believe that would keep the buttonState in the run (low) setting until the start switch was turned off. Then the....buttonState = digitalRead(switchPin);..... would read the pin high, set the buttonState high, and the sequence would stop. Is that an acceptable procedure? I'm going to try to put it into your code to see what happens.

aarg.......you are absolutely correct and I will be adding that feature but expect it will be done outside of the program just as you suggested so I haven't brought it up here. In this application it would be more to protect against bent parts and machine damage than life and limb but important none the less. I realize that by doing this I can run my original program with the delays but I'm sure I will have other applications in the future where delays aren't desirable thus my quest to "do it right". :slight_smile:

the code I wrote is semi auto as in if you keep your finger on the button it follows the steps. If you remove your finger then it goes safe (all relays off). This is not a perfect situation as there should be a reset all cylinders to start position just in case someone decide to stop during a cycle.

if you put your finger back on the button then it should start again at step one. (I haven't tested this but adding some Serial.Println should show you whats really happening)

now I did not see latching or looping in the sketch you posted so I didn't program that way.

//7 is the shut down step
if ( CycleStage >= 7) {//open if
//CycleStage counts higher than 7 stop it at 7
CycleStage = 7;
}//close if
//7 is the shut down step

this section of the code is whats blocking the program from looping

as for latching you will have to take the button input and turn that into a flag (1 or 0). The flag will then replace the places in the program that the button state is referenced so (buttonState == LOW) becomes
if (runflag==1).

plan this out on paper as you need a good idea of what you want before you try to code it.

ex:
if I press the button run steps and loop?
if I press the button again....?
if the program is stopped how do I plan to deal with the cylinders?

Gpop I reloaded and ran your code again with the same result, it runs immediately upon loading, it ignores my button pushes, but will run again when I press reset.

I'm sorry for not being clear on the cycling. The purpose of this is to move parts from a hopper onto a loading plate, move the plate into position, insert the part into the welder, then trip the air valve on the welder to run its cycle. When the weld cycle is complete the part drops out of the welder and the whole cycle repeats. In my code the part coming out of the hopper is actually the last step (solRelayD). So you manually load the first part onto the plate then start the program. "A" tips the part from horizontal to vertical, "B" pushes the part between the welder grippers, "C" starts the weld cycle and the part is physically held by the welder grippers so "B" can then retract followed by "A" going back to horizontal. When the weld cycle "C" ends "D" extends and retracts to push a new part out of the hopper and onto the loading plate. Then the cycle would repeat.

I think I'm physically handling the on off differently that what I'm seeing as typical and that may be causing an understanding issue. I don't want to get (at this point) into using a momentary switch to toggle between on and off. Perhaps this isn't convention but I'm simple using pin12 pulled up to high by the pullup resistor and wired to ground with a latching switch. When pin12 is high the program is "off" and when I turn the switch on (complete the circuit to ground) it reads low and the program runs. It's simple and it seems to work without worrying about debouncing.

My current impasse is my program, using delays, works with my switch set up. Your program, which is using the better timing method, doesn't want to work with the switch for some reason. I've tried everything I can think of to integrate the two but I'm running out of ideas.

I should also mention that at some point I will probably want to add in cycle switches that confirm the physical position of the loader before initiating the next step rather than just timing them although that is a long term project that I don't want to burden my poor brain with at the moment. Baby steps! :slight_smile:

ok lets think about why the code doesn't work.

  if ((buttonState == LOW) && (currentMillis - previousMillis > timeDelay)) {//open if
    //if true then change CycleStage and reset timer
    CycleStage++;//++means add one same as CycleStage=CycleStage+1
    previousMillis = currentMillis;//reset timer
    // prevmillis=currentmillis really means reset timer
  } //close if
  //else keeps the next if linked to the first if
  else if (buttonState == HIGH) {//open else if
    //what to do if some one lets go off button
    previousMillis = currentMillis;//reset timer
    timeDelay = 0; //reset to default for step one which is no timer
    CycleStage = 7;//im guessing go to last step to stop everything
  }//close else if

  // back in the main loop

notice the lines above. Everything is wrapped in a if or else if

both are looking at buttonState. The first part says if button ==LOW do this when timer says its done

if that fails check to see if the buttonState is HIGH. If it is then do this

(really should change buttonState to SwitchState as most people think of button as a pushbutton and a switch as maintained)

ok so does anything make the steps run when the button is high.....nope
notice we are returning to main loop

  //back in the main loop

  switch (CycleStage) {//look up switch its just a fancy if statement
    //if CycleStage==? kinda of arguement its a better way of writing it

    case 0://if CycleStage==0 kinda of arguement
      digitalWrite (SolRelayA,   LOW);
      timeDelay = 6000;//now you need to understand that i only wrote one timer
      //the timer is being used 7 times so after it done it job i have
      //to tell it what the next job is
      //first job was timedelay==0 as i didnt want it to delay
      //next step i want it to wait for 6 seconds
      //its not perfect timing but this timing doesnt need it

      break;//this allows the processor to get out of the switch after
    //doing what ever is in the case that way it doesnt have to look at
    //the rest of the code in the cases

ok next section. before this section we are in the main loop.
ok now we get to the switch statement.
do we ask if we should run the switch?. nope we are in main loop its going to hit the switch and as the cyclestage is a number between 0 and 7 its going to run the switch.

Well that not whats required so we need to block the switch from running when ever its read by the main loop.

so what should we use as a block. Maybe we should block unless the button is low. But if we do that then the cylinder relay will stay on. So you have to decided how to deal with this

posted code removes the step 7 block and blocks the switch from main code based on if the button is low. Also added extra lines to shut down the cyclinders if the button is high

//never use pin 0 or 1 unless you have no other option
//your usb is kinda using the pins

const int SolRelayA        = 2;   // changed this to diffrent pin
const int SolRelayB        = 3;   // Extend Loading Cylinder
const int SolRelayC        = 4;   // Start Welding Cycle
const int SolRelayD        = 5;   // Extend Blade Lift Cyinder
const int switchPin        = 12;
unsigned long previousMillis;
unsigned long timeDelay = 0;

int CycleStage = 0;
int buttonState = 0;


void setup() {
  Serial.begin(9600);//this allows printing to the plc to see
  //whats really happening in the code
  //also the reason not to use pin0 and pin1

  //i would put pinmode first but compiler seems happy to do it this way

  digitalWrite (SolRelayA,   HIGH); //Set Relay Pins High
  digitalWrite (SolRelayB,   HIGH);
  digitalWrite (SolRelayC,   HIGH);
  digitalWrite (SolRelayD,   HIGH);
  pinMode (SolRelayA,      OUTPUT); //Set Relay Pins as Outputs
  pinMode (SolRelayB,      OUTPUT);
  pinMode (SolRelayC,      OUTPUT);
  pinMode (SolRelayD,      OUTPUT);
  pinMode (switchPin, INPUT_PULLUP);
}

void loop() {//open loop

  unsigned long currentMillis = millis();//update every loop

  // what i think you are trying to program
  //when i press the button run 7 steps in sequence. add timing
  //between the steps, first step is instant


  //next line says have you pressed the button and is the timer done
  //first press has no delay. time delay was set to 0 on start up
  if ((buttonState == LOW) && (currentMillis - previousMillis > timeDelay)) {//open if
    //if true then change CycleStage and reset timer
    CycleStage++;//++means add one same as CycleStage=CycleStage+1
    previousMillis = currentMillis;//reset timer
    // prevmillis=currentmillis really means reset timer
  } //close if
  //else keeps the next if linked to the first if
  else if (buttonState == HIGH) {//open else if
    //what to do if some one lets go off button
    previousMillis = currentMillis;//reset timer
    timeDelay = 0; //reset to default for step one which is no timer
  }//close else if

  // back in the main loop

  if (buttonState == LOW) { //block switch below from main loop
    switch (CycleStage) {
      case 0:
        digitalWrite (SolRelayA,   LOW);
        timeDelay = 6000;
        break;
      case 1://if CycleStage==1 kinda of arguement
        digitalWrite (SolRelayB,   LOW);
        //delay (5000);
        timeDelay = 5000;//update timeDelay for next step
        break;
      case 2:
        digitalWrite (SolRelayC,   LOW);
        // delay (500);
        timeDelay = 500;//update timeDelay for next step
        break;
      case 3:
        digitalWrite (SolRelayB,   HIGH);
        timeDelay = 500;//update timeDelay for next step
        //delay(500);
        break;
      case 4:
        digitalWrite (SolRelayA,   HIGH);
        // delay(4000);
        timeDelay = 4000;//update timeDelay for next step
        break;
      case 5:
        digitalWrite (SolRelayC,   HIGH);
        digitalWrite (SolRelayD,   LOW);
        //delay (1000);
        timeDelay = 1000;//update timeDelay for next step
        break;
      case 6:
        digitalWrite (SolRelayD,   HIGH);
        timeDelay = 6000;//update timeDelay for next step
        break;
      case 7:
        digitalWrite (SolRelayA,   HIGH);
        digitalWrite (SolRelayB,   HIGH);
        digitalWrite (SolRelayC,   HIGH);
        digitalWrite (SolRelayD,   HIGH);
        timeDelay = 6000;//7 is now going to loop back to 0
        CycleStage = 0; //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);
  }

  //back in the main loop

}//close main loop

Okay Gpop, just so you don't think I'm sitting here waiting for you to do the whole thing without even trying myself :wink: I have a few specific questions about your code that, if answered might help me understand better. I may use the wrong terminology but I hope you'll understand what I'm asking. Here goes.....

In my program I "think" what is happening is that my switch pin voltage is being read and the buttonstate is being set, and then the program being told to run by this section of code:

  // put your main code here, to run repeatedly:
  buttonState = digitalRead(switchPin);

  if (CycleStage == 0) {
    if (buttonState == LOW) {
      digitalWrite (SolRelayA,   LOW);

In the very top section of my code (definitions?) I set the int buttonState to 1 which I
m assuming is high (1 on, 0 off). Then the code reads pin 12 as low (if switch is closed) and that sets buttonState LOW and the program runs. First, are all my assumptions correct?

Next when I look at that area of your code I see that the int buttonState is set to 0 (assuming again that 0=LOW?) and also that your code has an "if buttonState == LOW" command to start the program but I don't see any connection between the buttonState and the switchPin. So I'm guessing that is why the program runs one time after a reset but closing the switch has no effect?

Also, to get the program to loop can we somehow tell it when CycleStage >= 7 to simple set the CycleStage = 0. Or is it not that simple??

PS...I was writing this as you were replying

"If during power on a signal went low it would extend an air cylinder when it wasn't supposed to. I believe it was PaulS who suggested that fix to me."

all the other posters are better programmers than me. I honestly didn't know that you could assign a pin high before you assigned it as a output. which is why I made the comment

//i would put pinmode first but compiler seems happy to do it this way

now I do think theres away to write pinmode as a output set high so hopefully someone will posted the correct way to do it.

There were a couple of solutions posted to that issue in my concept thread but this, by far, was the simplest and it works. Okay, so the latest version of your program loops but still ignores the switch position (it just keeps going with the switch on or off) and there is a 4 to 5 second delay between the end of the loop and beginning. (between relayD cycling and relayA activating). I'm going to investigate that but I'm still wondering about the difference in our two codes regarding the switchPin and if that's why I can't control your code starting and stopping. All your help is sincerely appreciated.

EDIT: Saw the code causing the delay between loops and was able to shorten it. If I can get the switch to work we have a winner!

lol looks like we posting at the same time.

your button works fine read the notes in post 13 and you will see that there was a code mistake and a explanation based on what the mistake was.

When testing you need to learn how to use Serial.print.

test this program then click tools, serial monitor. its the same program just added some thing to help you troubleshoot.

//never use pin 0 or 1 unless you have no other option
//your usb is kinda using the pins

const int SolRelayA        = 2;   // changed this to diffrent pin
const int SolRelayB        = 3;   // Extend Loading Cylinder
const int SolRelayC        = 4;   // Start Welding Cycle
const int SolRelayD        = 5;   // Extend Blade Lift Cyinder
const int switchPin        = 12;
unsigned long previousMillis;
unsigned long timeDelay = 0;

int CycleStage = 0;
int buttonState = 0;


void setup() {
  Serial.begin(9600);//this allows printing to the plc to see
  //whats really happening in the code
  //also the reason not to use pin0 and pin1

  //i would put pinmode first but compiler seems happy to do it this way

  digitalWrite (SolRelayA,   HIGH); //Set Relay Pins High
  digitalWrite (SolRelayB,   HIGH);
  digitalWrite (SolRelayC,   HIGH);
  digitalWrite (SolRelayD,   HIGH);
  pinMode (SolRelayA,      OUTPUT); //Set Relay Pins as Outputs
  pinMode (SolRelayB,      OUTPUT);
  pinMode (SolRelayC,      OUTPUT);
  pinMode (SolRelayD,      OUTPUT);
  pinMode (switchPin, INPUT_PULLUP);
}

void loop() {//open loop

  unsigned long currentMillis = millis();//update every loop

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

  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
  Serial.println(" ");


  if (buttonState == LOW) { //block switch below from main loop
    switch (CycleStage) {
      case 0:
        digitalWrite (SolRelayA,   LOW);
        timeDelay = 6000;
        break;
      case 1://if CycleStage==1 kinda of arguement
        digitalWrite (SolRelayB,   LOW);
        //delay (5000);
        timeDelay = 5000;//update timeDelay for next step
        break;
      case 2:
        digitalWrite (SolRelayC,   LOW);
        // delay (500);
        timeDelay = 500;//update timeDelay for next step
        break;
      case 3:
        digitalWrite (SolRelayB,   HIGH);
        timeDelay = 500;//update timeDelay for next step
        //delay(500);
        break;
      case 4:
        digitalWrite (SolRelayA,   HIGH);
        // delay(4000);
        timeDelay = 4000;//update timeDelay for next step
        break;
      case 5:
        digitalWrite (SolRelayC,   HIGH);
        digitalWrite (SolRelayD,   LOW);
        //delay (1000);
        timeDelay = 1000;//update timeDelay for next step
        break;
      case 6:
        digitalWrite (SolRelayD,   HIGH);
        timeDelay = 6000;//update timeDelay for next step
        break;
      case 7:
        digitalWrite (SolRelayA,   HIGH);
        digitalWrite (SolRelayB,   HIGH);
        digitalWrite (SolRelayC,   HIGH);
        digitalWrite (SolRelayD,   HIGH);
        timeDelay = 6000;//7 is now going to loop back to 0
        CycleStage = 0; //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);
  }

  //back in the main loop

}//close main loop

you already know what I screwed up by deleting im just waiting for you to paste the line back in and tell me what I did wrong. (I know it sounds cruel but I know you know the answer)

Okay, here is the readout from the serial monitor. It appears that the buttonstate is on right from the very beginning. It isn't affected by turning the switch on or off or even removing it completely.

CycleStage : 0 timer set point : 0

buttonstate : 0 0=on 1=off
CycleStage : 0 timer set point : 6000

buttonstate : 0 0=on 1=off
CycleStage : 0 timer set point : 6000

buttonstate : 0 0=on 1=off
CycleStage : 0 timer set point : 6000

buttonstate : 0 0=on 1=off
CycleStage : 0 timer set point : 6000

LOL...I just saw your last post. Yes...you are cruel! :wink: Can you just confirm for me that in my code with delays the switch code is actually doing what I think it's doing? If it is then I think I can fix this. But right now the dogs need to go out and my blurry eyes need a break!