Go Down

Topic: Help programing - Turn on/off based on input (Read 2 times) previous topic - next topic

Xenia2

Can someone help me with coding? Below is what I have, but I would like to replace the delay() function to millis()

Any help would be appreciated  :)

int relayPin = 13;  // relay connecte to digital pin 13
int inPin = 7;      // sensor input source connecte to digital pin 7
int val = 0;        // variable to store the read value

void setup()
{                
 // initializes
 pinMode(relayPin, OUTPUT);        // sets the digtial pin 13 as output
 pinMode(inPin, INPUT);            // sets the digital pin 7 as input
}

void loop()
{
 val = digitalRead(inPin);            // read the input pin
 
 if(val == HIGH)
 {
   delay(10000);                      //wait 10secs.
   digitalWrite(relayPin, HIGH);
 }
 else
 {
   delay(2000);                      //remain on for 2secs
   digitalWrite(relayPin, LOW);
 }

   
}

MarkT

Firstly you want to record the times at which things are to happen, not actually wait.
Code: [Select]

  if (val == HIGH)
  {
    relay_turn_on = true ;
    relay_on_time = millis () + 10000 ;
  }
  if (val == LOW && relay_turn_on)
  {
    relay_turn_off = true ;
    relay_off_time = millis () + 2000 ;
  }


And you also need to check if these events are due

Code: [Select]


  if (relay_turn_on && millis () - relay_on_time >= 0)
  {
     digitalWrite (relayPin, HIGH) ;
     relay_turn_on = false ;
  }
  if (relay_turn_off && millis () - relay_off_time >= 0)
  {
    digitalWrite (relayPin, LOW) ;
    relay_turn_off = false ;
    relay_turn_on = false ;  // cancel pending turn on event since we've just turned it off.
  }


Something like that - although I haven't tested this and I'm a bit wary about how the events interact as they are not independent - I've assumed that the need to turn off the relay is only if its already scheduled to turn on - but I'm not sure exactly what you want the behaviour to be.
[ I won't respond to messages, use the forum please ]

Xenia2

Here is the basic idea what I wanted the program to do. I have sensor that monitor the water level, High in air and Low in water.

So when water low; sensor is High, turn on relay (pump) but before it turn on, because water fluctuate delay for 10secs before it really turn on. Once it is on remain on for 2secs and then shut off relay.

I also would like a the relay to stay on for 30secs after that program should stop execute until manually Reset.

wildbill

Not quite sure I understand the requirement. Is it "if the sensor is confirmed high over a ten second period, run the pump for 2 seconds, but limit total pumping until a restart to 30 seconds?"

That would certainly give some protection against a flood caused by the level sensor going bad. Once you have that working, you might consider instituting a daily (or longer) pumping limit so you don't have to do the manual restart so frequently. Also consider whether you need to defend against the arduino getting reset if the power goes out.

Xenia2

2 seconds plus whatever time it take for the pump to fill up the water to reach the sensor (sensor read Low). In other words after sensor comfirmed High, run the pump, fill up the water, sensor read Low...remain on for 2 seconds before shut off.

The 30 seconds (just a make up number for now) is the fault protection is for the bad sensor or the water reservoir empty, this to prevent the pump running too long when water is empty.

Xenia2

So in theory, I dont have to reset as often...unless water run out or sensor go bad.

wildbill

I think you're going to need some extra logic to handle the sensor bad/out of water condition. Otherwise, when one of those things occurs, you're going to run the pump for 30 seconds every time you check the level sensor, possibly burning out the pump once it exhausts the reservoir.

Xenia2

Well 30 seconds is the cut off time, if pump still on (meaning no water in the reservoir) shut it off. Assuming it take 20 seconds to fill up the water, so it never have to reach the 30 seconds limit.

Does that make sense?

wildbill

Not entirely. Now I think it's "if the sensor is confirmed high over a ten second period, run the pump until sensor is low and then for another 2 seconds. If that pumping is still happening after 30 seconds, stop the pump and use the infinite loop to stop all subsequent operations until reset"

Xenia2

Yes! that is pretty much what I wanted to do :-)

wildbill

Requirement is defined (pretty much) so it's time to look at state machines - you'll find examples in the forums. Enumerate your states (I count five),  figure out what you have to do in each state, what causes transitions between them and what to do when you transition. Loop() becomes a switch statement with the states as cases. Add in some variables to tell you when timed events started and you're most of the way there.

