#include <LiquidCrystal.h>
#include <EEPROM.h>
// THIS DOES NOT KEEP TIME, AND HAS NO WAY OF KEEPING TIME! THIS CODE DOES NOT SUPPORT TIME AS A WAY OF KNOWING HOW LATE IT IS IN A DAY!
LiquidCrystal lcd(3, 4, 5, 6, 7, 8);
/*
A0 - exit (left)
A1 - enter (right)
A2 - up
A3 - down
*/
// ↓↓↓ Configs ↓↓↓
unsigned int wheelCircum = 2194; // wheel circumference in millimeters (changeable in settings)
byte configh = 16; // abbbbbbb, a → unit, (0 - km/h, 1 - mi/h,),, b → 7-bit number (number of seconds before speed zeroes itself)
byte configl = 50; // low byte of configs, one 8-bit number (refresh time in hundredths of a second)
int zerotime = 0; // number of seconds before speed gets zeroed out
byte units = 0; // kilometers ( + per hour) as default
byte mover = 0;
// ↑↑↑ Configs ↑↑↑
float time = 1000000.00;
unsigned long present = 0;
unsigned long present2 = 0;
unsigned long present4 = 0;
unsigned long past2 = 0;
unsigned long past4 = 0;
unsigned long past5 = 0;
unsigned long ridetime = 0; // total ride time in ms (will not count first 10 wheel rotations to get stable data)
unsigned long ridetime2 = 0; // total ride time in seconds (will not count first 10 wheel rotations to get stable data)
float kmph = 0;
float kmphShown = 0;
float kmphmax = 0; // maximum speed
float mph = 0;
float mphmax = 0;
float dist = 0;
float velocity = 0;
float maxvel = 0;
String veldelim = "";
String distdelim = "";
float km = 0;
float mi = 0;
float intermid = 0;
float intermid2 = 0;
float intermid3 = 0;
float intermid4 = 0;
float intermid5 = 0;
unsigned long count = 0;
unsigned long count2 = 0;
int isinmenu = 0;
int page = 0;
int subpage = 0;
int arwhorpos = 0; // horizontal position of arrow in number editing
unsigned int arwvertpos = 0; // arrow vertical position in menu item selection
int incrementer = 1;
void setup() {
int iswritten = 0;
EEPROM.get(0, iswritten);
if(iswritten <= 2) {
EEPROM.put(0, 4);
EEPROM.put(2, wheelCircum);
EEPROM.write(4, configh);
EEPROM.write(5, configl);
} else {
EEPROM.get(2, wheelCircum);
configh = EEPROM.read(4);
configl = EEPROM.read(5);
}
units = configh & 128;
zerotime = configh & 127;
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(2, INPUT_PULLUP); // Magnet Sensor
pinMode(A0, INPUT_PULLUP);
pinMode(A1, INPUT_PULLUP);
pinMode(A2, INPUT_PULLUP);
pinMode(A3, INPUT_PULLUP);
delay(250);
lcd.begin(20, 4);
delay(250);
lcd.print("New and improved");
lcd.setCursor(0, 1);
lcd.print("Bicycle speedometer");
lcd.setCursor(0, 2);
lcd.print("With more features!");
lcd.setCursor(0, 3);
lcd.print("Now has menus!");
delay(3000);
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Very adjustable!");
lcd.setCursor(0, 1);
lcd.print("So many settings!");
lcd.setCursor(0, 2);
lcd.print("A great improvement");
lcd.setCursor(0, 3);
lcd.print("over the old version");
attachInterrupt(digitalPinToInterrupt(2), zeroing, FALLING);
delay(3200);
lcd.clear();
}
void zeroing () {
count = count + 1;
time = present2 - past2;
past2 = present2;
count2 = 0;
ridetime = ridetime + time;
}
void loop() {
if((!(units))) {
velocity = kmphShown;
veldelim = "km/hr";
distdelim = "km";
maxvel = kmphmax;
dist = km;
}
if(units) {
velocity = mph;
veldelim = "mi/hr";
distdelim = "mi";
maxvel = mphmax;
dist = mi;
}
if(isinmenu < 2 && digitalRead(A1) == LOW) { // if we are less than 3 menus deep and enter is pressed
delay(250);
isinmenu = isinmenu + 1;
}
if(isinmenu > 0 && digitalRead(A0) == LOW) {
delay(250);
if(isinmenu <= 1) {
EEPROM.put(2, wheelCircum);
configh = configh & 128;
configh = configh | zerotime;
EEPROM.write(4, configh);
EEPROM.write(5, configl);
}
isinmenu = isinmenu - 1;
}
if(isinmenu == 1) {
arwvertpos = arwvertpos % 4;
if((!(digitalRead(A3)))) {
delay(250);
arwvertpos = arwvertpos + 1;
}
if((!(digitalRead(A2)))) {
delay(250);
arwvertpos = arwvertpos - 1;
}
}
if(isinmenu == 2) {
switch(arwvertpos) {
case 0:
if((!(digitalRead(A3) && digitalRead(A2)))) {
delay(250);
units = units + 1;
units = units % 2;
if(units) {
configh = configh | 128;
} else {
configh = configh & 127;
}
}
break;
case 1:
if(!(digitalRead(A2))) {
delay(250);
wheelCircum = wheelCircum + incrementer;
}
if(!(digitalRead(A3))) {
delay(250);
wheelCircum = wheelCircum - incrementer;
}
if(!(digitalRead(A1))) {
arwhorpos = arwhorpos + 1;
arwhorpos = arwhorpos % 4;
delay(250);
}
break;
case 2:
if(!(digitalRead(A2))) {
delay(250);
zerotime = zerotime + incrementer;
}
if(!(digitalRead(A3))) {
delay(250);
zerotime = zerotime - incrementer;
}
if(!(digitalRead(A1))) {
arwhorpos = arwhorpos + 1;
arwhorpos = arwhorpos % 4;
delay(250);
}
break;
case 3:
if(!(digitalRead(A2))) {
delay(250);
configl = configl + incrementer;
}
if(!(digitalRead(A3))) {
delay(250);
configl = configl - incrementer;
}
if(!(digitalRead(A1))) {
arwhorpos = arwhorpos + 1;
arwhorpos = arwhorpos % 4;
delay(250);
}
break;
}
}
if(present - past5 > (configl * 10)) {
lcd.clear();
past5 = present;
if(isinmenu == 1) {
lcd.print(" System of units "); // row 1
lcd.print(" Zeroing time "); // row 3
lcd.print(" Wheel circumference"); // row 2
lcd.print(" LCD Refresh time "); // row 4
lcd.setCursor(0, arwvertpos);
lcd.print(">");
}
if(isinmenu == 2) {
switch(arwvertpos) {
case 0:
lcd.print(" Measurement units: ");
lcd.setCursor(1, 2);
if((!(units))) {
lcd.print("Metric (km, /hr)");
} else {
lcd.print("Imperial (mi, /hr)");
}
break;
case 1:
if(wheelCircum >= 1000) {mover = 3;}
if(wheelCircum < 1000 && wheelCircum >= 100) {mover = 4;}
if(wheelCircum < 100 && wheelCircum >= 10) {mover = 5;}
if(wheelCircum < 10) {mover = 6;}
lcd.setCursor(0, 0);
lcd.print("Wheel circumference:");
lcd.setCursor(mover, 2);
lcd.print(wheelCircum);
lcd.setCursor((arwhorpos + 3), 3);
lcd.write(94);
lcd.setCursor(9, 2);
lcd.print("millimeters");
break;
case 2:
if(zerotime >= 1000) {mover = 3;}
if(zerotime < 1000 && zerotime >= 100) {mover = 4;}
if(zerotime < 100 && zerotime >= 10) {mover = 5;}
if(zerotime < 10) {mover = 6;}
lcd.setCursor(0, 0);
lcd.print("Zeroing time:");
lcd.setCursor(mover, 2);
lcd.print(zerotime);
lcd.setCursor((arwhorpos + 3), 3);
lcd.write(94);
lcd.setCursor(9, 2);
lcd.print("seconds");
break;
case 3:
if(configl >= 1000) {mover = 1;}
if(configl < 1000 && configl >= 100) {mover = 2;}
if(configl < 100 && configl >= 10) {mover = 3;}
if(configl < 10) {mover = 4;}
lcd.setCursor(0, 0);
lcd.print("LCD Refresh time:");
lcd.setCursor(mover, 2);
lcd.print(configl);
lcd.setCursor((arwhorpos + 1), 3);
lcd.write(94);
lcd.setCursor(6, 2);
lcd.print("1/100ths of 1s");
break;
}
}
if((!(isinmenu))) {
lcd.setCursor(0, 0);
lcd.print("Speed: ");
lcd.print(velocity);
lcd.setCursor(15, 0);
lcd.print(veldelim);
lcd.setCursor(0, 1);
lcd.print("Trip: ");
lcd.print(dist);
lcd.setCursor(18, 1);
lcd.print(distdelim);
lcd.setCursor(0, 2);
lcd.print("MaxSPD: ");
lcd.print(maxvel);
lcd.setCursor(15, 2);
lcd.print(veldelim);
lcd.setCursor(0, 3);
lcd.print("Time:");
lcd.print(ridetime2);
lcd.setCursor(13, 3);
lcd.print("Seconds");
}
}
/*
lcd.print();
lcd.setCursor(, );
*/
switch(arwhorpos) {
case 0:
incrementer = 1000;
break;
case 1:
incrementer = 100;
break;
case 2:
incrementer = 10;
break;
case 3:
incrementer = 1;
break;
}
ridetime2 = ridetime / 1000;
if (count <= 9) {
ridetime = 0;
}
mph = kmphShown / 1.609344;
mphmax = kmphmax / 1.609344;
mi = km / 1.609344;
present = millis();
present2 = millis();
present4 = millis();
if (kmphmax <= kmph) {
kmphmax = kmph;
}
intermid5 = wheelCircum * count;
km = intermid5 / 1000000;
intermid = 1000 / time;
intermid2 = intermid * wheelCircum;
intermid3 = intermid2 * 3600;
intermid4 = intermid3 / 1000000;
kmph = intermid4;
if (present4 - past4 >= 1000) {
count2 = count2 + 1;
past4 = present4;
}
if (count2 <= zerotime - 1) {
kmphShown = kmph;
}
if (count2 >= zerotime) {
kmphShown = 0;
}
}