Do I need an interrupt?

Hi all,

Running Arduino Mega 1280. I'm trying to add capabilities to basic sketch here.

I have 4 LEDs. D-PIN 10=LED1,11=2,12=3,13=4. With serial command (@ 9600) I can send 1HIGH, send 2 HIGH while sending 1 LOW first, or command to send both LOW if one or other is high. At same time controlling LEDs 3 & 4 the same way.

For example:
I want to be able to make LED1 go HIGH for a designated delay (say 60 sec) and then have it go LOW. But, then, if I want LED2 to go HIGH before LED1's delay is finished, it will send LED1 LOW and stop its delay. It will then send LED2 HIGH and start its delay and go LOW after it times out unless cut short as LED1's delay was.

(This is the area I have been trying to paste my sketch in to no avail. Sorry.)

Please, are there any gurus who can help me here. I have been all over looking. I'm just not sure what works and how to implement it if I found it.

Thanks.

You need to look at the millis() function (millis() - Arduino Reference). It allows you to monitor time.

Take a look at this and see if it helps (http://www.cmiyc.com/blog/2011/01/06/millis-tutorial/). Example #5 I think is similar to what you are trying to do. (Also note, my code will fail every 49 days, but it'll get you started.)

Your sketch will get seemingly more complicated, but once you understand how you can monitor time (without interrupts) it gets much easier. Just a glance it seems like you'll have variables to monitor how long LED1 has been high so you can determine if it should shut off yet or if LED2 should be turned on yet.

well just have a look at this ! Mikeys Notes
and try to integrate it with your code

OK. I read through the links you sent on millis. The reference link is for using millis as a "how long has something been running" way, no?
The tutorial seems more comprehensive and it says it makes for more flexible code. Please forgive my ignorance, but, I am trying to understand how to apply it in my instance. I have found out how to post my sketch and hope it helps.

/*
* Turn 4 LEDs split into 2 sets on and off with special characters
* sent over the serial connection with only 1 LED of each set 
* allowed on at a time. 
* If  the 2nd LED is commanded on, the first will be turned off
* prior.
*/

int led1 = 13;      // led is hooked up to this pin
int led2 = 12;      // led is hooked up to this pin
int led3 = 11;      // led is hooked up to this pin
int led4 = 10;      // led is hooked up to this pin

char LED1 = '1';     // ascii LED 1 on
char OFF12 = 'o';     // ascii leds 1&2 off
char LED2 = '2';  // ascii LED 2 on
char LED3 = '3';    // ascii LED 3 on
char OFF34 = 'f';    // ascii leds 3&4 off
char LED4 = '4';   // ascii LED 4 on
char ON13 = '5';      // ascii LED 1&3 on
char AllOFF = 'a';    // ascii ledsAll off
char ON24 = '6';      // ascii LED 2&4 on

int ledState1;
int ledState2;
int ledState3;
int ledState4;
char nextChar;

void setup()
{
       Serial.begin(9600);
       
       pinMode(led1, OUTPUT);
       digitalWrite(led1, LOW);
       ledState1 = LOW;
       
       pinMode(led2, OUTPUT);
       digitalWrite(led2, LOW);
       ledState2 = LOW;
       
       pinMode(led3, OUTPUT);
       digitalWrite(led3, LOW);
       ledState3 = LOW;
       
       pinMode(led4, OUTPUT);
       digitalWrite(led4, LOW);
       ledState4 = LOW;
}

void loop()
{
  if (Serial.available())
    {   
       nextChar = Serial.read();  // read just one character
       if (nextChar == LED1)  // check for '1'
       {
         ledState1 = HIGH;
         ledState2 = LOW;
         Serial.println("LED 1 On");
       }
       else if (nextChar == LED2)  // check for '2'
       {
         ledState1 = LOW;
         ledState2 = HIGH;
         Serial.println("LED 2 On");
       }
       else if (nextChar == OFF12)  // check for 'o'
       {                 
         ledState1 = LOW;
         ledState2 = LOW;
         Serial.println("1/2 Off");
       }   
       else if (nextChar == LED3)  // check for '3'
       {
         ledState3 = HIGH;
         ledState4 = LOW;
         Serial.println("LED 3 On");
       }
       else if (nextChar ==LED4)  // check for '4'
       {
         ledState3 = LOW;
         ledState4 = HIGH;
         Serial.println("LED 4 On");
       }
       else if (nextChar == OFF34)  // check for 'f'
       {                 
         ledState3 = LOW;
         ledState4 = LOW;
         Serial.println("3/4 Off");
       }
       else if (nextChar == ON13)  // check for '5'
       {
         ledState1 = HIGH;
         ledState2 = LOW;
         ledState3 = HIGH;
         ledState4 = LOW;
         Serial.println("LED 1/3 On");
       }
       else if (nextChar == ON24)  // check for '6'
       {
         ledState1 = LOW;
         ledState2 = HIGH;
         ledState3 = LOW;
         ledState4 = HIGH;
         Serial.println("LED 2/4 On");
       }
       else if (nextChar == AllOFF)  // check for 'a'
       {
         ledState1 = LOW;
         ledState2 = LOW;
         ledState3 = LOW;
         ledState4 = LOW;
         Serial.println("All LED Off");
       }
       digitalWrite(led1, ledState1);
       digitalWrite(led2, ledState2);
       digitalWrite(led3, ledState3);
       digitalWrite(led4, ledState4);
    }
}

James C4S,

I have been playing with the sample sketches you sent me to. Nice! It is good to see so many ways to create a delay. Or, perhaps I shouldn't call it a"delay" anymore. It seems the term is limiting.

My main sketch is to be able to turn on/off LEDs with serial commands, but, instead of it being entirely manual control, to add a "delay" function to every "On" command. Each "On" would not only create the desired function and enable its "delay", but, overwrite the opposite LEDs function and "delay". :-/

You're asking for multiple forms of logic then, which will require you to restructure your code a little. You'll need to track the state of each LED and the amount of time it should stay On. (maybe you can do this with the same variable.)

In loop(), you'll update the status of each of your LEDs based on their state value and if their timers have elapsed. Then you can do you if-checking for any serial commands. The serial commands can also update those LED state variables. Then on the next iteration of loop() the lights will respond to your manual commands.

puesdo-code will look like this:

loop() {
    currentTime = millis();

   check if LED1 should shut-off yet, by comparing currentTime to LED1timeOutValue
        update LED1state
   check if LED2 should shut-off yet, by comparing currentTime to LED1timeOutValue
        update LED2state

   set LED1 to the value of LED1state
   set LED2 to the value of LED2state ...

   Is there anything from serial yet?
       update LED1 state if necessary
       update LED1 timeout if necessary (e.g. LED1Timer = millis() + timeOutValue)
       ... repeat for all other serial commands / LEDs.
}

Example #5 of my tutorial is closest to what you are trying to do. My example doesn't have code to manually update the variables, but that is what you are already doing. So just a small change for that part.

The keys are:

  1. every loop, update the state of the LED (no harm if the state hasn't changed.)
  2. Determine if you've timed out yet for any of your lights
  3. manually update your variables based on serial commands.

Another way to do this is to set up a few software timers with callback functions to turn LEDs off. The timers are incremented every say 100mS and you do something like this to start a LED

turn_LED_on (LED_NUM)
start_timer (LED_NUM, LED_TIME)

The timers tick away in the background (on an timer interrupt, can that be done with Arduino? if not use a timer directly) and every time a timer times out it turns the appropriate LED off, either directly or using a callback function.

This way there's no testing for states or if..this..then..something...else statments for each LED.


Rob

Graynomad,

That might be an easier way than all the other complicated stuff, huh?
So, you are saying to have a timer for, say, LED 2 starting when LED2 go's HIGH? And this timer could be set for any amount of time(1 sec, 10 min, hours, etc)? And the timer expiration would trigger a state change of the LED or simply send a LOW command? And, if LED 1 is sent HIGH inside LED 2's timer countdown, it could send 2 LOW and cancel its timer too?

Here's my initial take on the job.

#define N_LEDS 4


struct led {

      long count;
      byte pin;

} ;

struct led      leds[4];

void scanCounters (void) {
// this gets called every 100mS, or whatever granularity makes sense for your app
      struct led *l;

      for (int i = 0; i < N_LEDS; i++) {

            l = &leds[i];
            
                  if (l->count != -1) {
                  l->count--;
                  if (l->count == -1) {
                        // do LED timout stuff, EG
                        digitalWrite (i, LOW);                  
                  }
            }
      }

}

boolean led_3_should_go_on() {
 return true; 
}

void startLed (byte led, long time) {
      leds[led].count = time;
      digitalWrite (leds[led].pin, HIGH);
}

void stopLed (byte led) {
      leds[led].count = -1;
      digitalWrite (leds[led].pin, LOW);
}

void setup () {
      // map logical LEDs to physical pins
      leds[0].pin = 3;  // use your pin numbers here
      leds[1].pin = 5;
      leds[2].pin = 9;
      leds[3].pin = 12;
      
      // init counters
      for (int i = 0; i < N_LEDS; i++) {
            leds[i].count = -1;
            pinMode(leds[i].pin, OUTPUT);
            digitalWrite(leds[i].pin, LOW);
      
        }
}

void loop () {

      if ((millis() % 100) == 0) scanCounters(); // scan 10x a second
      
      if (led_3_should_go_on() ) {
            startLed(3, 1000);
            stopLed(2);
      }
}

I missed the "LED2 turns off LED1" bit at first but depending on the exact relationship between LEDs that can be handled in the main loop I would think.

This compiles but is untested and of course doesn't handle the serial commands.


Rob