Odometer and trip meter help

Hi all,

I have recently built my own dash for a modified car and would like to make a simple odometer and resetable trip meter to work with a 16x2 lcd screen (if things go well I will add a temp display also).

What I do know is that the 5V pulses the ECU receives are about 4000 per kilometer (will calibrate this later, a lot of japanese cars seem to be similar)...

Something that is important is for the odometer to retain its values after the car has lost power. I did look into the EEPROM wear leveler thing, however I think it may be easier to use a good lithium battery to retain the figures or look into using an SD card with a power down initiation with button battery backup...

I did search to have a look at what was out there, however I found only either Bicycle speedometers or vehicle projects that used hardware that is very different from mine, not to mention finding myself out of depth with the mathmatics...

If anyone could help, it would be greatly appreciated, it would be great to share it so others can have access to it.

Hardware:

stock Duemillonove & Hitachi 16x2 LCD

Vehicle:

1996 Honda Civic VTI-R

Thanks in advance,

Mike

Similar question: Storage of Mileage and Trip info into memory - Storage - Arduino Forum. The opening post might give you an idea for an approach, e.g. by only writing of the speed equals 0.

sterretje,

Thanks for the input, I looked at this video and tested the code in it myself, adding my LCD into the mix and it worked quite well.

Below is what I have come up with so far, the variables and the EEPROM read/ write functions- does this look right?

#include <LiquidCrystal.h> //Include LCD Library
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //DFRobot LCD keypad pinout
#include <EEPROM.h> //Include EEPROM Library

int speedPulse = 0; //declare input variable
int odoCount = 0; //declare variable to be displayed & stored
int tripCount = 1; //declare resetable trip value to be displayed & stored

void setup() {
Serial.begin (9600); //might come in handy when calibrating

lcd.begin(16, 2);
lcd.setCursor(0,0);
lcd.print("Odo:");
lcd.print(0);
lcd.setCursor(0,1);
lcd.print("Trip:");
lcd.print(1);

odoCount = EEPROM.read(0);
EEPROM.write(0,odoCount);
tripCount = EEPROM.read(1);
EEPROM.write(1,tripCount);

Mike

You can not use EEPROM.write to store an integer (using a single statement). EEPROM.write only writes a single byte, an integer is two bytes. So if you use EEPROM.write, you need to write the two bytes separately. There are the functions LOWBYTE and HIGHBYTE that allow you to split the integer into two bytes.

It's easier to use EEPROM.put which can basically take any type of variable.

  EEPROM.put(0, odoCount);
  EEPROM.put(sizeof(odoCount), tripCount);

The first line is similar to your first write; the second line takes the size of the odoCount (2 bytes) into account and will translate to EEPROM.put(2, tripCount); when you compile. Advantage of this is that when you change odoCount to another type (e.g. an unsigned long), the code will automatically scale.

To read it back, you can use EEPROM.get

  EEPROM.get(0, odoCount);
  EEPROM.get(sizeof(odoCount), tripCount);

Thank you for that!
So, if I'm reading this right, one single line EEPROM.put(2,(odoCount), tripCount); is all that is required to write both the odometer and trip values (1 byte each) and if i were to add one more functions like range temp...etc I just need to include an extra byte for each and the respective variable?

I would also like to learn how to configure EEPROM write to only act on a power down, that way I can avoid having to replace the 328 once its EEPROM gives up...

Thanks again, this is a very steep learning curve for me!

Mike

No, you need to write each variable as shown. And your tripCount and odoCount ain't of type byte (in the code that you showed earlier), they are of type int.

The first one is written to e.g. location zero, the second one to location zero plus the size of the previous variable. Or the first one is written to to e.g. location five, the second one to location five plus the size of the previous variable.

The example code that I presented will do the work; where and how you use it depends on your needs.

If you want to have one statement to store everything in one go, you will need to 'combine' the variables in a class or struct and save/retrieve the struct.

@jupiterengineering

When posting code, please use code tags.

Also, please post your entire sketch, so we have a better idea of what's going on.

You don't really intend to use an int for the number of kilometers, do you? If you do, what will you do once you reach 32768 kilometers?

As for wear leveling: I suggest you split the number up into pieces, and then store the pieces.

// Here is the number we want to store: 
unsigned long num = 123456;

// We split it up into parts
// (for example, 123456 would get split up as 12, 34, 56)
byte numHighPart   = num / 10000;
byte numMiddlePart = (num / 100) % 100;
byte numLowPart    = num % 100;

// We store each part separately
EEPROM.update(1, numHighPart);
EEPROM.update(2, numMiddlePart);
// I will use a wear-leveling trick for the low part
EEPROM.update((3 + numMiddlePart), numLowPart);
// Notice that numLowPart is stored in a different location,
// depending on the value of numMiddlePart.
// Notice also that there are 100 possible locations for numLowPart.
// These 100 locations -- locations 3 through 102 -- are now spoken for.

Thanks both for the reply.

I stumbled upon this sketch which is what I need and more.

https://codebender.cc/sketch:269437#Speedometer-Odometer%20Arduino%20Sketch%20by%20ElectricWater.ino

I am going to study this and get back to my own sketch once I learn how to properly use the EEPROM functions as its clear I'm still missing some things.

Thanks for the help so far, I still have a lot to learn.

Mike

jupiterengineering:
I am going to study this and get back to my own sketch once I learn how to properly use the EEPROM functions as its clear I'm still missing some things.

A single EEPROM location can hold one byte.
A byte can hold one number from 0 to 255. It has to be a whole number, no decimals.
If you want to store a number greater than 255 in one byte, too bad! You can't. But if you use two or more bytes, you can.
The trick is to split the number up into parts. Think of how an old-fashioned odometer worked, using wheels. Each wheel by itself could only go from 0 to 9, but with five wheels, you could go all the way up to 99999. That is because each wheel only kept track of one part of the number.

As for actually storing data in the EEPROM, I suggest you use EEPROM.read() and either EEPROM.write() or EEPROM.update().
Reference for these functions:
https://www.arduino.cc/en/Reference/EEPROMRead
https://www.arduino.cc/en/Reference/EEPROMWrite
https://www.arduino.cc/en/Reference/EEPROMUpdate

Also useful for you is the remainder operator (%).
Reference for remainder operator:

Example for division and remainder:

int x = 567;
int y = x / 100;
int z = x % 100;

// now y should be 5 and z should be 67

Hi all,

I have been looking at a few sketches online and came across this one:
can anyone give me some pointers on why the commented lines won't compile?
I have had to manually copy this from a youtuve video as the OP's link to the code is dead...

Thanks in advance,

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);

