Delaying action on State Change

Hi,
I'm pretty new to Arduino/programming and am looking for some help. I am trying to set up the code so that:

When sensor/switch goes high:
the motor (operated with a solid state relay) will rotate for a certain time, dwell, and rotate back to original position (second SSR on for the same amount of time.)

The problem I am having is that I don't want the motor to return to the original position until the switch goes low. I want to run CWTurn() and dwell until switch goes low. I have tried using while statements but it just gets stuck.

Here is the important part of the code i have so far:

 int valA = digitalRead(LinputPin);  //read input value
  if (valA == HIGH)                  //check if input is HIGH
  {
    //do this if valA is HIGH
    CWTurn();
    delay(Dwell);
    CCWTurn();
  }
  else
  {
    //else do this if valA is not HIGH
    digitalWrite(CWPin, LOW);  //turn LED off
  }

void CWTurn()
{
  digitalWrite(CWPin, HIGH);
  delay(MotorTime);
  digitalWrite(CWPin, LOW);
}
 
void CCWTurn()
{
  digitalWrite(CCWPin, HIGH);     //turn Motor
  delay(MotorTime);
  digitalWrite(CCWPin, LOW);
}

Thanks!!

Just to clarify:

If the switch goes low before the motor has rotated for the full time, you want it to stop and reverse back to its starting point?

What happens if the switch goes high again before it has reached the starting point?

The motor is unlikely to be completely consistent about how far it travels in a given time (especially if you are stopping and reversing it). How concerned are you with the exact position of the motor?

PeterH:
Just to clarify:

If the switch goes low before the motor has rotated for the full time, you want it to stop and reverse back to its starting point?
It doesn't have to stop prior to the full prescribed time, it can just complete the time, dwell for some amount of time, and return. I suppose a debounce at that point would make sense?

What happens if the switch goes high again before it has reached the starting point?
If it goes high while it is returning, It could just finish returning and if it is high still, it could start the loop over

The motor is unlikely to be completely consistent about how far it travels in a given time (especially if you are stopping and reversing it). How concerned are you with the exact position of the motor?
I figured this would happen and am building a manual override with buttons in another part of the code, but i am thinking this should be good enough for now. There is a potentiometer attached to the motor that i could use to treat it like a servo, but i think that would require other hardware (op amp?) that is beyond my learning point as of now.

thanks for looking!

Sounds like a job for a State Machine.

WaitingForSwitchOn
wait until switch is on
MotorMovingOut
wait until motor time elapses
Dwell
wait until dwell time elapses
WaitingForSwitchOff
wait until switch is off
MotorMovingIn
wait until motor time elapses
go back to WaitingForSwitchOn

If you put a switch at each end of the servo travel, you won't need to time the moves and should always get it right, or very close.

If the motor has an integral potentiometer then you should be able to read the motor position and control the position precisely with relatively little effort and no extra hardware (except some wires connecting it to the Arduino).

Otherwise, the behaviour you're describing sounds very simple to implement.

thanks for taking a look, I am going to look further into the state machine, I think that should be very similar to the StateChangeDetection example sketch?

The "StateChangeDetection" sketch is for a button with only two states. A State Machine generally has more states. I like to use an enumeration to name the states and a switch statement to sort out the states:

enum {WaitingForSwitchOn, MotorMovingOut, DwellPeriod, WaitingForSwitchOff, MotorMovingIn} machineState = WaitingForSwitchOn;

void loop() {
   switch (machineState){
case WaitingForSwitchOn:
        if (switchPin) {
            timerStart = millis();
            digitalWrite(CWPin, HIGH);
            machineState = MotorMovingOut;
        }
        break;
            
case MotorMovingOut:
       if (millis() - timerStart > MotorTime) {
            digitalWrite(CWPin, LOW);
            timerStart = millis;
            machineState = DwellPeriod;
       }
       break;

case DwellPeriod:
       if (millis() - timerStart > Dwell) {
            machineState = WaitingForSwitchOff;
       }
       break;

case WaitingForSwitchOff:
        if (!switchPin) {
            timerStart = millis();
            digitalWrite(CCWPin, HIGH);
            machineState = MotorMovingIn;
        }
        break;

case MotorMovingIn:
       if (millis() - timerStart > MotorTime) {
            digitalWrite(CCWPin, LOW);
            machineState = WaitingForSwitchOn;
       }
       break;
    }
}

johnwasser,
Thanks a bunch for your replies and code, I have been playing with it here and there and i am having an issue with the code not switching. It appears that after the button is pushed, the machineState does not change? Putting it another way, when i monitor the code below in the serial window, it will repeat "Motor Moving Out" whenever the button is pushed and will do nothing when the button is released. I'm still playing with it, but any advise would be greatly appreciated. Thanks!!

/*
Debugging sketch
ALT - 11Sept12

*/

const int CWPin = 12; //defines Clockwise Pin
const int CCWPin = 11; //defines Counter-clockwise Pin
const int LinputPin = 4;  //defines the input pin(for Left switch)
const int RinputPin = 3;  //defines the input pin(for Right switch)
const int MotorTime = 1500;   //defines the time the Motor is on
const int Dwell = 500;      //defines the time until motor changes


void setup(){
  Serial.begin(9600);        //initialize serial communication at 9600 bps
  pinMode(CWPin, OUTPUT);    //declare CW Pin as output
  pinMode(CCWPin, OUTPUT);  //declare CCW Pin as output
  pinMode(LinputPin, INPUT);  //declare Left switch as input
  pinMode(RinputPin, INPUT);  //declare Right switch as input
}

void loop() {

enum {WaitingForSwitchOn, MotorMovingOut, DwellPeriod, WaitingForSwitchOff, MotorMovingIn} machineState = WaitingForSwitchOn;

   switch (machineState){
     unsigned long timerStart;
case WaitingForSwitchOn:
        if (digitalRead (LinputPin)) {
            timerStart = millis();
            digitalWrite(CWPin, HIGH);
            Serial.println("Motor Moving Out");
            machineState = MotorMovingOut;
        }
        break;
            
case MotorMovingOut:
       if (millis() - timerStart > MotorTime) {
            Serial.println("does it get to here?");
            digitalWrite(CWPin, LOW);
            timerStart = millis();
            machineState = DwellPeriod;
       }
       break;

case DwellPeriod:
       if (millis() - timerStart > Dwell) {
            machineState = WaitingForSwitchOff;
       }
       break;

case WaitingForSwitchOff:
        if (digitalRead (!LinputPin)) {
            timerStart = millis();
            digitalWrite(CCWPin, HIGH);
            machineState = MotorMovingIn;
        }
        break;

case MotorMovingIn:
       if (millis() - timerStart > MotorTime) {
            digitalWrite(CCWPin, LOW);
            machineState = WaitingForSwitchOn;
       }
       break;
    }
}

You mis-translated this line:

        if (!switchPin) {

to this:

        if (digitalRead (!LinputPin)) {

when what you should have translated it to is:

        if (!digitalRead (LinputPin)) {

With the logical negation in the wrong place it was reading the wrong pin (!4 == !true == false == 0). It was reading pin 0 instead of reading pin 4 and negating it.

Thanks for catching that, I made the change but the code still doesn't seem to move past the first case when the button on pin 4 is pushed. The CWPin stays high, and the program only prints to Serial when the button is pushed (the pin remains high during subsequent pushes until the arduino is reset)

I think the problem is that the variable that holds the timer start time is going out of scope before the time is complete. By putting the definition of timerStart inside loop() you made it a local variable. Every time you go through loop() that local variable gets re-built but the value you set it to the previous time through loop() is not preserved.

To fix that you have to make timerStart a global or static variable. To make it global, move it out of the loop() function. To make it static, change the line to:

     static unsigned long timerStart;

Another problem is that you are using ints for your timer intervals. To make them compatible with millis() and timerStart they should be declared as unsigned long, like this:

const unsigned long MotorTime = 1500;   //defines the time the Motor is on
const unsigned long Dwell = 500;      //defines the time until motor changes

thanks a bunch for your help! I changed the lines you recommended and still wasn't getting the switchcase function to work properly. After reading up a little more on static variables, i realized the machine state change wasn't carrying through the end of the function. I made this change and it worked:

static enum {WaitingForSwitchOn, MotorMovingOut, DwellPeriod, WaitingForSwitchOff, MotorMovingIn} machineState = WaitingForSwitchOn;