i don't want delay

hi there. i am putting two separate codes together. one that translates ping sensor cm measurements to analog output and the other turns on relays based on state of a digital pin.
My problem is that I want the relays to be on for 20 seconds after the digital input goes high. This occurs but because I have delay in my code the ping sensor stops sensing for the duration of the relay being on.
I looked at the “blink without delay” code but that doesn’t seem right for me, because I don’t want a looping on/off.
Thanks (and this due tomorrow/ big job ) aLOT!
-M

I looked at the "blink without delay" code but that doesn't seem right for me, because I don't want a looping on/off.

It can still apply. It's just 'time stamping' a variable at the start of some event and later comparing it to the desired amount of time passage.

It doesn't depend on what kind of loop is it is enclosed in. By the way you do relialize that the main loop() is a repeating loop?

Lefty

thanks i know this really basic, but I am stuck. I am trying to understand what your saying: Basically when the sensor is HIGH I can have the millis count 30 seconds? I attached the code that i have thus far.


/* Ping))) Sensor

This sketch reads a PING))) ultrasonic rangefinder and returns the distance to the closest object in range. To do this, it sends a pulse to the sensor to initiate a reading, then listens for a pulse to return. The length of the returning pulse is proportional to the distance of the object from the sensor.

The circuit: * +V connection of the PING))) attached to +5V * GND connection of the PING))) attached to ground * SIG connection of the PING))) attached to digital pin 7

http://www.arduino.cc/en/Tutorial/Ping

created 3 Nov 2008 by David A. Mellis modified 30 Jun 2009 by Tom Igoe

This example code is in the public domain.

*/

// this constant won't change. It's the pin number // of the sensor's output: const int pingPin = 7; const int analogOutPin = 9;

const int motPin1 = 2; // the number of the pushbutton pin const int motr1 = 3; const int motPin2 = 4; // the number of the pushbutton pin const int motr2 = 5; // the number of the LED pin

// variables will change: int mot1State = 0; int mot2State = 0;// variable for reading the pushbutton status

int outputValue = 0;

