read sensor data while doing something else

Hi all,
First post here! I'm a bit new to Arduino, so have perhaps a bit of n00b question. I have an arduino mini pro talking to MaxMSP. After much trial and error (and reading some great help on this forum!), I have my sketch and patch set-up nicely so I can read analog and digital input from some pins while sending PWM data to others.

I'm now trying to get a few more functions onto the arduino. Here's where I am stuck: if I receive an 'f' (followed by some extra numbers) from Max, I want to flash some LEDs. The part is all workin' dandy. My problem is that while the LEDs are flashing, I do not want to stop receiving data form the sensors during this time. Right now this isn't the case...as soon as I call the function to flash the LEDs, everything else stops. Is it possible to do what I want? I could certainly do the "flash" in Max instead, but would like to minimize traffic on the serial port if I can.

Here's my sketch.

Thanks in advance!
Best,
David

int ledPin = 13; // status LED on Arduino
int pwmOne = 6;  // pin 6 = PWM LED output 1
int pwmTwo = 9;  // pin 9 = PWM LED output 2
int compass = 10; // pin 10 = power for compass
int inByte = 0; // container to hold incoming serial data
int byteCounter = 0;
int command = 0;
int val1 = 0;
int val2 = 0;
int val3 = 0;


void setup()
{
  Serial.begin(57600);               // 115200 is the default Arduino Bluetooth speed
  pinMode(ledPin, OUTPUT);            // declare LED as output
  pinMode(2, INPUT);            // declare pin 2 as digital input
  pinMode(4, INPUT);            // declare pin 4 as digital input
  pinMode(pwmOne, OUTPUT);            // declare pin 6 as output
  pinMode(pwmTwo, OUTPUT);            // declare pin 9 as output
  pinMode(compass, OUTPUT);           // declare pin 9 as output


  for (int i=0; i <= 25; i++){ // flash all LEDs once a connection is made
    digitalWrite(ledPin, HIGH);
    analogWrite(pwmOne, 255);
    analogWrite(pwmTwo, 255);
    delay(20);
    digitalWrite(ledPin, LOW);
    analogWrite(pwmOne, 0);
    analogWrite(pwmTwo, 0);
    delay(20);
  } 

}


void loop()
{ 
  while (Serial.available() > 0) { // Check serial buffer for any data

    inByte = Serial.read();
    //                 Serial.print("raw value = ");
    //                 Serial.println(inByte);

    if (inByte == '

) { // reset character = $
     byteCounter = 0;
     command = 0;
     val1 = 0;
     val2 = 0;
     val3 = 0;
     //                        Serial.println("reset");
   }
   else if (inByte != 13 && inByte != 36 && byteCounter == 0) { // first value of list = command
     command = inByte;
     //                        Serial.print("command byte = ");
     //                        Serial.println(command);
     byteCounter++; // increase byteCounter by 1
   }
   else if (inByte != 13 && inByte != 36 && byteCounter == 1) { // PWM pin # OR flash time part 1
     val1 = inByte;
     //                        Serial.print("val1 =");
     //                        Serial.println(val1);
     byteCounter++; // increase byteCounter by 1
   }
   else if (inByte != 13 && inByte != 36 && byteCounter == 2) { // PWM value OR flash time part 2
     val2 = inByte;
     //                       Serial.print("val2 =");
     //                       Serial.println(val2);
     byteCounter++; // increase byteCounter by 1
   }
   else if (inByte != 13 && inByte != 36 && byteCounter == 3) { // flash time intensity
     val3 = inByte;
     //                       Serial.print("val3 =");
     //                       Serial.println(val3);
     byteCounter++; // increase byteCounter by 1
   }
   else if (inByte == 13) {
     //                        Serial.println("end of command");
     //                  Serial.flush();
     //                  delay (10); // make sure we aren't overloading anything
   } // end if

if (command == 'r') { // If command 'r' is received then read the pins
     digitalWrite(ledPin, HIGH); // turn on the status LED
     Serial.print("wand "); // sets a header for the data

// read analog pins
     int a0 = analogRead(0); // read analog input 0
     Serial.print("a0=");
     Serial.print(a0);
     int a1 = analogRead(1); // read analog input 1
     Serial.print("a1=");
     Serial.print(a1);
     int a2 = analogRead(2); // read analog input 2
     Serial.print("a2=");
     Serial.print(a2);

// read digital pins
     int d2 = digitalRead(2); // read button value on pin 2
     Serial.print("d2=");
     Serial.print(d2);
     int d4 = digitalRead(4); // read button value on pin 4
     Serial.print("d4=");
     Serial.print(d4);

Serial.println(); // Send a carriage return to mark end of pin data.
     digitalWrite(ledPin, LOW); // turn off the status pin

} // end command = 'r'

// If a 'w' is received then write data to the output pins
   if (command == 'w' && byteCounter == 3) {
     analogWrite(val1, val2);
   } // end if command = 'w'

// If a 'c' = 99 is received then toggle power pin for compass
   if (command == 'c') {
     digitalWrite(compass, HIGH); // turn on the compass
     Serial.println("turning on compass");
     delay (10); // delay to make sure compass sends data.
     digitalWrite(compass, LOW); // turn off the compass
     Serial.println("turning off compass");
   } // end if command = 'c'

// If an 'f' is received, flash the LEDs based on value for val1
   if (command == 'f' && byteCounter == 4) {  // flash them LEDs
     flashLEDs(val1,val2,val3);
     command = 0;
     val1 = 0;
     val2 = 0;
     val3 = 0;
   } // end if command = 'f'

} // end while

} // end loop

void sendValue (int x){               // function to send the pin value followed by a "space".
 Serial.print(x);
 Serial.print(32, BYTE);
}

void flashLEDs(int a, int b, int c) {
 int flashtime = ((a * 1000)+(b * 10)) / 40; // gives resolution of hundreth of second
 Serial.print("a =");
 Serial.println(a);
 Serial.print("b =");
 Serial.println(b);
 Serial.print("Flash time =");
 Serial.print(flashtime * 40);
 Serial.print(" Intensity =");
 Serial.println(c);
 for (int i=0; i <= flashtime; i++){
   analogWrite(pwmOne, c);
   analogWrite(pwmTwo, c);
   delay(20);
   analogWrite(pwmOne, 0);
   analogWrite(pwmTwo, 0);
   delay(20);
 } //end for loop
} // end of flashLEDs

A delay will stop execution, so eliminate the delays and replace them with counters.

Make the whole program one big loop, and if LED is flagged on, use the loop to countdown duration rather than delays = )

Yes, the basic thing to do is to eliminate the explicit delays. It makes the program a bit harder to understand (at least, I find 'em harder to understand), but may be it'll help if you think about it like this: instead of calling for a ten second delay, make a note of a time, ten seconds from now, when some action must happen. Then, keep an eye on the time and when it's time for the action, do it. Durnig that "keep an eye on the time" phase, you can keep (the other) eye on some other activities.

Hope that make sense!

Thank you both for your help! It makes sense...I think! Now trying to decide if I should attempt this on the Arduino, or just in Max where my programming chops are considerably more proficient :slight_smile: Actually the more I think about it, it might not be TOO beyond what I can do on the Arduino...nice little challenge, at least!

Thanks again!
David

Actually, I think the problem lies in your flashLEDs function. Yes, the delays are a problem, but I suspect your code is getting stuck in your "for" loop in that function.

If we think of the flow of the program:

  1. program recieves flash command and parameters
  2. call flashLEDs(val1,val2,val3)
  3. calculate flashtime, print to serial
  4. loop from 0-flashtime, delaying 40ms (20+20) each loop
  5. continue with the rest of the code

So, while the program is in the for loop, it is doing nothing more than turning the LEDs on and off - and encountering a 40*flashtime millisecond delay. What you could do to get around this is store flashtime as a global variable, which by default is set to 0. Then, modify the flow of the code from above so that step 3 becomes:

  1. calculate flashtime, store in global variable, print to serial

Then, in your main loop (maybe in a function called updateLEDs, or something similar), you do this:

if (global_flashtime > 0)
{
    analogWrite(pwmOne, c);
    analogWrite(pwmTwo, c);
    delay(20);
    analogWrite(pwmOne, 0);
    analogWrite(pwmTwo, 0);
    delay(20);

    global_flashtime--;
}

This way, instead of you encountering a 40*flashtime ms delay while flashing your LEDs, you encounter a 40ms delay but the program keeps looping through the whole thing - including the reading of inputs and serial i/o.

If a 40ms delay is too much, you could also store a toggle and cycle from 0-flashtime*2. Then, if the toggle is a 1, you turn on the LEDs, if it's a 0, you turn them off, and then you do your 20ms delay.

So, yes, the delay was sort of the problem - but the real problem was where the delays were.

Edit: The way I have written the code above, the LEDs will spend more time off than on. They will be on for 20ms, then off for 20ms + the time it takes to reach the code again. Not sure if that is a problem or not, but the second method i described (using a toggle) would go some way to eliminating this.