Motorcycle Speedometer problem

Hello All,
I tried to make digital speedometer using Uno,Hall effect sensor,TM1637 and and MAX7219. It is worked correctly when the engine is not started. When the engine is started, it is worked like RPM meter (Even when not connected the sensor ). I think that is using sense of ignition pulse.Please help. Here is my code

#include <Arduino.h>
#include <TM1637Display.h>
#include <LEDDisplayDriver.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <EEPROM.h>
#include <Wire.h>
#include <util/atomic.h>

//===Max=====
#define DIN_PIN 3
#define CS_PIN 4
#define CLK_PIN 5
// Module connection pins (Digital Pins)
#define CLK 6
#define DIO 7

#define PIN_HALL_SPEED_SENSOR 2

void setup() {
Serial.begin( 115200 );
Serial.print( "Initialization complete\n" );
DDRD = B01111011;
ReedMileage();
SpeedPulseCounterSetup();
}

void loop() {
SpeedPulseCounterLoop();
}

int counter = 0;
unsigned long mileage = 0;
unsigned long oldMileage = 0;
static int lastKMPHDisplayed = -1;
static int lastMileageDisplayed = -1;

TM1637Display display1637(CLK, DIO);
LEDDisplayDriver display(DIN_PIN, CLK_PIN, CS_PIN, true, 8); // With 8 digits===Max=====

void writeData(int address, long number)
{
if((number >> 24)!=(oldMileage >> 24)) {
EEPROM.write(address, (number >> 24) & 0xFF);}
if((number >> 16)!=(oldMileage >> 16)) {
EEPROM.write(address + 1, (number >> 16) & 0xFF);}
if((number >> 8)!=(oldMileage >> 8)) {
EEPROM.write(address + 2, (number >> 8) & 0xFF); }
EEPROM.write(address + 3, number & 0xFF);
}

long readData(int address)
{
return ((long)EEPROM.read(address) << 24) +
((long)EEPROM.read(address + 1) << 16) +
((long)EEPROM.read(address + 2) << 8) +
(long)EEPROM.read(address + 3);
}

void ReedMileage(){
mileage = readData(100);
oldMileage=mileage;
}

void SpeedPulseCounterSetup() {
// Hall Speed Sensor interrupt setup
pinMode( PIN_HALL_SPEED_SENSOR, INPUT );
attachInterrupt( digitalPinToInterrupt( PIN_HALL_SPEED_SENSOR ), hallSpeedInterruptHandler, RISING );

// Set up the 7 segment display, default address
display1637.setBrightness(0x02);
display.setBrightness(0x02);
}

#define DISTANCE_PER_PULSE_IN_KM 0.0004625f // wheel circumference 1.85 meters, 4 Pulses per Round)
#define MICROSECONDS_PER_HOUR 3600000000.0f // 60 minutes * 60 seconds * 1,000,000 microseconds

volatile unsigned long lastPulseTimeUS = 0; // When the last pulse was read via micros()
volatile unsigned long lastPulseLengthUS = 0; // The smoothed pulse length, for use by the main loop

void hallSpeedInterruptHandler()
{
// - Compute the pulse length, filtered to smooth out noise and timing inaccuracies
unsigned long now = micros();
lastPulseLengthUS = now - lastPulseTimeUS;
lastPulseTimeUS = now;

Serial.print( lastPulseLengthUS ); // For test lastPulseLength
Serial.print( "\n" );

counter++;
if(counter>=217 ) {
mileage++;
writeData(100, mileage);
delay(1);
counter=0;
}
}

static int lastMPHDisplayed = -1;
static unsigned long lastMPHUpdateTime = 0; // The last time we updated the display

#define MPH_REFRESH_RATE 500 // How frequently we check for a new speed to display (1/2 second)

void SpeedPulseCounterLoop() {

// If not a lot of time has passed, just return. We don't want to spend all our
// time displaying the speed.
unsigned long now = millis();
if( now - lastMPHUpdateTime < MPH_REFRESH_RATE )
return;

lastMPHUpdateTime = now;

// Make local copies of variables changed by interupts
unsigned long _lastPulseTimeUS, _lastPulseLengthUS;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
_lastPulseTimeUS = lastPulseTimeUS;
_lastPulseLengthUS = lastPulseLengthUS;
}

// See if we're stopped
if( _lastPulseTimeUS + 500000 < micros() ) {
// We're stopped (no pulses in the last 1/2 second); clear out the speeds
_lastPulseTimeUS=micros();
_lastPulseLengthUS = 0;
}

// Microsecond version
float pulseLengthInHours = ((float)_lastPulseLengthUS) / MICROSECONDS_PER_HOUR;
int newKMPH = (int)(DISTANCE_PER_PULSE_IN_KM / pulseLengthInHours );

if( lastKMPHDisplayed != newKMPH ) {
if( newKMPH == 0 ) {
display1637.showNumberDec(0, false);
} else {
display1637.showNumberDec(newKMPH, false);
}
lastKMPHDisplayed = newKMPH;
}
if( lastMileageDisplayed != mileage ) {
display.showNumWithPoint(long(mileage),1);
lastMileageDisplayed=mileage;
}
}

Read the forum guidelines to see how to properly post code and some information on how to get the most from this forum.
Use the IDE autoformat tool (ctrl-t or Tools, Auto format) before posting code in code tags.

You can go back and fix your original post by highlighting the code and clicking the </> in the menu bar.
code tags new

Post a schematic of the wiring. Include all components, their part numbers and/or values and all power supplies.

Post photos of the wiring.

The more information that we have the faster and better help you can get.

How can you tell ? Are you pushing the bike ?

That means that you have noise from the alternator of the GNd line (and the power line as well)
You will have to filter your power supply lines. Start with a few diodes. 1 Fly-back (between GND and V+ of the bike, cathode to V+ of the bike. On the power input, put a Diode from V+ of the bike to V+ of the supply of the Arduino (cathode to the arduino) and put a trimming coil between GND of the arduino and GND on the bike (another diode there may also work) Then put a fair size capacitor between all that (470uF should be enough). Put your own to-220 package 7805 regulator, and put another capacitor of about 100uF on the 5v rail and use the UNO's 5v to power the board.
Since you have power consuming parts like TFT or OLED screen using 5v, you may have to increase the capacitor sizes.
Any external part that you connect to the UNO should also be separated from the noise of the alternator using diodes with the cathode to GND (or if you drive relays with a NPN transistor this is also OK, as long as it is a 1 way street from the CPU & component to GND)

Hello Deva_Rishi,
Thanks your advise. As I understood, the problem is not in power line. Normally I use filtered power line with 7805 regulator. I tested using external battery power.same problem. As i said before, It is worked correctly when the engine is not started and on my table. Not only that, I am using PIC based speedometer since 10 years. It is worked correctly even now.
Actually my case is - I had to use two PIC circuit for Speedometer and mileage meter. Its need more space. So I wanted to reduce it and I tried this.
I think that the Uno board sensitive to ignition pulse. How can I fixed this? Thanks

Here is PCB
PCB

Well it is not the power spikes (which i still suspect when i see your PCB) then only magnetic interference can cause this, and well yes a 328P and probably any AVR MCU (actually pretty much all electronics but hey) is sensitive to magnetic fields that can be created by the coil charging and dsicharging for the ignition, and the obvious answer is 'shielding' Put the whole thing in metal box.
I have had experience with a Pro-mini that i had mounted near a dimpack that cause interference on the UART, partly beacuse it was mounted upside down and the shielding on the PCB was not in between the dimpack and the MCU anymore.
Ignition actually causes a spike on the GND line, so that side of the power line needs to be shielded, and on your PCB it isn't. a 7805 also doesn't filter power spikes out very effectively.
Add the 3 diodes i recommended (1 flyback, a 1N4148 will suffice, and 2x a 1N4007 or 1N4001 or equivalent and increase the size of the 100nF capacitor to 100uF (or just add one)
Actually just add this to you circuit
Power Filter
If your PCB is 2 layer, you could use copper-fill on the bottom. Connected to GND or VCC, and in this case VCC would be better.

So clearly there is nothing wrong with the code.

Actually let me add this little bit. If you connect a line for a tacho (ready made from the shop) . The data line is connected the the GND side of the coil.
Oh yes and an Alternator can throw out spikes above 40 volts, so you probably should keep that in mind for the capacitor. 50v at least. And so the 7805 may not filter all of that out. AVR MUC's are quite sturdy though and quite usable for automotive.

Dear Deva,
I checked Putting the whole thing in metal box as you said. But there is no success.
So, I changed interrupt to Pin change interrupt (PCINT18). Then solved then problem. I don't know what the reason for that. But some pulses occurred by magnetic interference come from hall sensor. Do you have a idea to prevent the unwanted pulses coming from hall sensor?

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