void setup() { // initialize serial communication: // initialize the LED pin as an output: pinMode(motr1, OUTPUT); // initialize the pushbutton pin as an input: pinMode(motPin1, INPUT); // initialize the LED pin as an output: pinMode(motr2, OUTPUT); // initialize the pushbutton pin as an input: pinMode(motPin2, INPUT); Serial.begin(9600); }

void loop() { // read the state of the pushbutton value: mot1State = digitalRead(motPin1); mot2State = digitalRead(motPin2);

if (mot1State == HIGH) { // turn LED on: digitalWrite(motr1, HIGH); delay (20000) ; digitalWrite(motr1, LOW); } else { // turn LED off: digitalWrite(motr1, LOW); } if (mot2State == HIGH) { // turn LED on: digitalWrite(motr2, HIGH); delay (20000) ; digitalWrite(motr2, LOW); } else { // turn LED off: digitalWrite(motr2, LOW); }

// establish variables for duration of the ping, // and the distance result in inches and centimeters: long duration, inches, cm;

// The PING))) is triggered by a HIGH pulse of 2 or more microseconds. // Give a short LOW pulse beforehand to ensure a clean HIGH pulse: pinMode(pingPin, OUTPUT); digitalWrite(pingPin, LOW); delayMicroseconds(2); digitalWrite(pingPin, HIGH); delayMicroseconds(5); digitalWrite(pingPin, LOW);

// The same pin is used to read the signal from the PING))): a HIGH // pulse whose duration is the time (in microseconds) from the sending // of the ping to the reception of its echo off of an object. pinMode(pingPin, INPUT); duration = pulseIn(pingPin, HIGH);

// convert the time into a distance cm = microsecondsToCentimeters(duration); outputValue = map(cm, 10, 250, 255, 0); outputValue = constrain(outputValue, 0, 255); // change the analog out value: analogWrite(analogOutPin, outputValue);

Serial.print(inches); Serial.print("in, "); Serial.print(cm); Serial.print("cm"); Serial.println();

delay(100); }

long microsecondsToInches(long microseconds) { // According to Parallax's datasheet for the PING))), there are // 73.746 microseconds per inch (i.e. sound travels at 1130 feet per // second). This gives the distance travelled by the ping, outbound // and return, so we divide by 2 to get the distance of the obstacle. // See: http://www.parallax.com/dl/docs/prod/acc/28015-PING-v1.3.pdf return microseconds / 74 / 2; }

long microsecondsToCentimeters(long microseconds) { // The speed of sound is 340 m/s or 29 microseconds per centimeter. // The ping travels out and back, so to find the distance of the // object we take half of the distance travelled. return microseconds / 29 / 2; }

i guess whats getting me confused is how use this huge stream of milliseconds to my advantage. How do I let the arduino know when it needs to "look" at the millisecond stream? I'm confused, any help would be great. -M

Your problem is with the delay function. Every time you delay(20000) your entire program blocks (stops working) for 20 seconds.

As lefty says you have to remember a time then compare that against the current time to see if 20s has elapsed. Which is what the "blink without delay" example does.

Without writing the code for you here is a rough example of how this is normally done.

loop () {

if (button_just_pressed) {
   remembered_time = current_time
   turn_led_motor_whatever_on
}

if (current_time == remembered_time + 20000) {
   do_turn_led_motor_whatever_off
}

do_ping_stuff()
}

As you appear to have two buttons you will need to keep two "remembered_time" variables, one for each button and duplicated the "if" blocks.

Like retrolefty was saying, the “Blink without delay” code is a generic example of a timed action executed without using “delay” (as your code does), but instead by having the arduino check for elapsed time each time it loops through the code in “loop()”.

You code already makes the switches turn on their respective motors whenever the input pins are triggered. You could adjust your code so that instead of triggering the motors directly, the inputs reset a counter:

if (mot1State == HIGH) {     
   // Assign new trigger1Time
   trigger1Time = millis();
}

Then you could have the arduino check to see if the elapsed time since that trigger is more or less than 20 seconds (20000 ms).

if (millis - trigger1Time < 20000) {....

If less, the motor should be turned on. If more, the motor should be turned off. That way, the arduino will monitor the inputs continuously, and keep the motors on for 20 seconds after the end of the last input trigger.

brilliant thanks guys. I am really green when it comes to coding, I do mostly hardware engineering. Thanks alot -

question tho : this is gonna be running in an installation up for a month. Is the milli prone to error over time? Also I read that u shouldn't do arithmetic at the same time using milli. I have a map line in the code, will it still run ok? Thanks -M

millis() will overflow 49.7 days after the program starts so you’re right for a while. If you’re worried about that keep an overflow variable and check for a new value < the last value. The time may creep over a long period, it’s controlled by a crystal that should be accurate to about 30ppm (parts per million) in general and will have changes with temperature but I doubt any of that will worry this application.

As for doing arithmetic, surely there’s no multi-tasking going on, you can’t do things “at the same time”, millis() and any other function executes then the program moves on to the next function. I wouldn’t expect side affects as you mention but it’s possible.

ok so i am really freaking now...i couldn't really get this so I tried a hardware solution - didn't work. So now this is my only option. I realize it won't help to beg for the code but I do have simple questions i hope can be answered. Basically, I want the time since arduino is on to be "stamped" only when one of the digital inputs is high. When the input goes high, the corresponding output pin goes HIGH and then the comparison btwn the time stamped and the current time begins until "remembered time + 20000" is == "current time." Then the output pin goes low. Is this in the ballpark of understanding?? Thanks a million, -M

I think you're getting it, while the pseudo code I posted obviously won't run I think it's about right logically.

Notice I wrote

if (button_just_pressed)

not

if (mot1State == HIGH)

as you have. Your code will restart the timer every time the code loops and the button is high, effectively not allowing the timing to start until the button is released, not when it's pressed. This may be OK with you but if not then something like

if (digitalRead(motPin1) == HIGH && mot1State == LOW)
   mot1State = digitalRead(motPin1)
   remembered_time = current_time
   turn_led_motor_whatever_on

will detect the rising edge of the button input. (it's more efficient to read the pin state once into a variable but I don't think that will matter here).

None of this allows for debouncing either.

OK I GOT THE CODE TO WORK…cool. BUT PROBLEM is that the motor is STUCK on when I upload the code that includes the PING text…what the #$%^^!!!

unsigned long time1;
const int pingPin = 7;
const int analogOutPin = 9;

const int motPin1 = 2; // the number of the pushbutton pin
const int motr1 = 3;

// the number of the LED pin

// variables will change:
int mot1State = 0;
int mot2State = 0;// variable for reading the pushbutton status

int outputValue = 0;

void setup() {
// initialize serial communication:
// initialize the LED pin as an output:
pinMode(motr1, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(motPin1, INPUT);
// initialize the LED pin as an output:

Serial.begin(9600);
}

void loop()
{
// read the state of the pushbutton value:
mot1State = digitalRead(motPin1);

if (mot1State == HIGH) {

time1 = millis();
digitalWrite(motr1, HIGH);
}
if (millis() == time1 + 30000)
{
// turn LED off:
digitalWrite(motr1, LOW);
}

// establish variables for duration of the ping,
// and the distance result in inches and centimeters:
long duration, cm;

pinMode(pingPin, OUTPUT);
digitalWrite(pingPin, LOW);
delayMicroseconds(2);
digitalWrite(pingPin, HIGH);
delayMicroseconds(5);
digitalWrite(pingPin, LOW);

// The same pin is used to read the signal from the PING))): a HIGH
// pulse whose duration is the time (in microseconds) from the sending
// of the ping to the reception of its echo off of an object.
pinMode(pingPin, INPUT);
duration = pulseIn(pingPin, HIGH);

// convert the time into a distance
cm = microsecondsToCentimeters(duration);
outputValue = map(cm, 10, 250, 255, 0);
outputValue = constrain(outputValue, 0, 255);
// change the analog out value:
analogWrite(analogOutPin, outputValue);

}

long microsecondsToCentimeters(long microseconds)
{
// The speed of sound is 340 m/s or 29 microseconds per centimeter.
// The ping travels out and back, so to find the distance of the
// object we take half of the distance travelled.
return microseconds / 29 / 2;
}

could have something to do with the "delays" in the ping code? Thanks I'm freaking still -

BUT PROBLEM is that the motor is STUCK on when I upload the code that includes the PING text

Without you needing to push the button?

sorry - to clarify there is a motion sensor(on/off) attached to the input pin, not a button.

to clarify there is a motion sensor(on/off) attached to the input pin

So, presumably the sensor senses motion when you turn the device on, so the motor fires up. Seems reasonable, given your code. What is the problem?

I don't know if it matters with Arduino but I'd move the

// establish variables for duration of the ping, // and the distance result in inches and centimeters: long duration, cm;

to the top of the prog as they are essentially globals or to the top of loop() if it's a normal function (is there a hidden while loop in here). PaulS?

I don't know if it matters with Arduino

It does not. The Arduino language is based on C++, where variables can be declared anywhere (and should be declared as close to where they are needed as possible).

The code will constantly power the motor as long as there is a high on motPin1 then continue for 30s after motPin1 goes low.

Is that what you intended?