Arduino Custom Flasher Box for LED Light Bar

Thread Starter

Blenderite

Joined Feb 2, 2016
16
Hello Guys!!
I am working on my first 'permanent' project. And I could use a little help.

But first, a little back story:
I got two sets of those el cheapo LED light bars off of ebay for free. I got them installed on my truck and was very disappointed with the flash patterns. A normal person would have just got a different flash box off of Amazon, but of course I opt to do things the hard way. I have an Arduino (UNO R3) laying around and in a moment of pure genius decided I should make my own flasher. Since the LED's run off the 12v straight from the car battery, I have a bank of 12 MOSFETs to switch the ground on and off for them. Hopefully that was a good choice. The plan is to have the 12v going into the Vin on the Arduino. Is that ok or should I through in a 5v voltage regulator? Then I bought on of the VKey Voltage Keypad off of SF and am planning on using that so that I can select from 12 different flash patterns.




Here's the problem:
How do I have a flash pattern running while checking to see if the user is pressing one of the other buttons to change the flash pattern?

I am a little stumped here. I hope I don't have to have two Arduino to do this, one monitoring the keypad while the other controls the flash pattern.

Any help/direction is greatly appreciated! Thanks
Blenderite
 

dannyf

Joined Sep 13, 2015
2,197
You can detect the user input in an interrupt. Or put the flashing in a timer interrupt, depending how fast it is.
 

Thread Starter

Blenderite

Joined Feb 2, 2016
16
The plan is to have the keypad being monitored constantly for changes. The flash patterns will be similar to road crew flash patterns, same sort of speed.

Now the example code for the keypad does run on delay(50) so there is a little delay between checks. Which would be better suited for an interrupt?
 

Hutkikz

Joined Jan 29, 2016
9
This can be handled using a switch/case statement.
each case can be a step in your flash pattern and then in loop increment a counter variable to determine which step your at.
that way while the arduino is waiting for the next step it will be free to check for button presses.

Here is a example sketch that flashes 5 lights and 7 patterns, while checking a button and a pot.
I was learning to use port manipulation, just pretend that the PORTD commands are digitalWrites and the PIND is digitalRead.
Code:
/*
Greg's Flasher
  Flasher unit for Greg's antique sign
Version 2  Dec. 2015
\\\\\\\\\\ Lights on Pins 3,4,5,6,7 /////////////////
*/

////////////Output Pins 3,4,5,6,7 \\\\\\\\\\\\\\\\\
const byte potPin = A0;  // Analog Input Pin
byte patternStep, pattern, intervalModified;  // Counters/Flags
unsigned long interval, starTime;  // Timing

void setup()
{
  Serial.begin(9600);
  DDRD = 0xFA;  // Set Pins 1 & 3-7  As Outputs, Pins 0,2 as inputs
  PORTD = 0xFC;  // Set INPUT_PULLUP on button, Initialize Outputs LOW
}


void loop()
{
  pattern += buttonCheck();  // Increment pattern when button pressed
  if (pattern > 7) pattern = 0;
  Serial.println(pattern);
  unsigned long currenTime = millis();
  if (currenTime - starTime >= interval)
  {
  patternStep++;
  starTime += interval;
  interval = potRead();
  intervalModified = 0;
  Serial.println("Time's up");
  }

  switch (pattern) {
  case 0:  // All On
  PORTD |= 0xF8;  // Turn Off All Lights
  Serial.println("0 executed");
  break;
  case 1:  
  followTheLeader();
  Serial.println("Pattern 1");
  break;
  case 2:
  scanner();
  break;
  case 3:
  negScanner();
  break;
  case 4:
  upndown();
  break;
  case 5:
  centerBloom();
  break;
  case 6:
  all();
  break;
  case 7:  // All Off
  PORTD |= 0xF8;  // Turn On All Lights
  break;
  }
}


int potRead()  // Sets Base Interval
{
  int potValue;

  potValue = analogRead(potPin);  // Read Potentiometer
  potValue = map(potValue, 0, 1023, 850, 50);
  return potValue;
}


