Hi, ill try my best to keep this as short as possible.
I'm trying to get an arduino based speedometer for my electric bike working.
This is the code I have written: (ik it is probably poorly written - i only do coding stuff occasionally )
//--------------------------------------------------------------------------------------------//
// ELECTRIC BIKE SPEEDOMETER (KM/H) & ODOMETER //
// Written by Darcy Johnson Dec. 2021 //
//--------------------------------------------------------------------------------------------//
// //
// For Use With/Notes: //
// *ATMega328p Arduino Based Microcontroller (e.g. Arduino Uno) //
// *Nokia Type 5110 Monochrome LCD Display //
// *Hall Effect Sensor //
// *Use of EEPROM for storing total distance (odo.) and total on time. //
// //
//--------------------------------------------------------------------------------------------//
//Adapted RPM Code by James Rovere
//DISPLAY-CONFIGURATION-----------------------------------------------------------------------//
#include "U8glib.h" //Include U8glib Library
// Create display and set pins: (Using Nokia LCD for Arduino)
U8GLIB_PCD8544 u8g(13, 11, 10, 9, 8); // (CLK=13, DIN=11, CE=10, DC=9, RST=8)
//--------------------------------------------------------------------------------------------//
//EEPROM-CONFIGURATION------------------------------------------------------------------------//
//Note: EEPROM is coded to count to 1020km travelled on odo (can add more addr. for more dist.)
#include <EEPROM.h> //Include EEPROM Library
//Addresses we will write to EEPROM with:
//Odo. Addresses:
const int EEPROMaddr1 = 0; //255km block 1
const int EEPROMaddr2 = 1; //255km block 2
const int EEPROMaddr3 = 2; //255km block 3
const int EEPROMaddr4 = 3; //255km block 4
const int EEPROMaddr5 = 4; //0.99km block
//Time Addresses:
const int EEPROMaddr6 = 5; //Ride Hours
const int EEPROMaddr7 = 6; //Ride Minutes
//How often writes to eprom occurs (half e.g. an interval of 10 would equal 20seconds)
const int EEPROMwriteInterval = 10; //Must be a multiple of 2. This x2 is how long it waits.
//--------------------------------------------------------------------------------------------//
//CONFIGURATION-------------------------------------------------------------------------------//
const int wheel_circumference = 2062; //The circumference of the wheel in mm (including tyre)
String unitText = "kph"; //Change if you want to change kph to KPH or something like that.
//--------------------------------------------------------------------------------------------//
float kph = 0;
int speedy;
float value = 0;
float detected = 0;
int rpm;
int oldtime = 0;
int time;
int topspeed = 0; //Top Speed Achieved
float distance; //Total Distance travelled
float newdistance; //Distance travelled in sample time in km
int timepassed; //Time passed to check if odometer write (EEPROM) is due
bool checked; //First check for error in calculation on startup
int decimalwrite;
int hours;
int minutes;
int seconds;
void detection()
{
//Runs everytime the magnet on wheel is detected.
detected = detected + 1;
}
void setup()
{
Serial.begin(9600); //Debug Only
u8g.setRot180(); //Rotate Display by 180 degrees
//LOAD ALL ODO. VALUES FROM EEPROM
int eepromread1 = EEPROM.read(EEPROMaddr1);
int eepromread2 = EEPROM.read(EEPROMaddr2);
int eepromread3 = EEPROM.read(EEPROMaddr3);
int eepromread4 = EEPROM.read(EEPROMaddr4);
float eepromread5 = EEPROM.read(EEPROMaddr5);
float eepromdecimal = eepromread5/100; //Convert EEPROM decimal block (e.g. 12) to decimal (0.12)
distance = eepromread1 + eepromread2 + eepromread3 + eepromread4 + eepromdecimal; //Add all blocks together
//LOAD ALL TIME VALUES FROM EEPROM
int eepromread6 = EEPROM.read(EEPROMaddr6);
int eepromread7 = EEPROM.read(EEPROMaddr7);
hours = eepromread6;
minutes = eepromread7;
Serial.print("DISTANCE EEPROM READ: ");
Serial.println(distance);
Serial.print("DECIMAL EEPROM READ: ");
Serial.println(eepromread5);
Serial.println(eepromdecimal);
checked = false;
attachInterrupt(0, detection, RISING); //Attach Interrupt to Digital Pin 2
}
void loop()
{
delay(2000); // 2 Second Delay
detachInterrupt(0); //Detach Interupt
seconds = seconds + 2;
if (seconds == 60)
{
minutes = minutes + 1;
seconds = 0;
}
if (minutes == 60)
{
hours = hours + 1;
minutes = 0;
}
Serial.println(hours);
Serial.println(minutes);
Serial.println(seconds);
timepassed = timepassed + 2; //INCREASE TIMEPASSED FOR EEPROM WRITE
time=millis()-oldtime; //finds the time
rpm=(detected/time)*60000; //calculates rpm
Serial.println(" ");
Serial.println(" ");
Serial.println(detected);
Serial.print(time);
Serial.println(" ");
Serial.println(" ");
oldtime=millis(); //saves the current time
detected=0;
//Calculate Speed (kph)
int kph = (((wheel_circumference/10)/3.14)*rpm*0.001855);
//Block out first interupt:
//(is sometimes triggered on power up)
if (checked == false)
{
if (kph > 0)
{
kph = 0;
checked = true;
}
else
{
checked = true;
}
}
if (kph > topspeed) //If current speed is greater than past logged topspeed
{
topspeed = kph; //Amends topspeed with new topspeed
}
speedy = ((int)kph);
//Calculate distance travelled in those 2 seconds
/*int sampletime = 2; //Time = 2 seconds
int wheel_circumference_km = wheel_circumference/1000000;
newdistance = wheel_circumference_km*sampletime*rpm; //D = C x T x RPM */
newdistance = ((kph/3.6)*2)/1000; //Convert kph to m/s, m/s x sample time (2s), divide by 1000 (m -> km)
Serial.print("New Distance: ");
Serial.print(newdistance);
Serial.println("km");
if (newdistance > 0)
{
distance = distance + newdistance;
}
Serial.print("TIME: ");
Serial.println(timepassed);
/*Check if EEPROMwriteInterval/2 seconds has passed, if so write
*distance to EEPROM splitting distance into 4 address capable
*of 0-255 per address.*/
if (timepassed == EEPROMwriteInterval) // t/2 IT WAITS EACH TIME FOR EEPROM TO WRITE
{
timepassed = 0; //reset time that has passed for EEPROM write check
//Checking Distance Value to split between addresses:
if (distance > 0 && distance < 255) //Only uses EEPROMaddr1
{
int EEPROMwrite1 = distance;
int EEPROMwrite2 = 0;
int EEPROMwrite3 = 0;
int EEPROMwrite4 = 0;
if (EEPROM.read(EEPROMaddr1) != EEPROMwrite1)
{
EEPROM.write(EEPROMaddr1, EEPROMwrite1);
Serial.println("WRITTEN");
}
if (EEPROM.read(EEPROMaddr1) != EEPROMwrite2)
{
EEPROM.write(EEPROMaddr2, EEPROMwrite2);
Serial.println("WRITTEN");
}
if (EEPROM.read(EEPROMaddr1) != EEPROMwrite3)
{
EEPROM.write(EEPROMaddr3, EEPROMwrite3);
Serial.println("WRITTEN");
}
if (EEPROM.read(EEPROMaddr1) != EEPROMwrite4)
{
EEPROM.write(EEPROMaddr4, EEPROMwrite4);
Serial.println("WRITTEN");
}
} else if (distance > 255 && distance < 510) //Uses EEPROMaddr1 and EEPROMaddr2
{
int EEPROMwrite1 = 255;
int EEPROMwrite2 = distance - 255;
int EEPROMwrite3 = 0;
int EEPROMwrite4 = 0;
if (EEPROM.read(EEPROMaddr1) != EEPROMwrite1)
{
EEPROM.write(EEPROMaddr1, EEPROMwrite1);
Serial.println("WRITTEN");
}
if (EEPROM.read(EEPROMaddr1) != EEPROMwrite2)
{
EEPROM.write(EEPROMaddr2, EEPROMwrite2);
Serial.println("WRITTEN");
}
if (EEPROM.read(EEPROMaddr1) != EEPROMwrite3)
{
EEPROM.write(EEPROMaddr3, EEPROMwrite3);
Serial.println("WRITTEN");
}
if (EEPROM.read(EEPROMaddr1) != EEPROMwrite4)
{
EEPROM.write(EEPROMaddr4, EEPROMwrite4);
Serial.println("WRITTEN");
}
} else if (distance > 510 && distance < 765) //Uses EEPROMaddr1, EEPROMaddr2 and EEPROMaddr3
{
int EEPROMwrite1 = 255;
int EEPROMwrite2 = 255;
int EEPROMwrite3 = distance - (255*2);
int EEPROMwrite4 = 0;
if (EEPROM.read(EEPROMaddr1) != EEPROMwrite1)
{
EEPROM.write(EEPROMaddr1, EEPROMwrite1);
Serial.println("WRITTEN");
}
if (EEPROM.read(EEPROMaddr1) != EEPROMwrite2)
{
EEPROM.write(EEPROMaddr2, EEPROMwrite2);
Serial.println("WRITTEN");
}
if (EEPROM.read(EEPROMaddr1) != EEPROMwrite3)
{
EEPROM.write(EEPROMaddr3, EEPROMwrite3);
Serial.println("WRITTEN");
}
if (EEPROM.read(EEPROMaddr1) != EEPROMwrite4)
{
EEPROM.write(EEPROMaddr4, EEPROMwrite4);
Serial.println("WRITTEN");
}
} else if (distance > 765 && distance < 1020) //Uses all 4 EEPROMaddr
{
int EEPROMwrite1 = 255;
int EEPROMwrite2 = 255;
int EEPROMwrite3 = 255;
int EEPROMwrite4 = distance - (255*3);
if (EEPROM.read(EEPROMaddr1) != EEPROMwrite1)
{
EEPROM.write(EEPROMaddr1, EEPROMwrite1);
Serial.println("WRITTEN");
}
if (EEPROM.read(EEPROMaddr1) != EEPROMwrite2)
{
EEPROM.write(EEPROMaddr2, EEPROMwrite2);
Serial.println("WRITTEN");
}
if (EEPROM.read(EEPROMaddr1) != EEPROMwrite3)
{
EEPROM.write(EEPROMaddr3, EEPROMwrite3);
Serial.println("WRITTEN");
}
if (EEPROM.read(EEPROMaddr1) != EEPROMwrite4)
{
EEPROM.write(EEPROMaddr4, EEPROMwrite4);
Serial.println("WRITTEN");
}
}
//CALCULATE AND STORE DECIMAL OF DISTANCE
int distanceint = distance;
//convert decimals to whole numbers (*100)
float decimals = (distance - distanceint)*100;
//remove decimal places of the new whole number (float -> int)
int decimalwrite = decimals;
/*Serial.print("Decimals: ");
Serial.println(decimals);
Serial.println(decimalwrite);*/
//WRITE TO EEPROM
if (EEPROM.read(EEPROMaddr5) != decimalwrite)
{
EEPROM.write(EEPROMaddr5, decimals);
Serial.println("WRITTEN");
}
//TIME
int EEPROMwrite6 = hours;
int EEPROMwrite7 = minutes;
EEPROM.write(EEPROMaddr6, EEPROMwrite6);
EEPROM.write(EEPROMaddr7, EEPROMwrite7);
/*Serial.println("");
Serial.println(EEPROM.read(EEPROMaddr1));
Serial.println(EEPROM.read(EEPROMaddr2));
Serial.println(EEPROM.read(EEPROMaddr3));
Serial.println(EEPROM.read(EEPROMaddr4));
Serial.println(EEPROM.read(EEPROMaddr5));*/
}
//DEBUG SERIAL
Serial.println("Speed:");
Serial.print(kph);
Serial.println("kph");
Serial.println("RPM:");
Serial.println(rpm);
//DISPLAY STUFF----
u8g.firstPage();
do
{
draw();
}
while(u8g.nextPage());
attachInterrupt(0, detection, RISING); //Reattach Interrupt to Digital Pin 2
}
//DRAW EVERYTHING ON THE DISPLAY
void draw()
{
//Small Font
u8g.setFont(u8g_font_6x10);
//Title Text
u8g.drawStr(0, 7, "DARCYS BIKE v1");
//Top Speed Text
u8g.setPrintPos(4, 35);
String hourUnitText = "h";
String spacer;
if (topspeed < 10)
{
spacer = " ";
} else {
spacer = " ";
}
//Running Time Text
String minuteUnitText = "m";
String topTimerPrint = topspeed + unitText + spacer + hours + hourUnitText + minutes + minuteUnitText;
u8g.print(topTimerPrint);
//Total Distance Text (Odometer)
u8g.setPrintPos(20, 45);
String odoText = "Odo: ";
String odoUnitText = "km";
String odoPrint = String(distance) + odoUnitText;
u8g.print(odoPrint);
//Large Font
u8g.setFont(u8g_font_10x20);
//Speed Text (Speedometer)
if (kph < 10) //Ensures that text is somewhat centred
{
u8g.setPrintPos(21, 23);
}
else
{
u8g.setPrintPos(19, 23);
}
String speedy2 = String(speedy) + unitText;
u8g.print(speedy2);
}
I have setup an ATmega328p IC flashed with the arduino bootloader, 16mhz crystal, etc all on a proto board. I'm using one of those nokia 5110 LCD displays as well. I'm using a generic hall effect sensor with a 10K resistor between 5v and the signal pin. It's using an interrupt pin on the arduino to detect the magnet 'triggering' the hall effect sensor.
The issue is that whenever i surpass around 40kph (it can be +- 10kph really though), the kph displayed jumps around randomly between -2000 and +2000kph. I'm not really sure what's happening. There is quite a bit of vibration >35kph on the bike. Just so you know it does work perfectly fine and as intended up until these speeds.
I understand the code is probably not very clear but i'll really appreciate any help and suggestions and i'll try my best to help if it is not clear.
Code is also attached:
Main.ino (13.1 KB)
I can post pictures if need be.
Thanks!
Darcy