Interrupting when an input changes

Posted in another forum and noticed errors. Tried to correct, but lost the main body. So…

I'm working on a project to replace the stock (incandescent) bulbs in my car's indicators with LED "bulbs". I've figured out the hardware (i.e. changing between the car's ˜12V and Arduino 5V) as well as building the LED "bulbs".

I'm now working on the code and have hit a couple of roadblocks. What I need to do is read 4 inputs and output to LED arrays depending on the input combinations. The outputs will differ depending on the inputs (i.e. output for Brake input will be different than output for Brake and Left-turn combined).

I've figured out how to code the outputs based upon different input combinations, but what I don't know is how repeat the output until ANY one of the 4 inputs changes, then stop the output sequence and return to the top of the loop. So, I need the code to do this:

  1. Read 4 inputs
  2. Output to 8 pins depending on inputs and repeat until
  3. Detect change on ANY input
  4. Stop and return to the top

For the 4 inputs, there are 7 possible input combinations (brake, left-turn, right-turn, brake & left-turn, etc.) and 8 different output combinations. I should also mention that the turn indicators are 3-bulb sequentials (as are original standard on my '68 T-Bird) which explains the delay functions is some of the code.

Here's what I have so far:

int outPin = 0;
int inPin = 0;
int setPin = 0;
int pinRead = 0;
int lightPin = 0;

void setup()
{
 for (int outPin = 0; outPin < 8; outPin++);  {  //set pins 0 thru 7 as OUTPUT
   pinMode(outPin, OUTPUT);
  }
 
 for (int inPin = 9; inPin < 13; inPin++);  {    //set pins 9 thru 12 as INPUT
   pinMode(inPin, INPUT);
  }
 
 for (int setPin = 0; setPin < 8; setPin++); {  //set all pins to LOW
   setPin = LOW;
  }  
}

void loop()
{
  for (int pinRead = 9; pinRead < 13; pinRead++)  {  //read pins 9 thru 13
  digitalRead (pinRead);
  }

// write to OUTPUT pins based on INPUT pin combinations (7 different combinations)
 
  if (9 == HIGH && 10 == LOW && 11 == LOW && 12 == LOW) {  //Brake
   for (int lightPin = 0; lightPin < 8; lightPin++)
   digitalWrite(lightPin, HIGH);
  
  } else if (9 == LOW && 10 == HIGH && 11 == LOW && 12 == LOW) {   //LeftTurn
     digitalWrite (0, HIGH);
     delay(500);
     digitalWrite (1, HIGH);
     delay(500);
     digitalWrite (2, HIGH);
     delay(500);
     digitalWrite (0, LOW);
     digitalWrite (1, LOW);
     digitalWrite (2, LOW);
     delay(1000);
  
  } else if (9 == LOW && 10 == LOW && 11 == HIGH && 12 == LOW) {  //RightTurn
     digitalWrite (3, HIGH);
     delay(500);
     digitalWrite (4, HIGH);
     delay(500);
     digitalWrite (5, HIGH);
     delay(500);
     digitalWrite (0, LOW);
     digitalWrite (1, LOW);
     digitalWrite (2, LOW);
     delay(1000);
  
  } else if (9 == LOW && 10 == LOW && 11 == LOW && 12 == HIGH) {  //Hazard
     digitalWrite (0, HIGH);
     digitalWrite (3, HIGH);
     delay(500);
     digitalWrite (1, HIGH);
     digitalWrite (4, HIGH);
     delay(500);
     digitalWrite (2, HIGH);
     digitalWrite (5, HIGH);
     for (int lightPin = 0; lightPin < 6; lightPin++)
       digitalWrite(lightPin, LOW);
     delay(1000);
  
  } else if (9 == HIGH && 10 == HIGH && 11 == LOW && 12 == LOW) {  //LeftBrake
    digitalWrite (3, HIGH);
    digitalWrite (4, HIGH);
    digitalWrite (5, HIGH);
    digitalWrite (0, HIGH);
    delay(500);
    digitalWrite (1, HIGH);
    delay(500);
    digitalWrite (2, HIGH);
    delay(1000);
    digitalWrite (0, LOW);
    digitalWrite (1, LOW);
    digitalWrite (2, LOW);
  
  } else if (9 == HIGH && 10 == LOW && 11 == HIGH && 12 == LOW) {  //RightBrake
    digitalWrite (0, HIGH);
    digitalWrite (1, HIGH);
    digitalWrite (2, HIGH);
    digitalWrite (3, HIGH);
    delay(500);
    digitalWrite (4, HIGH);
    delay(500);
    digitalWrite (5, HIGH);
    delay(1000);
    digitalWrite (3, LOW);
    digitalWrite (4, LOW);
    digitalWrite (5, LOW):
  
  } else if (9 == LOW && 10 == LOW && 11 == LOW && 12 == LOW) {  //ALL OFF
  for (int lightPin = 0; lightPin < 8; lightPin++);
  digitalWrite (lightPin, LOW);
  }
}

So, what I need to know is:

  1. How do I repeat the resulting functions of an individual "if" statement
  2. How to detect a change in ANY of the 4 inputs during that repeat, and
  3. Stop the "repeat" and return to the top of the loop upon #2

I'm no expert, but from what I remember glancing over the interrupters on the UNO are only on pins 2 and 3 known as '0' and '1' when dealing with interrupts. If you need 4, you're going to have to upgrade to a mega, or convert the signals to analog so they can all use those two pins.

-disclaimer, I'm a complete noob. I could very well be wrong.

Here's a good link though http://www.engblaze.com/we-interrupt-this-program-to-bring-you-a-tutorial-on-arduino-interrupts/

I'll check that out.

Also noticed that I had the wrong pins to digitalWrite "LOW" for the RightTurn segment. Has been corrected.

It seems that I should somehow be able compare the original 4 digitalReads with "current" digitalReads and either - 1. continue and repeat if there is no change, or stop and jump to the top if there is a change. (Is this an employment of a "state" statement?)

You don't need interrupts, unless you are planning to turn your indicators on and off every microsecond or so.

Just a simple test of the switches will do it. Those delays will have to go, you won't be able to blink multiple LEDs that way. Read this:

In particular further down that page: "Example of flashing lots of LEDs".

Thanks for the reply!
First, I don't know what "a simple test of switches" means. How do I code a "simple test of switches"?
Second, I'm not attempting to blink multiple LEDs. The delays are pauses between LEDs. For example,

digitalWrite (0, HIGH);
digitalWrite (1, HIGH);
digitalWrite (2, HIGH);
digitalWrite (3, HIGH);
delay(500);
digitalWrite (4, HIGH);
delay(500);
digitalWrite (5, HIGH);
delay(1000);
digitalWrite (3, LOW);
digitalWrite (4, LOW);
digitalWrite (5, LOW):

is intended to turn on LEDs 0,1,2,3 at the "same time", wait .5 seconds, turn on LED 4, wait .5 seconds, turn on LED 5, wait 1 second, turn off LEDs 3,4,5 while LEDs 0,1,2 stay on.

Am I missing something?

is intended to turn on LEDs 0,1,2,3 at the "same time", wait .5 seconds, turn on LED 4, wait .5 seconds, turn on LED 5, wait 1 second, turn off LEDs 3,4,5 while LEDs 0,1,2 stay on.

The problem with using delays is your controller sits and spins its wheels until the delay time is over, during which time nothing can happen.
Did you read Nicks link?

Second, I'm not attempting to blink multiple LEDs.

You put on your indicators and then hits the brakes. Won't that blink (or at least, turn on) multiple LEDs?

    digitalWrite (0, HIGH);
    digitalWrite (1, HIGH);
    digitalWrite (2, HIGH);
    digitalWrite (3, HIGH);
    delay(500);
    digitalWrite (4, HIGH);
    delay(500);
    digitalWrite (5, HIGH);
    delay(1000);
    digitalWrite (3, LOW);
    digitalWrite (4, LOW);
    digitalWrite (5, LOW):

That's going to turn into a mess.

How about more like:

const byte BRAKE_LED = 2;
const byte LIGHT_LED = 3;
const byte LEFT_INDICATOR = 4;
const byte RIGHT_INDICATOR = 5;

const byte BRAKE_SWITCH = 6;
const byte LIGHT_SWITCH = 7;
const byte LEFT_INDICATOR_SWITCH = 8;
const byte RIGHT_INDICATOR_SWITCH = 9;

void setup ()
  {
  pinMode (BRAKE_LED, OUTPUT);
  pinMode (LIGHT_LED, OUTPUT);
  pinMode (LEFT_INDICATOR, OUTPUT);
  pinMode (RIGHT_INDICATOR, OUTPUT);

  }  // end of setup

void loop ()
  {
  if (BRAKE_SWITCH == HIGH)
    digitalWrite (BRAKE_LED, HIGH);
  else
    digitalWrite (BRAKE_LED, LOW);
    
  if (LIGHT_SWITCH == HIGH)
    digitalWrite (LIGHT_LED, HIGH);
  else
    digitalWrite (LIGHT_LED, LOW);
  
  delay (500); // make the indicators blink
  
  if (LEFT_INDICATOR_SWITCH == HIGH)
    digitalWrite (LEFT_INDICATOR, !digitalRead (LEFT_INDICATOR));
  else
    digitalWrite (LEFT_INDICATOR, LOW);
  
  if (RIGHT_INDICATOR_SWITCH == HIGH)
    digitalWrite (RIGHT_INDICATOR, !digitalRead (RIGHT_INDICATOR));
  else
    digitalWrite (RIGHT_INDICATOR, LOW);
  }  // end of loop

I don't really like the delay, because it means you would have a 0.5 second delay between hitting the brakes and the brake light coming on, and you could avoid that with a more sophisticated piece of code.

However that's the general idea. Keep it simple. You may have to reverse the tests (ie. make them == LOW) depending on how you have the switches wired up.

Better would be this:

const byte BRAKE_LED = 2;
const byte LIGHT_LED = 3;
const byte LEFT_INDICATOR = 4;
const byte RIGHT_INDICATOR = 5;

const byte BRAKE_SWITCH = 6;
const byte LIGHT_SWITCH = 7;
const byte LEFT_INDICATOR_SWITCH = 8;
const byte RIGHT_INDICATOR_SWITCH = 9;

const unsigned long BLINK_TIME = 500;  // milliseconds

void setup ()
  {
  pinMode (BRAKE_LED, OUTPUT);
  pinMode (LIGHT_LED, OUTPUT);
  pinMode (LEFT_INDICATOR, OUTPUT);
  pinMode (RIGHT_INDICATOR, OUTPUT);

  }  // end of setup

unsigned long lastBlinkTime;

void loop ()
  {
  if (BRAKE_SWITCH == HIGH)
    digitalWrite (BRAKE_LED, HIGH);
  else
    digitalWrite (BRAKE_LED, LOW);
    
  if (LIGHT_SWITCH == HIGH)
    digitalWrite (LIGHT_LED, HIGH);
  else
    digitalWrite (LIGHT_LED, LOW);
  
  if (millis () - lastBlinkTime < BLINK_TIME)
    return;
  lastBlinkTime = millis ();
  
  if (LEFT_INDICATOR_SWITCH == HIGH)
    digitalWrite (LEFT_INDICATOR, !digitalRead (LEFT_INDICATOR));
  else
    digitalWrite (LEFT_INDICATOR, LOW);
  
  if (RIGHT_INDICATOR_SWITCH == HIGH)
    digitalWrite (RIGHT_INDICATOR, !digitalRead (RIGHT_INDICATOR));
  else
    digitalWrite (RIGHT_INDICATOR, LOW);
  }  // end of loop

That uses millis() to see when half a second (or whatever interval you want) is up, and if it isn't skip the part of the code that flashes the indicators. That way the brake light comes on the moment you hit the brakes.

(edit) Fell for one the of things I usually warn about. These lines are wrong:

  if (BRAKE_SWITCH == HIGH)
...
  if (LIGHT_SWITCH == HIGH)
...
  if (LEFT_INDICATOR_SWITCH == HIGH)
...
  if (RIGHT_INDICATOR_SWITCH == HIGH)

They should read:

  if (digitalRead (BRAKE_SWITCH) == HIGH)
...
  if (digitalRead (LIGHT_SWITCH) == HIGH)
...
  if (digitalRead (LEFT_INDICATOR_SWITCH) == HIGH)
...
  if (digitalRead (RIGHT_INDICATOR_SWITCH) == HIGH)

Ok. I see where you're going and will have to digest for bit. However, I don't think you have the desired concept that I intended for the delays. I admit that I am an Arduino infant, but I don't think that I have communicated adequately. Please, if you have time, check out this video that will show the desired result for the indicators (actual delay time to be adjusted).

How to detect a change in ANY of the 4 inputs

First get all the input pins into one variable:-

state = digitalRead(pin1) | (digitalRead(pin2) <<1) | (digitalRead(pin3) << 2) | (digitalRead(pin4) << 3);

Where pin1, pin2 etc, are the pin numbers you read.
Then compare that state variable with what you read last time. If anything has changed then do your stuff.

int state, oldState
void loop(){
state = digitalRead(pin1) | (digitalRead(pin2) <<1) | (digitalRead(pin3) << 2) | (digitalRead(pin4) << 3);
if( oldState != state) {
 // something has changed so do your stuff
}
oldState = state;
}
  • Read the instructions for posting here. Put your code in "code" tags using the little "scroll and brackets" icon. You can go back and modify your posting to make it more readable.

  • What I can see in the code is something that has to do with indicator lights. Please do not not get confused about what "interrupts" in the Arduino are for - your project has nothing whatever to do with interrupts.

  • I see a lot of "numeral == HIGH**|**LOW" comparisons here - that will do absolutely nothing. Neither HIGH nor LOW will ever equal 9, 10 11 or 12.

[/code]

Paul__B:

  • I see a lot of "numeral == HIGH**|**LOW" comparisons here - that will do absolutely nothing. Neither HIGH nor LOW will ever equal 9, 10 11 or 12.

My bad. I posted an amendment.

armysaxman:
Ok. I see where you're going and will have to digest for bit. However, I don't think you have the desired concept that I intended for the delays. I admit that I am an Arduino infant, but I don't think that I have communicated adequately. Please, if you have time, check out this video that will show the desired result for the indicators (actual delay time to be adjusted).

https://www.youtube.com/watch?v=ZSbgvJSrTxc

Ah, I see what you mean. This slightly more complex version does that quite nicely without using any delays. Tested this time. :slight_smile:

const byte BRAKE_LED = 2;
const byte LIGHT_LED = 3;
const byte LEFT_INDICATOR [3] = { 4, 5, 6 };
const byte RIGHT_INDICATOR [3] = { 7, 8, 9 };

const byte BRAKE_SWITCH = A0;
const byte LIGHT_SWITCH = A1;
const byte LEFT_INDICATOR_SWITCH = A2;
const byte RIGHT_INDICATOR_SWITCH = A3;

const unsigned long BLINK_TIME = 150;  // milliseconds

void setup ()
  {
  pinMode (BRAKE_LED, OUTPUT);
  pinMode (LIGHT_LED, OUTPUT);
  for (int i = 0; i < 3; i++)
    pinMode (LEFT_INDICATOR [i], OUTPUT);
  for (int i = 0; i < 3; i++)
    pinMode (RIGHT_INDICATOR [i], OUTPUT);

  pinMode (BRAKE_SWITCH, INPUT_PULLUP);
  pinMode (LIGHT_SWITCH, INPUT_PULLUP);
  pinMode (LEFT_INDICATOR_SWITCH, INPUT_PULLUP);
  pinMode (RIGHT_INDICATOR_SWITCH, INPUT_PULLUP); 
  }  // end of setup

unsigned long lastBlinkTime;
byte leftIndicatorSequence, rightIndicatorSequence;

void doSequence (const byte inputPin, 
                 const byte (& outputPins) [3],
                 byte & sequence)
  {
  
  if (digitalRead (inputPin) == HIGH)  // if switch is on
    {
    switch (sequence++)
      {
      case 0: digitalWrite (outputPins [0], HIGH); break;
      case 1: digitalWrite (outputPins [1], HIGH); break;
      case 2: digitalWrite (outputPins [2], HIGH); break;
      default:
        for (int i = 0; i < 3; i++)
          digitalWrite (outputPins [i], LOW);
        sequence = 0;
        break;
      }  // end of switch
    return;
    }  // end of indicator switch on
    
  // indicator switch is off
  for (int i = 0; i < 3; i++)
    digitalWrite (outputPins [i], LOW);
  sequence = 0;
  
  }  // end of doSequence
  
void loop ()
  {
  if (digitalRead (BRAKE_SWITCH) == HIGH)
    digitalWrite (BRAKE_LED, HIGH);
  else
    digitalWrite (BRAKE_LED, LOW);
    
  if (digitalRead (LIGHT_SWITCH) == HIGH)
    digitalWrite (LIGHT_LED, HIGH);
  else
    digitalWrite (LIGHT_LED, LOW);
  
  if (millis () - lastBlinkTime < BLINK_TIME)
    return;
  lastBlinkTime = millis ();

  // flash indicators
  doSequence (LEFT_INDICATOR_SWITCH, LEFT_INDICATOR, leftIndicatorSequence);
  doSequence (RIGHT_INDICATOR_SWITCH, RIGHT_INDICATOR, rightIndicatorSequence);
  
  }  // end of loop

if (9 == HIGH && 10 == LOW && 11 == LOW && 12 == LOW) { //Brake

Although that was armysaxman's bad. HIGH is defined as 1, so 1 will never be equal to 9. You have to digitalRead that pin. And not like this:

  for (int pinRead = 9; pinRead < 13; pinRead++)  {  //read pins 9 thru 13
  digitalRead (pinRead);

digitalRead returns a value. Your code is discarding it.

Thanks for all of the help and input! It will take me some time to read through it to understand. As I said, I'm VERY new to the wonderful world of coding!

Have a Merry Christmas!!

Thomas499:
I'm no expert, but from what I remember glancing over the interrupters on the UNO are only on pins 2 and 3 known as '0' and '1' when dealing with interrupts. If you need 4, you're going to have to upgrade to a mega, or convert the signals to analog so they can all use those two pins.

-disclaimer, I'm a complete noob. I could very well be wrong.

Good disclaimer!

Every digital and analog pin on the Uno can be used to generate an interrupt from an external signal. It's even possible to use them to generate software interrupts by setting them as output pins and writing to them.

But I could be wrong. :slight_smile:

But I could be wrong. :slight_smile:

No you are not wrong. This is the pin change interrupt mode. This project makes use of that and generates an interrupt from 6 lines.
http://www.thebox.myzen.co.uk/Hardware/Crazy_People.html

But as we said this project does not need interrupts.