byte buttonCheck()  // Return positive Once per press
{
  static int isButtonPressed = 0;

  if (!(PIND & (1 << PD2)))  // Read button on pin 2
  {
  isButtonPressed++;  // Increment Debounce variable
  } else {
  isButtonPressed = 0;  // Reset if it bounced
  }

  if (isButtonPressed == 3)  // Debounce Confirmed Threshold
  {
  starTime = millis();  
  patternStep = 0;  
  PORTD = 0x04;  // Turn Off All Lights
  return 1;  // Button Pressed
  } else {
  return 0;  // Button Not Pressed
  }
}


void followTheLeader()  // Light up all the LEDs in turn then shut them off in turn
{
  switch (patternStep) {
  case 0:  // | PATTERN |
  PORTD &= ~0x08;  //  0 0 0 0 1  010
  Serial.println("Step 0");
  break;
  
  case 1:
  PORTD &= ~0x10;  //  0 0 0 1 1  010
  Serial.println("Step 1");
  break;
  
  case 2:
  PORTD &= ~0x20;  //  0 0 1 1 1  010
  Serial.println("Step 2");
  break;
  
  case 3:
  PORTD &= ~0x40;  //  0 1 1 1 1  010
  Serial.println("Step 3");
  break;
  
  case 4:
  PORTD &= ~0x80;  //  1 1 1 1 1  010
  Serial.println("Step 4");
  if (intervalModified == 0)
  {
  interval /= 4;  //  1/4 Interval
  intervalModified = 1;
  }
  break;
  
  case 5:
  PORTD |= 0x08;  //  1 1 1 1 0  010
  Serial.println("Step 5");
  break;
  
  case 6:
  PORTD |= 0x10;  //  1 1 1 0 0  010
  Serial.println("Step 6");
  break;
  
  case 7:
  PORTD |= 0x20;  //  1 1 0 0 0  010
  Serial.println("Step 7");
  break;
  
  case 8:
  PORTD |= 0x40;  //  1 0 0 0 0  010
  Serial.println("Step 8");
  break;
  
  case 9:
  PORTD |= 0x80;  //  0 0 0 0 0  010
  patternStep = 0;
  Serial.println("Step 9");
  break;
  }
}


void centerBloom()  // start in center expand then contract
{
  switch (patternStep)
  {
  case 0:
  PORTD |= 0x20;  // Turns on LED #2 (pin 5)
  break;
  case 1:
  PORTD |= 0x50;  // Turns on LED #1 & LED #3 (pins 4,6)
  break;
  case 2:
  PORTD |= 0xf4;  // Turns on LED #0 & LED#4 (pins 3,7)
  break;
  interval *= 2;
  case 3:
  PORTD &= ~0xf4;  // Turn off LED #0 & LED#4 (pins 3,7)
  break;
  case 4:
  PORTD &= ~0x50;  // Turn off LED #1 & LED #3 (pins 4,6)
  break;
  case 5:
  PORTD &= ~0x20;  // Turn off LED #2 (pin 5)
  patternStep = 0;
  interval *= 2;
  break;

  }
}


void scanner()
{
  switch (patternStep)
  {
  case 0:
  PORTD = 0x10;  // LED #0 OFF(pin 3)& LED #1 ON(pin 4)
  break;
  case 1:
  PORTD = 0x20;  // LED #1 OFF(pin 4)& LED #2 ON(pin 5)
  break;
  case 2:
  PORTD = 0x40;  // LED #2 OFF(pin 5)& LED #3 ON(pin 6)
  break;
  case 3:
  PORTD = 0x80;  // LED #3 OFF(pin 6)& LED #4 ON(pin 7)
  interval *= 2;
  break;
  case 4:
  PORTD = 0x40;  // LED #3 ON(pin 6)& LED #4 OFF(pin 7)
  break;
  case 5:
  PORTD = 0x20;  // LED #2 ON(pin 5)& LED #3 OFF(pin 6)
  break;
  case 6:
  PORTD = 0x10;  // LED #1 ON(pin 4)& LED #2 OFF(pin 5)
  break;
  case 7:
  PORTD = 0x08;  // LED #0 ON(pin 3)& LED #1 OFF(pin 4)
  patternStep = 0;
  break;
  }
}


void negScanner()
{
  switch (patternStep)
  {
  case 0:
  PORTD = 0xf0;
  break;
  case 1:
  PORTD = 0xE8;
  break;
  case 2:
  PORTD = 0xD8;
  break;
  case 3:
  PORTD = 0xB8;
  case 4:
  PORTD = 0x78;
  interval *= 2;
  break;
  case 5:
  PORTD = 0xB8;
  break;
  case 6:
  PORTD = 0xD8;
  break;
  case 7:
  PORTD = 0xE8;
  break;
  case 8:
  PORTD = 0x08;
  interval *= 2;
  patternStep = 0;
  break;
  }
}


void upndown()
{
  switch (patternStep)
  {
  case 0:
  PORTD |= 0x08;
  break;
  case 1:
  PORTD |= 0x10;
  break;
  case 2:
  PORTD |= 0x20;
  break;
  case 3:
  PORTD |= 0x40;
  break;
  case 4:
  PORTD |= 0x80;
  break;
  case 5:
  PORTD &= ~0x80;
  break;
  case 6:
  PORTD &= ~0x40;
  break;
  case 7:
  PORTD &= ~0x20;
  break;
  case 8:
  PORTD &= ~0x10;
  break;
  case 9:
  PORTD &= ~0x08;
  patternStep = 0;
  break;
  }
}
 

Thread Starter

Blenderite