volatile static double pulse_distance = 0.00025000;

volatile double traveled_distance;
volatile unsigned long counter, avg_speed_divider,dist_pulse_count,all_speed_values;
volatile unsigned int speed, avg_speed,max_speed, distance_count; //distance_count was put here by me as line 69 wouldnt compile


void setup(){
  
  noInterrupts();
  
  lcd.begin(20,4);
  lcd.clear();
  
  TCCR1A=0;
  TCCR1B |=((1<<CS10)| (1 << CS11));
  TIMSK1 |=(1 << TOIE1);
  TCNT1 - 3036;
  
  pinMode(2,INPUT);
  
  attachInterrupt(digitalPinToInterrupt(2),distance_count,FALLING);
  interrupts();
  
void loop();{
  if(millis()/ 500--0);{ //lvalue required as decrement operand
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("DST:");
    lcd.setCursor(5,0);
    lcd.print(traveled_distance);
    
    lcd.setCursor(0,1);
    lcd.print("SPEED");
    lcd.setCursor(7,1);
    lcd.print(speed);
    
    lcd.setCursor(0,2);
    lcd.print("MAX SPEED");
    lcd.setCursor(11,2);
    lcd.print(max_speed);
    
    lcd.setCursor(0,3);
    lcd.print("AVG SPEED");
    lcd.setCursor(11,3);
    lcd.print(avg_speed);
    
  }
  
  ISR(TIMER1_OVF_vect){  //expected unqualified-id before string constant
    counter++;
    if(counter>3){
      speed = pulse_distance*dist_pulse_count*3600;
      
      if(speed > 3){
        avg_speed_divider++;
        avgSpeed();
        maxSpeed();
      }
      dist_pulse_count = 0;
      counter=0;
    }
    TCNT1=3036;
  }
  
  void distance_count(){
    dist_pulse_count++;
    teaveled_distance += pulse_distance;
  }
  
  void maxSpeed(){
    if(speed > max_speed) max_speed = speed;
  }
  void avgSpeed(){
    all_speed_values += speed;
    avg_speed = all_speed_values / avg_speed_divider;
  }
}

It would be easier of you posted the errors as they show in the output window (complete).

Anyway, -- should be ==
And I think that the second is because loop() is missing a closing }

Just a passing thought: If you can access the gear selector you could arrange to save to EEPROM only when going into Park. This would eliminate storing values at every stop light/sign/traffic backup. I'd think this, combined with wear leveling, would put the number of write cycles well under the rated 100,000 cycles. If this is true, you could dispense with the complication and additional components (read potential failure points) of an external memory.

.02

jupiterengineering:
Hi all,

I have been looking at a few sketches online and came across this one:
can anyone give me some pointers on why the commented lines won't compile?
I have had to manually copy this from a youtuve video as the OP's link to the code is dead...

It appears that you are simply throwing stuff at the wall and seeing what sticks.
You need to make more of an effort to understand things.

And it is not good to have too much faith in floats. Especially with what you're doing.
My guess is that whoever wrote that code lost sight of the fact that floats are only good to so many digits.

Great idea, however mine is manual so I guess I could apply that idea to the hand brake instead!

dougp:
Just a passing thought: If you can access the gear selector you could arrange to save to EEPROM only when going into Park. This would eliminate storing values at every stop light/sign/traffic backup. I'd think this, combined with wear leveling, would put the number of write cycles well under the rated 100,000 cycles. If this is true, you could dispense with the complication and additional components (read potential failure points) of an external memory.

.02

jupiterengineering:
Great idea, however mine is manual so I guess I could apply that idea to the hand brake instead!

That occurred to me but I thought "Who drives a manual any more?" :smiley:

Someone who does not like flappy paddles :wink: