Problem driving a tachometer gauge while listening for interrupts from a circuit

Hello all,

I have been trying to create a diy RPM gauge for a 2 stroke motorcycle. I am not a very good at electricity so I just followed a guide. Bellow are the circuit I used:



My problem is once I start the motor the gauge "works" for a few seconds, then it goes to 0 and stops moving. Occasionally it moves to a few thousand RPM and stops once again. Also the arduino sometimes just freezes. Can anyone please help me?

I have written a few tests, so that I could verify the workings of the gauge and it does work correctly. I have also attached a LED that toggles on a interrupt which works, but freezes for a second sometimes.

Any help would be much appreciated!

The code:

// PIN SETUP
const uint8_t TACHO_OUTPUT_PIN = 9;
const uint8_t SENSOR_INPUT_PIN = 2; // available pins: https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/
const uint8_t TEST_LED = 10;

// SIGNAL INPUT SETTINGS
const int NUM_OF_CYLINDERS = 1;
const int STROKE = 2;
const int SIGNALS_PER_RPM = (NUM_OF_CYLINDERS * STROKE) / 2;

// TACHOMETER SETTINGS
const int NUM_OF_TACHO_CYLINDERS = 8;
const int MAX_RPM = 8000;
const float GAUGE_OFFSET = 0.03; // in percent, the offset of the needle
const int TACH_UPDATE_INTERVAL = 1000;


// GLOBAL VARIABLES
volatile int sparkFireCount = 0;
int lastRpmValue = 0;
unsigned long lastUpdateTime = 0;
//int rpmTone;

void setup()  { 
  //Serial.begin(9600);
  pinMode(TACHO_OUTPUT_PIN, OUTPUT);
  pinMode(TEST_LED, OUTPUT);
  //pinMode(SENSOR_INPUT_PIN, INPUT_PULLUP)
  attachInterrupt(digitalPinToInterrupt(SENSOR_INPUT_PIN), onSensorInterupted, FALLING);

  test2();
  //digitalWrite(TEST_LED, HIGH);
} 

void loop()  { 
  //test2();
  //test1();
  unsigned long elapsedTime = millis() - lastUpdateTime;
  if (elapsedTime <= TACH_UPDATE_INTERVAL)
    return;
  
  //int rpm = sparkFireCount * SIGNALS_PER_RPM;
  // rpm = number of fires * type of engine * elapsed time since last update * to minutes
  int rpm = sparkFireCount * ((1000 / TACH_UPDATE_INTERVAL) * 60) * SIGNALS_PER_RPM;
  
  // we smooth out the rpm value, so it looks more stable
 // rpm = (rpm + lastRpmValue) / 2;

  noInterrupts();
  sparkFireCount = 0;
  //interrupts();
  lastUpdateTime = millis();
  lastRpmValue = rpm;

  setTachometer(rpm);
  interrupts();
}

void setTachometer(int rpm) {
  rpm = constrain(rpm, 0, MAX_RPM);
  //Serial.println(rpm);

  int rpmTone = (double)rpm / 60.0 * NUM_OF_TACHO_CYLINDERS / 2.0;
  rpmTone = rpmTone - rpmTone * GAUGE_OFFSET;

  // we set the RPM output
  // because the signal is downward limited to 30hz, we will disable it if its half of that
  if (rpmTone < 16)
    noTone(TACHO_OUTPUT_PIN);
  else {
    rpmTone = constrain(rpmTone, 30, 100000);
    tone(TACHO_OUTPUT_PIN, rpmTone);
  }
}

void onSensorInterupted() {
  digitalWrite(TEST_LED, !digitalRead(TEST_LED));
  ++sparkFireCount;
}


void test1() {
  setTachometer(0);
  delay(2000);
  setTachometer(1000);
  delay(1000);
  setTachometer(2000);
  delay(1000);
  setTachometer(3000);
  delay(1000);
  setTachometer(4000);
  delay(1000);
  setTachometer(5000);
  delay(1000);
  setTachometer(6000);
  delay(1000);
  setTachometer(7000);
  delay(1000);
  setTachometer(8000);
  delay(3000);
}

void test2() {
  delay(1000);
  for(int i = 0; i<MAX_RPM; ++i) {
    setTachometer(i);
    //delay(1);
  }
  setTachometer(0);
  //delay(5000);
}

And here are some videos of the problem:

Taking the ignition wires this close to the Arduino is likely the reason. The controller faces electrical disturbance.
How exactly does the UNO get its power?

I once, 35 years ago, did the similar to a 4 stroke car and it still worked when removed from the car 10 years later. I remember I used an optocopler. Likely it was situated in the engine bay. I did have an oscilloscope at hand.

The arduino was powered by a 5v phone charger and the 12v rail was powered by a battery pack.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.