Joined Feb 2, 2016
16
If you follow the link you posted
(https://learn.sparkfun.com/tutorial...p-guide?_ga=1.263780876.1855040054.1449254609)
it has example code for using the keypad. The example simply places a message on your monitor telling which key was pressed. Coding would use the key number variable to select the flash pattern void routine you desire.
Yes, that is what I am doing, but the problem is that I have to constantly monitor that variable to see if it changes. I tried it with simple coding and it 'works', but it could take several attempts to change patterns. You basically have to land the button press between when it checks for any changes in the variable and when it starts the flash pattern. Here is the code that does that:

Code:
#include <VKey.h>

VKey keypad(A1, VKey::FIVE);

int brightness = 0;
int fadeAmount = 225;
int buttonPin = 2;
int buttonState = 0;
int sequence = 0;

int newKey = 0;
int currentKey;

void setup() {
  // initialize digital pin 13 as an output.
  pinMode(13, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(2, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  VKey::eKeynum k;
  if(keypad.checkKeys(k)){
    newKey = k;
  }
  if(newKey != 0){
    if(newKey != currentKey){
      currentKey = newKey;
    }
  }
//---Post Interupt---//
  if(currentKey == 1){
    patternOne();
  }
  if(currentKey == 2){
    patternTwo();
  }
  if(currentKey == 3){
    patternThree();
  }
  if(currentKey == 4){
    patternFour();
  }
  if(currentKey == 5){
    patternFive();
  }
  if(currentKey == 6){
    patternSix();
  }
  if(currentKey == 7){
    patternSeven();
  }
  if(currentKey == 8){
    patternEight();
  }
  if(currentKey == 9){
    patternNine();
  }
  if(currentKey == 10){
    patternTen();
  }
  if(currentKey == 11){
    patternEleven();
  }
//  if(currentKey == 12){
//    patternTweleve();
//  }
// 
}

void patternOne() {
  digitalWrite(7, HIGH);
  digitalWrite(5, HIGH);
  delay(100);
  digitalWrite(7, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, HIGH);
  digitalWrite(4, HIGH);
  delay(100);
  digitalWrite(6, LOW);
  digitalWrite(4, LOW);
  delay(100);
}

void patternTwo() {
  digitalWrite(13, HIGH);
  digitalWrite(9, HIGH);
  digitalWrite(11, HIGH);
  delay(100);
  digitalWrite(13, LOW);
  digitalWrite(9, LOW);
  digitalWrite(11, LOW);
  digitalWrite(10, HIGH);
  digitalWrite(12, HIGH);
  digitalWrite(8, HIGH);
  delay(100);
  digitalWrite(10, LOW);
  digitalWrite(12, LOW);
  digitalWrite(8, LOW);
  delay(100);
}

void patternThree() {
  digitalWrite(3, HIGH);
  delay(100);
  digitalWrite(3, LOW);
  digitalWrite(2, HIGH);
  delay(100);
  digitalWrite(2, LOW);
  delay(100);
}

void patternFour() {
  digitalWrite(3, HIGH);
  digitalWrite(7, HIGH);
  digitalWrite(5, HIGH);
  digitalWrite(13, HIGH);
  digitalWrite(9, HIGH);
  digitalWrite(11, HIGH);
  delay(100);
  digitalWrite(3, LOW);
  digitalWrite(2, HIGH);
  digitalWrite(7, LOW);
  digitalWrite(5, LOW);
  digitalWrite(6, HIGH);
  digitalWrite(4, HIGH);
  digitalWrite(13, LOW);
  digitalWrite(9, LOW);
  digitalWrite(11, LOW);
  digitalWrite(10, HIGH);
  digitalWrite(12, HIGH);
  digitalWrite(8, HIGH);
  delay(100);
  digitalWrite(6, LOW);
  digitalWrite(4, LOW);
  digitalWrite(10, LOW);
  digitalWrite(12, LOW);
  digitalWrite(8, LOW);
  digitalWrite(2, LOW);
  delay(100);
}

void patternFive() {
  digitalWrite(13, HIGH);
  digitalWrite(7, HIGH);
  delay(125);
  digitalWrite(13, LOW);
  digitalWrite(7, LOW);
  delay(125);
  digitalWrite(8, HIGH);
  digitalWrite(12, HIGH);
  delay(125);
  digitalWrite(8, LOW);
  digitalWrite(12, LOW);
  delay(125);
  digitalWrite(11, HIGH);
  digitalWrite(9, HIGH);
  delay(125);
  digitalWrite(11, LOW);
  digitalWrite(9, LOW);
  delay(125);
  digitalWrite(10, HIGH);
  delay(125);
  digitalWrite(10, LOW);
  delay(125);
}

void patternSix() {
  digitalWrite(13, HIGH);
  digitalWrite(7, HIGH);
  delay(500);
  digitalWrite(12, HIGH);
  digitalWrite(8, HIGH);
  delay(500);
  digitalWrite(11, HIGH);
  digitalWrite(9, HIGH);
  delay(500);
  digitalWrite(10, HIGH);
  delay(500);
  digitalWrite(13, LOW);
  delay(50);
  digitalWrite(13, HIGH);
  delay(50);
  digitalWrite(13, LOW);
  delay(50);
  digitalWrite(13, HIGH);
  delay(50);
  digitalWrite(9, LOW);
  delay(50);
  digitalWrite(9, HIGH);
  delay(50);
  digitalWrite(9, LOW);
  delay(50);
  digitalWrite(11, HIGH);
  delay(50);
  digitalWrite(11, LOW);
  delay(50);
  digitalWrite(11, HIGH);
  delay(50);
  digitalWrite(8, LOW);
  delay(50);
  digitalWrite(8, HIGH);
  delay(50);
  digitalWrite(13, LOW);
  digitalWrite(7, LOW);
  digitalWrite(12, LOW);
  digitalWrite(8, LOW);
  digitalWrite(11, LOW);
  digitalWrite(9, LOW);
  digitalWrite(10, LOW);
  delay(500);
}

void patternSeven(){
  digitalWrite(13, HIGH);
  digitalWrite(12, HIGH);
  digitalWrite(11, HIGH);
  delay(100);
  digitalWrite(13, LOW);
  digitalWrite(12, LOW);
  digitalWrite(11, LOW);
  delay(100);
  digitalWrite(13, HIGH);
  digitalWrite(12, HIGH);
  digitalWrite(11, HIGH);
  delay(100);
  digitalWrite(13, LOW);
  digitalWrite(12, LOW);
  digitalWrite(11, LOW);
  delay(100);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
  digitalWrite(9, HIGH);
  delay(100);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW); 
  delay(100);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
  digitalWrite(9, HIGH);
  delay(100);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  delay(100);
}

void patternEight(){
  digitalWrite(13, HIGH);
  digitalWrite(12, HIGH);
  digitalWrite(11, HIGH);
  delay(50);
  digitalWrite(13, LOW);
  digitalWrite(12, LOW);
  digitalWrite(11, LOW);
  delay(50);
  digitalWrite(13, HIGH);
  digitalWrite(12, HIGH);
  digitalWrite(11, HIGH);
  delay(50);
  digitalWrite(13, LOW);
  digitalWrite(12, LOW);
  digitalWrite(11, LOW);
  delay(100);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
  digitalWrite(9, HIGH);
  delay(50);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW); 
  delay(50);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
  digitalWrite(9, HIGH);
  delay(50);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  delay(100);
}

void patternNine(){
  digitalWrite(13, HIGH);
  digitalWrite(12, HIGH);
  digitalWrite(11, HIGH);
  delay(30);
  digitalWrite(13, LOW);
  digitalWrite(12, LOW);
  digitalWrite(11, LOW);
  delay(30);
  digitalWrite(13, HIGH);
  digitalWrite(12, HIGH);
  digitalWrite(11, HIGH);
  delay(30);
  digitalWrite(13, LOW);
  digitalWrite(12, LOW);
  digitalWrite(11, LOW);
  delay(50);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
  digitalWrite(9, HIGH);
  delay(30);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW); 
  delay(30);
  digitalWrite(7, HIGH);
  digitalWrite(8, HIGH);
  digitalWrite(9, HIGH);
  delay(30);
  digitalWrite(7, LOW);
  digitalWrite(8, LOW);
  digitalWrite(9, LOW);
  delay(50);
}

void patternTen(){
  digitalWrite(13, HIGH);
  digitalWrite(7, HIGH);
  delay(250);
  digitalWrite(13, LOW);
  digitalWrite(7, LOW);
  delay(50);
  digitalWrite(12, HIGH);
  digitalWrite(8, HIGH);
  delay(250);
  digitalWrite(12, LOW);
  digitalWrite(8, LOW);
  delay(50);
  digitalWrite(11, HIGH);
  digitalWrite(9, HIGH);
  delay(250);
  digitalWrite(11, LOW);
  digitalWrite(9, LOW);
  delay(50);
  digitalWrite(10, HIGH);
  delay(250);
  digitalWrite(10, LOW);
  delay(50);
}

void patternEleven(){
  digitalWrite(13, HIGH);
  digitalWrite(7, HIGH);
  delay(100);
  digitalWrite(13, LOW);
  digitalWrite(7, LOW);
  delay(50);
  digitalWrite(12, HIGH);
  digitalWrite(8, HIGH);
  delay(100);
  digitalWrite(12, LOW);
  digitalWrite(8, LOW);
  delay(50);
  digitalWrite(11, HIGH);
  digitalWrite(9, HIGH);
  delay(100);
  digitalWrite(11, LOW);
  digitalWrite(9, LOW);
  delay(50);
  digitalWrite(10, HIGH);
  delay(100);
  digitalWrite(10, LOW);
  delay(50);
}

void patternTwelve(){
}
 

dannyf

Joined Sep 13, 2015
2,197
in cases like this, this is the gist of what you do:

1) determine how fast you want to detect the keypad. let's say 10ms. the longer the interval, the less "responsive" the keypad is and the lower the cpu load is.

2) in the adc interrupt, detect if the keypad is pressed -> adc value within a range;
2.a) if you need to debounce the keypad, you may wait for a set pattern to show up.

3) once the adc result has been read, start the next adc;

4) once the keypad is pressed, with or without debounce, process the key press.

5) exit.

With that, your main loop run nothing but your flashing code. Which actually can also be executed from a timer isr as well.
 

Thread Starter

Blenderite

Joined Feb 2, 2016
16
That is lovely and all, however I am not finding any information on an *ANALOG* (ADC) interrupt . I have Googled every combination that I can find. Even looked on the Arduino site. Checked YouTube. Even checked the lawn out front. Zilch.

Does anyone know of a site that has a good explanation of how to code a ADC interrupt?
 

Thread Starter

Blenderite

Joined Feb 2, 2016
16
I am still a little confused as to what exactly I need to use. I would really like to see something in the Arduino reference, cause it actually does a good job explaining stuff.
 
Top