Shift light code (am i doing it right?)

Hi guys, newbie here :confused:
I built a basic shiftlight, ended up using my own design as all the diy ones i found involved buttons and lcd screens and all sorts of jazz. I just want a simple shift light without the BS.

I knocked together the following circuit to intercept the 12v square wave from my tacho and to provide 5v for the Nano and the 2x 8LED-Neo-Pixelsticks (see pic)

I then took the code from u/Pyr0monk3y (if youve ever looked around at diy shift lights his is the Miata one)
I then proceeded to modify the code to try simplify it, remove the unneeded stuff for different night day modes and buttons and so on, and get it working with the 16LEDs with the colours i wanted and RPM frequencies and so on.

Everything works fine, but the code looks a bit sh!#y, there has to be a simpler way?
In the origional there was a line of code that turned off the leds during deceleration, but it also caused a bug that made the LED's flicker. I removed it then the LEDs would turn on at the specified RPM but they would then stay on. So i then set the igfreq value for each LED individually with RGB 0,0,0 to turn them off again.

Anyway im new to this and was hoping you guys could take a look and see if there is a better way to write the code. I mean it works and all, just seems like alot of code just to make some leds light up.

I am thankfull for any help or advice :slight_smile:

revlight_v1.4_test.ino (8.12 KB)

mickymik:
Everything works fine, but the code looks a bit sh!#y, there has to be a simpler way?

Yes, the code has a huge room for improvement, but the problem with improving is, a simpler way to do what? There is no definition anywhere of what it does. You can sit there and see what it's doing but we don't have the hardware.

Good code is somewhat self explanatory, but to try to figure out the program behaviour from this kind of code, is far too tedious to do for free. It's a kind of Mensa puzzle. There are a small minority of programmers that actually relish it as a kind of challenge.

If you can come up with a very good description of what you want the LEDs to do, the kind folks here will probably be willing to help you cobble up a different, proper program from scratch.

Hi, thanks for the reply.

Input:

-The Arduino takes a Square Wave as Input through one of the digital pins.

-The amplitude of the square wave is always the same.

-The frequency of the square wave changes.

Output:
-Digital signal to a 16 pixel LED Neo strip.

Function:

-The LEDs should light up one after another from left to right according to the frequency of the input signal.For example the first led should light up at 130Hz and the next at 136Hz and so on.

-They should also turn off when the frequency drops. For example the first led turns on over 130 Hz and turns off under 130Hz, the second LED should turn on above 136Hz and off under 136Hz, and so on.

-The LEDs should be colored from left to right; green, yellow, orange, red, blue.

-If a threshold is reached (say 250Hz) all the LEDs should blink in blue

-If a second threshold is reached (say 260Hz) all the LEDs should blink in red.

-It should react relatively fast

Here is what it should look like

Also is this the correct place for this topic? Or should I move it to another area of the forum?

Thanks

mickymik:
Also is this the correct place for this topic? Or should I move it to another area of the forum?

Hmmm. This is the "Project Guidance" area. It appears you want guidance on proceeding with your project.

Yep, I would say that fits. :grinning:

Challenge accepted

//Daihatsu K3-VE2 shift light v1.4.

//Another ridiculously good modification by Mick ;)

//Code originally from u/Pyr0monk3y.


//Removed all unneeded code for buttons and different modes ect.

//Modified pixel code for use with 16 pixel strip.

//Individual pixel colour and RPM now adjustable.

//Added notes and instructions for easy modification/adjustment by others.

//Default operating range 3700 to 7050 rpm (green, yellow, orange, red, blue).
//Shift flash @ 7050 to 7500rpm (all blue).
//Overrev flash @ >7500 rpm (all red).

//Default= 4 cylinder engine.
//For use on other engines or for other shift points, rpm frequency needs to be adjusted accordingly.

//Mick`s simplified circuit diagram and additional info avaliable @ https://livetodai.com/t/audruino-shift-light/2504/1
//Original code and circuit diagram avaliable @ https://www.reddit.com/r/arduino/comments/515vsd/my_progressive_shift_light_because_racecar/