David Pankhurst

To use a timer instead of a delay, you use code like MarkT showed already.

If you're short on space, one way to manage is to use a variable for each item's timer, and use zero to represent an unused event (that is, not currently active).

For example, say you want a light on for 5 seconds, then turn off. Use a variable 'timerLight' to hold the milliseconds to stop in the future:

Code: [Select]
unsigned long timerLight=0;
void loop()
{
  unsigned long msec=millis();
  if ( ourNotYetWrittenHelperFunctionToDetectIfWeWantTheLightOn() )
  {
    timerLight=msec+5000; // when to stop in the future

// now turn on light

  }
  if ( timerLight && timerLight<msec ) // time to turn off?
  {
    timerLight=0;// turn off timer so we don't check again
       
// turn off light (somehow)
   
  }
}


Now the code loop will stay active without delays, yet still catch events.

You can also gang up the events - for example, after you turn off one light, you could turn on another:

Code: [Select]
unsigned long timerLight1=0, timerLight2=0;
void loop()
{
  unsigned long msec=millis();
  if ( ourNotYetWrittenHelperFunctionToDetectIfWeWantTheLightOn() )
  {
    timerLight1=msec+5000; // when to stop in the future

// now turn on light

  }
  if ( timerLight1 && timerLight1<msec ) // time to turn off 1st light?
  {
    timerLight1=0;// turn off timer so we don't check again
       
// turn off light1 (somehow)

    // now next light - turn it off in 10 seconds
    timerLight2=msec+10000; // when to stop #2 in the future

// turn ON light2 (somehow)

   
  }
  if ( timerLight2 && timerLight2<msec ) // time to turn off 2nd light?
  {
    timerLight2=0;// turn off timer so we don't check again
       
// turn off light2 (somehow)
   
  }
}


The result is a you can a number of events in whichever order you want - just remember to add on and off code in the appropriate sections.

Xenia2

Thanks for the feedback guys.

My computer currently not working, so will have to wait few days to test out the codes.

Xenia2

Ok! I got this codes to do what I wanted, but I need a timeout code within this codes. I want to say if "val" still read HIGH after 1 minute, write LOW to relayPin.

Can someone help me?


unsigned long relay_on_time;
unsigned long loopTime;

int relayPin = 13;  // relay connected to digital pin 13
int inPin = 7;      // sensor input source connected to digital pin 7
int val = 0;        // variable to store the read value

void setup()
{
  relay_on_time = millis();
  loopTime = relay_on_time; 

  pinMode(relayPin, OUTPUT);        // sets the digtial pin 13 as output
  pinMode(inPin, INPUT);            // sets the digital pin 7 as input
}

void loop()
{
  relay_on_time = millis();
 
  if (relay_on_time >= (loopTime + 10000))
  {
    val = digitalRead(inPin);
   
    if (val == HIGH)
    {
      digitalWrite(relayPin, HIGH);
    }
   
    if (val == LOW)
    {
      digitalWrite (relayPin, LOW);
    }
    loopTime = relay_on_time;
  }
 
}

mem

Perhaps the (untested) sketch below will get you closer.
see the BlinkWithoutDelay example sketch if you need more on using millis to determine a timeout period

Code: [Select]
int relayPin = 13;   // relay connected to digital pin 13
int waterLowPin = 7; // pint goes high when water level is low
int val = 0;         // variable to store the read value

long relay_on_time;

void setup()
{
  pinMode(relayPin, OUTPUT);       // sets the digtial pin 13 as output
  pinMode(waterLowPin, INPUT);     // sets the digital pin 7 as input
}

void loop()
{
  if( digitalRead(waterLowPin))
  {
    // here if the water level is low
    delay(1000 * 10); // wait ten seconds
    if( digitalRead(waterLowPin))  // check again
    {
       // here if water level is still low   
       digitalWrite(relayPin, HIGH); // turn on relay       
       relay_on_time = millis();
       while( millis() - relay_on_time < (1000 * 30) )
       {   
         if( digitalRead(waterLowPin) == false)  // check if level is now high
         {
            delay(1000 * 2); // wait two seconds
            digitalWrite(relayPin, LOW); // turn off relay
            break; // exit the while loop
         }
       }
       // here if pump on for more than 30 seconds
       digitalWrite(relayPin, LOW); // turn off relay
    }
  }
}

Go Up