//initialize libraries
#include <Adafruit_NeoPixel.h>

#define PIN            6  //LED Data Pin
#define NUMPIXELS      16  //number of leds connected
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

//Progressive lights from 3700 RPM to 7050 RPM, smooth color transition from green to red, then blue.
//shift @7050 until 7500, all flashing blue.
//overrev @>7500, all flashing red.

//to change rpm values change igfreq (frquency values are different depending on no. of cylinders).
//RPM to Frequency chart avaliable @ https://adaptronicecu.com/blogs/modular-instructional-videos/how-to-setup-tacho-on-modular-ecus
//4 cylinder engine, sequential ignition Hz=RPM/30.
//4 Cylinder engine, wasted spark Hz=(RPM/30)x2.

//Set operating range (default=123hz to 235hz = 3700rpm to 7050rpm @ 4 cylinder sequential)

const unsigned int minFrequency = 123; // minimum frequency to begin turning on LEDs
const unsigned int maxFrequency = 235; // maximum frequency in normal range
const unsigned int shiftFrequency = 250; // frequency range from max to shift when shifting should happen

// colors for each pixel when on
const uint32_t tachColor[NUMPIXELS] = {
  Adafruit_NeoPixel::Color(0, 120, 0),
  Adafruit_NeoPixel::Color(0, 120, 0),
  Adafruit_NeoPixel::Color(0, 120, 0),
  Adafruit_NeoPixel::Color(15, 105, 0),
  Adafruit_NeoPixel::Color(30, 90, 0),
  Adafruit_NeoPixel::Color(45, 75, 0),
  Adafruit_NeoPixel::Color(60, 60, 0),
  Adafruit_NeoPixel::Color(75, 45, 0),
  Adafruit_NeoPixel::Color(90, 30, 0),
  Adafruit_NeoPixel::Color(105, 15, 0),
  Adafruit_NeoPixel::Color(120, 0, 0),
  Adafruit_NeoPixel::Color(0, 0, 120),
  Adafruit_NeoPixel::Color(0, 0, 120),
  Adafruit_NeoPixel::Color(0, 0, 120),
  Adafruit_NeoPixel::Color(0, 0, 120),
  Adafruit_NeoPixel::Color(0, 0, 120),
};

/*
   list of frequencies to determine when LEDs get turned on.
   for a given index if the frequency is above this value,
   the LED will be on using the colors above
   otherwise, it will be off.  These steps do not need to
   be linear but must start with minFrequency and not exceed maxFrequency
*/

const unsigned int lightShiftFreq[NUMPIXELS] = {
  minFrequency,
  130,
  137,
  144,
  151,
  158,
  165,
  172,
  179,
  186,
  193,
  200,
  207,
  214,
  221,
  228,
};

int i;
const byte tachPin = 2;

void setup() {
  pixels.begin(); // This initializes the NeoPixel library.
}

unsigned long igfreq;

void loop() {

//  int rpm;
  float ighigh, iglow;
  unsigned long igcal1, igcal2;

  //measure period of tach signal
  ighigh = pulseIn(tachPin, HIGH);
  iglow = pulseIn(tachPin, LOW);

  igcal1 = 1000 / ((ighigh / 1000) + (iglow / 1000));

  //do it again
  ighigh = pulseIn(tachPin, HIGH);
  iglow = pulseIn(tachPin, LOW);

  igcal2 = 1000 / ((ighigh / 1000) + (iglow / 1000));

  //to filter out some noise, we only consider our measurement valid if they are similar in value, we accept the average.
  if ((igcal1 - igcal2) < 8) {
    igfreq = (igcal1 + igcal2) / 2;
  }

  if (igfreq >= minFrequency && igfreq < maxFrequency) {
    // normal operating range
    for ( int i = 0; i < NUMPIXELS; ++i) {
      if (igfreq > lightShiftFreq[i]) {
        pixels.setPixelColor(i, tachColor[i]);
      }
      else {
        pixels.setPixelColor(i, pixels.Color(0, 0, 0));
      }
    }
    pixels.show();
  }
  else if (igfreq >= maxFrequency && igfreq < shiftFrequency) {
    //shift flash
    //default color=blue
    pixels.fill(pixels.Color(0, 0, 120));
    pixels.show();
    delay(20);
    pixels.fill(pixels.Color(0, 0, 0));
    pixels.show();
    delay(20);
  }

  else if (igfreq >= shiftFrequency) {
    //overrev flash
    //default color=red
    pixels.fill(pixels.Color(120, 0, 0));
    pixels.show();
    delay(20);
    pixels.fill(pixels.Color(0, 0, 0));
    pixels.show();
    delay(20);
  }
}

Hi, thanks for the help, really apprecieate it!

Some things i noticed:
when i ran a simulation on tinkercad i noticed the system was not struggling to run the code as it was with mine, seems to run alot smoother.

however,i also noticed with my code it takes about 20ms to react when the frequency increases (LEDs turning on), and about 60ms to react when the frequency decreases (LEDs turning off).

With the new code it takes about 200ms to react on increase and about 900ms to react on decrease.

First of all, why is that?

And secondly,
Is there a way to speed things up a bit?

Also your last edit @ 10:45 doesnt seem to work as "fill" is not difined

Appreciate the support, looking forward to your reply :slight_smile:

Edit:

I uploaded the code and took the car for a drive. The LEDs react fast enough and the lights keep up withthe tacho no problem.

The only bug is the first LED, once on it remains on below the operating range (below 123Hz it should be off)

Otherwise everything is A1

Once again, appreciate the help.

Another update,

the bug seems to be intermittent, sometimes when driving the first LED behaves as expected, and sometimes it stays on.

Any ideas?

Basically, as you slow down, the leds decrease but if it falls below the minimum frequency, it doesn't recheck the lights. This change will fix that

  //if (igfreq >= minFrequency && igfreq < maxFrequency) {
  if (igfreq < maxFrequency) {
    // normal operating range
    //...

Now, no matter how low igfreq goes, it will result in everything being off.

As for your other comments, the code compiles just fine for me with fill defined.

Fantastic!

Yeah the problem with the Fill is something to do with tinkercad when trying to run it in a simulation. Only happens sometimes, dont think it has anything to do with the code.

As mentioned earlier, the code works great in real world. Now with the fix it should be 100% perfect.

It was probably super easy for you but i cant tell you how grateful I am, i really appreciate it.

Not sure how i can return the favour, i can only say if you need any help or advice involving cars feel free to ask, that is my area of expertise.

Thanks again :slight_smile:

So I’ve been driving around with it for a while now and everything is great.

I would like to add a starting sequence so when the engine is started the LEDs all light once up from left to right.

It would be triggered by the frequency input.

When it is first measured (when igfreq changes from 0 to >0) a light sequence runs once.

The LEDs light up one after another from left to right, then turn off again from right to left.

Afterwards the program runs as normal.

If igfreq drops below 0, or the Arduino restarts, the sequence will run again when igfreq changes from 0 to >0 again.

First of all is it possible?
If so, could someone help me with it? @blh64 you did a killer job on the code, maybe you have some ideas for it?

Thanks

mickymik:
So I’ve been driving around with it for a while now and everything is great.

I would like to add a starting sequence so when the engine is started the LEDs all light once up from left to right.

It would be triggered by the frequency input.

When it is first measured (when igfreq changes from 0 to >0) a light sequence runs once.

The LEDs light up one after another from left to right, then turn off again from right to left.

Afterwards the program runs as normal.

If igfreq drops below 0, or the Arduino restarts, the sequence will run again when igfreq changes from 0 to >0 again.

First of all is it possible?
If so, could someone help me with it? @blh64 you did a killer job on the code, maybe you have some ideas for it?

Thanks

Of course it is possible. Give it a try. We help you with your code, not write it for you. Wouldn't the engine starting be the same as power being applied to your arduino and it starting up? Or is it powered all the time from the battery?

Hi, totally understand you want beginners to stand on their own two feet. Im defintly trying, and failing miserably :confused:

So to answer your question, no, the Arduino is powered by KL15 (IGN+) so its on when you turn the ignition on. I would like the sequence to run when the engine starts.
Here is where it gets a little tricky;
When the engine is cranking there is a tacho signal...

So to make the sequence run only when the engine has actually started and not during cranking i would simply define "const unsigned int onFrequency" to a Hz value that represents an engine speed between cranking (ca. 500-600RPM) and idle (ca.800 RPM)

Then just run a code like this:

if (igfreq >= onFrequency && igfreq < minFrequency) {
//start sequence
for ( int i = 0; i < NUMPIXELS; ++i) {
pixels.setPixelColor(i, tachColor*);*

  • pixels.show();*
    but the problem I am having is I dont know what to write here ^^^^ for a sequence...
    Ive spent countless hours on this and the best i can do is the colors light up and stay on until minFrequency is reached, or i can also get them to flash through one after another until minFrequency, but not just run once and stop.
    I have played around with colorWipe and theatreChase trying to get them to work. But its just not happening for me....
    This is why i was asking if it was even possible?
    (Its probably super easy and i'm just STUPID)
    anyway, is there any chance you could give me some pointers?

Best to post one of your attempts.

One thing to try is to add a global bool variable that tracks whether you have run the sequence yet. Check it to see if you should run it and set it when you have.

So to be honest, C++ is waaayyy out of my knowlage area

Anyway here are the solutions I have so far:

  1. if the the digital input is high (the car begins producing a tacho signal) a sequence runs in void setup
void setup() {
  pixels.begin(); // This initializes the NeoPixel library.

  
  float ighigh;
ighigh = pulseIn(tachPin, HIGH);
  
  
  if (ighigh){
    //start sequence
    for ( int i = 0; i < NUMPIXELS; ++i) {
    pixels.setPixelColor(i, tachColor[i]);
      pixels.show();
      delay(200);

  }
 }
}

This however doesn't stop the startup sequence from running during cranking.

I am aiming for the startup sequence to run once the engine actually starts/fires up (the rpm would jump from about 500 up to about 1000)

So another solution i found would be to run the igfreq code also in void startup, seems to work in simulation, but im not sure how it would work irl. Probably not very well as i assume in void setup it would literally measure only once at startup, and not actually measure long enough to know the engine speed is high enough to trigger the start sequence.
Plus it seems like things are starting to get over complicated, and it doesnt seem right that the same code is written twice in two different places. But it still seems like the best option so far?

const unsigned int onFrequency = 23;  //startup sequence, value represents engine speed higher than cranking and lower than idle
const unsigned int minFrequency = 123; // minimum frequency to begin turning on LEDs
const unsigned int maxFrequency = 235; // maximum frequency in normal range
const unsigned int shiftFrequency = 250; // frequency range from max to shift when shifting should happen

//.....//

int i;
const byte tachPin = 2;
unsigned long igfreq;

//...//

void setup() {
  pixels.begin(); // This initializes the NeoPixel library.

  
//  int rpm;
  float ighigh, iglow;
  unsigned long igcal1, igcal2;

  //measure period of tach signal
  ighigh = pulseIn(tachPin, HIGH);
  iglow = pulseIn(tachPin, LOW);

  igcal1 = 1000 / ((ighigh / 1000) + (iglow / 1000));

  //do it again
  ighigh = pulseIn(tachPin, HIGH);
  iglow = pulseIn(tachPin, LOW);

  igcal2 = 1000 / ((ighigh / 1000) + (iglow / 1000));

  //to filter out some noise, we only consider our measurement valid if they are similar in value, we accept the average.
  if ((igcal1 - igcal2) < 8) {
    igfreq = (igcal1 + igcal2) / 2;
  }
  
  
  if (igfreq > onFrequency)
    //start sequence
    for ( int i = 0; i < NUMPIXELS; ++i) {
    pixels.setPixelColor(i, tachColor[i]);
      pixels.show();
      delay(200);

  }
 }

another idea I had is this to run the code in void loop, but i cant figure out how to make it turn off / run just once. I tried adding "pixels.setPixelColor(i, pixels.Color(0, 0, 0));" and "while(1){}" but it seems to stop the whole sketch and make funny business :disappointed_relieved:

if (igfreq > onFrequency){
    //start sequence
    for ( int i = 0; i < NUMPIXELS; ++i) {
    pixels.setPixelColor(i, tachColor[i]);
      pixels.show();
      delay(200);
  
   }
  
 else if (igfreq < maxFrequency) {
    
    // normal operating range
    for ( int i = 0; i < NUMPIXELS; ++i) {
      if (igfreq > lightShiftFreq[i]) {
        pixels.setPixelColor(i, tachColor[i]);
      }
      else {
        pixels.setPixelColor(i, pixels.Color(0, 0, 0));
      }
    }
    pixels.show();
  }

Im sure there is an easier way but im just not great with this stuff. I need guidence :frowning:

Then there is the problem of the actual sequence itsself, how the LEDs light up. I would like (beggers cant be choosers i know) to have the LEDs light up one at a time, in the previously defined colours, from left to right, flash a couple times blue, then turn off one at a time from right to left.
After many many hours, I got as far as making them turn on one at a time from left to right :confused:

None of those things is a complete sketch that somebody and load or compile. Snippets don't help because only you have the entire code. When you make changes, always post the new, complete sketch. It is much easier to help you if you do so.

#include <Adafruit_NeoPixel.h>

#define PIN            6  //LED Data Pin
#define NUMPIXELS      16  //number of leds connected
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

const unsigned int onFrequency = 23;  //startup sequence, value represents engine speed higher than cranking and lower than idle
const unsigned int minFrequency = 123; // minimum frequency to begin turning on LEDs
const unsigned int maxFrequency = 235; // maximum frequency in normal range
const unsigned int shiftFrequency = 250; // frequency range from max to shift when shifting should happen


const uint32_t tachColor[NUMPIXELS] = {
  Adafruit_NeoPixel::Color(0, 120, 0),//green
  Adafruit_NeoPixel::Color(0, 120, 0),
  Adafruit_NeoPixel::Color(0, 120, 0),
  Adafruit_NeoPixel::Color(15, 105, 0),
  Adafruit_NeoPixel::Color(30, 90, 0),
  Adafruit_NeoPixel::Color(45, 75, 0),
  Adafruit_NeoPixel::Color(60, 60, 0),//orange
  Adafruit_NeoPixel::Color(75, 45, 0),
  Adafruit_NeoPixel::Color(90, 30, 0),
  Adafruit_NeoPixel::Color(105, 15, 0),
  Adafruit_NeoPixel::Color(120, 0, 0),//red
  Adafruit_NeoPixel::Color(0, 0, 120),//blue
  Adafruit_NeoPixel::Color(0, 0, 120),
  Adafruit_NeoPixel::Color(0, 0, 120),
  Adafruit_NeoPixel::Color(0, 0, 120),
  Adafruit_NeoPixel::Color(0, 0, 120),
};


const unsigned int lightShiftFreq[NUMPIXELS] = {
  minFrequency,
  130,
  137,
  144,
  151,
  158,
  165,
  172,
  179,
  186,
  193,
  200,
  207,
  214,
  221,
  228,
};

int i;
const byte tachPin = 2;
unsigned long igfreq;






void setup() {
  pixels.begin(); // This initializes the NeoPixel library.

  
//  int rpm;
  float ighigh, iglow;
  unsigned long igcal1, igcal2;

  //measure period of tach signal
  ighigh = pulseIn(tachPin, HIGH);
  iglow = pulseIn(tachPin, LOW);

  igcal1 = 1000 / ((ighigh / 1000) + (iglow / 1000));

  //do it again
  ighigh = pulseIn(tachPin, HIGH);
  iglow = pulseIn(tachPin, LOW);

  igcal2 = 1000 / ((ighigh / 1000) + (iglow / 1000));

  //to filter out some noise, we only consider our measurement valid if they are similar in value, we accept the average.
  if ((igcal1 - igcal2) < 8) {
    igfreq = (igcal1 + igcal2) / 2;
  }
  
  
  if (igfreq > onFrequency)
    //start sequence
    for ( int i = 0; i < NUMPIXELS; ++i) {
    pixels.setPixelColor(i, tachColor[i]);
      pixels.show();
      delay(200);

  }
 }








void loop() {

//  int rpm;
  float ighigh, iglow;
  unsigned long igcal1, igcal2;

  //measure period of tach signal
  ighigh = pulseIn(tachPin, HIGH);
  iglow = pulseIn(tachPin, LOW);

  igcal1 = 1000 / ((ighigh / 1000) + (iglow / 1000));

  //do it again
  ighigh = pulseIn(tachPin, HIGH);
  iglow = pulseIn(tachPin, LOW);

  igcal2 = 1000 / ((ighigh / 1000) + (iglow / 1000));

  //to filter out some noise, we only consider our measurement valid if they are similar in value, we accept the average.
  if ((igcal1 - igcal2) < 8) {
    igfreq = (igcal1 + igcal2) / 2;
  }


 if (igfreq < maxFrequency) {
    
    // normal operating range
    for ( int i = 0; i < NUMPIXELS; ++i) {
      if (igfreq > lightShiftFreq[i]) {
        pixels.setPixelColor(i, tachColor[i]);
      }
      else {
        pixels.setPixelColor(i, pixels.Color(0, 0, 0));
      }
    }
    pixels.show();
 }
  else if (igfreq >= maxFrequency && igfreq < shiftFrequency) {
    //shift flash
    //default color=blue
    pixels.fill(pixels.Color(0, 0, 120));
    pixels.show();
    delay(20);
    pixels.fill(pixels.Color(0, 0, 0));
    pixels.show();
    delay(20);
  }

  else if (igfreq >= shiftFrequency) {
    //overrev flash
    //default color=red
    pixels.fill(pixels.Color(120, 0, 0));
    pixels.show();
    delay(20);
    pixels.fill(pixels.Color(0, 0, 0));
    pixels.show();
    delay(20);
  }

Much easier to work with.... Rather than duplicating all your code in setup() so it only runs once, I introduced a boolean variable that starts out false but gets set to true once the sequence runs so it will never run again

#include <Adafruit_NeoPixel.h>

#define PIN            6  //LED Data Pin
#define NUMPIXELS      16  //number of leds connected
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

const unsigned int onFrequency = 23;  //startup sequence, value represents engine speed higher than cranking and lower than idle
const unsigned int minFrequency = 123; // minimum frequency to begin turning on LEDs
const unsigned int maxFrequency = 235; // maximum frequency in normal range
const unsigned int shiftFrequency = 250; // frequency range from max to shift when shifting should happen

bool hasStartupSequenceRun = false; // only run startup sequence one time

const uint32_t tachColor[NUMPIXELS] = {
  Adafruit_NeoPixel::Color(0, 120, 0),//green
  Adafruit_NeoPixel::Color(0, 120, 0),
  Adafruit_NeoPixel::Color(0, 120, 0),
  Adafruit_NeoPixel::Color(15, 105, 0),
  Adafruit_NeoPixel::Color(30, 90, 0),
  Adafruit_NeoPixel::Color(45, 75, 0),
  Adafruit_NeoPixel::Color(60, 60, 0),//orange
  Adafruit_NeoPixel::Color(75, 45, 0),
  Adafruit_NeoPixel::Color(90, 30, 0),
  Adafruit_NeoPixel::Color(105, 15, 0),
  Adafruit_NeoPixel::Color(120, 0, 0),//red
  Adafruit_NeoPixel::Color(0, 0, 120),//blue
  Adafruit_NeoPixel::Color(0, 0, 120),
  Adafruit_NeoPixel::Color(0, 0, 120),
  Adafruit_NeoPixel::Color(0, 0, 120),
  Adafruit_NeoPixel::Color(0, 0, 120),
};

const unsigned int lightShiftFreq[NUMPIXELS] = {
  minFrequency,
  130,
  137,
  144,
  151,
  158,
  165,
  172,
  179,
  186,
  193,
  200,
  207,
  214,
  221,
  228,
};

const byte tachPin = 2;
unsigned long igfreq;

void setup() {
  pixels.begin(); // This initializes the NeoPixel library.
}

void loop() {

  float ighigh, iglow;
  unsigned long igcal1, igcal2;

  //measure period of tach signal
  ighigh = pulseIn(tachPin, HIGH);
  iglow = pulseIn(tachPin, LOW);

  igcal1 = 1000 / ((ighigh / 1000) + (iglow / 1000));

  //do it again
  ighigh = pulseIn(tachPin, HIGH);
  iglow = pulseIn(tachPin, LOW);

  igcal2 = 1000 / ((ighigh / 1000) + (iglow / 1000));

  //to filter out some noise, we only consider our measurement valid if they are similar in value, we accept the average.
  if ((igcal1 - igcal2) < 8) {
    igfreq = (igcal1 + igcal2) / 2;
  }

  if (hasStartupSequenceRun == false) {
    if (igfreq > onFrequency) {
      //start sequence
      for ( int i = 0; i < NUMPIXELS; ++i) {
        pixels.setPixelColor(i, tachColor[i]);
        pixels.show();
        delay(200);
      }
      hasStartupSequenceRun = true;
      pixels.fill(pixels.Color(0, 0, 0));
      pixels.show();
    }
  }


  if (igfreq < maxFrequency) {

    // normal operating range
    for ( int i = 0; i < NUMPIXELS; ++i) {
      if (igfreq > lightShiftFreq[i]) {
        pixels.setPixelColor(i, tachColor[i]);
      }
      else {
        pixels.setPixelColor(i, pixels.Color(0, 0, 0));
      }
    }
    pixels.show();
  }
  else if (igfreq >= maxFrequency && igfreq < shiftFrequency) {
    //shift flash
    //default color=blue
    pixels.fill(pixels.Color(0, 0, 120));
    pixels.show();
    delay(20);
    pixels.fill(pixels.Color(0, 0, 0));
    pixels.show();
    delay(20);
  }

  else if (igfreq >= shiftFrequency) {
    //overrev flash
    //default color=red
    pixels.fill(pixels.Color(120, 0, 0));
    pixels.show();
    delay(20);
    pixels.fill(pixels.Color(0, 0, 0));
    pixels.show();
    delay(20);
  }
}

blh64:
Rather than duplicating all your code in setup() so it only runs once, I introduced a boolean variable that starts out false but gets set to true once the sequence runs so it will never run again

That makes no sense! :astonished:

If it is only initialisation, it goes in setup().

If you need it more than once, it is a function. :roll_eyes:

Paul__B:
That makes no sense! :astonished:

If it is only initialisation, it goes in setup().

If you need it more than once, it is a function. :roll_eyes:

Sure it does. The OP had copied a large portion of the loop() function and placed it in setup(). Sure, you could make it a function, but one more variable is an equally logical choice.

´Thanks for the help, slowly learning how things are done.
I have a few questions though to help my understanding...

Purely out of intrest, if I ran the following code in setup, as it was before, would it measure the frequency from pin 2 the whole time its turned on? Or would it be a one time event, so it would measure high once and low once then cease to run?

//measure period of tach signal
  ighigh = pulseIn(tachPin, HIGH);
  iglow = pulseIn(tachPin, LOW);

  igcal1 = 1000 / ((ighigh / 1000) + (iglow / 1000));

  //do it again
  ighigh = pulseIn(tachPin, HIGH);
  iglow = pulseIn(tachPin, LOW);

  igcal2 = 1000 / ((ighigh / 1000) + (iglow / 1000));

  //to filter out some noise, we only consider our measurement valid if they are similar in value, we accept the average.
  if ((igcal1 - igcal2) < 8) {
    igfreq = (igcal1 + igcal2) / 2;
  }

The next question I have is what dictates weather the LEDs light up from right to left or left to right?
Is left to right a default of the neopixel strip?

Thanks :slight_smile: