I have built a bike computer, I'm implementing a couple of hall sensors to calculate wheel and crank rpm and subsequently calculate the speed, distance and cadence on a tiny Nokia 5110 display.
Problem 1:
I need some help to calculate average speed achieved over a trip.
So I know if I divide the total distance traveled by the total time taken to cover the distance, I get the average speed.
What I don't know is how I can calculate the time taken to cover the distance.
Problem 2:
The display indicates a certain speed and cadence when the bicycle is moving and the pedals are cranked. But, when the pedals are not being cranked, the cadence indicator does not zero and shows the last calculated value.
Same goes for the speed indicator, when the bike comes to a stand still, the display does not show zero, but shows the last calculated value.
I do have a clue as to what's causing this, but I'm unsure about how to fix it.
I believe, since the hall sensor pulses are being read by the microcontroller on an interrupt based algorithm that measures the time intervals between interrupts, the code infinitely measures the time interval until the next interrupt and the indicator is stuck in the last computed value.
/*Display*/
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
/* Software SPI:
pin 7 - Serial clock out (SCLK)
pin 6 - Serial data out (DIN)
pin 5 - Data/Command select (D/C)
pin 4 - LCD chip select (CS)
pin 8 - LCD reset (RST) */
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 8);
/*Wheel*/
float wheelDiameter = 660.00; // In millimeters
float wheelSpeed;
float distance;
float rpmWheel;
volatile byte revWheel;
unsigned long timeWheel;
/*Cadence*/
int rpmCrank;
volatile byte revCrank;
unsigned long timeCrank;
/*Button*/
byte button;
byte state;
byte oldButton = 0;
byte buttonPin = 12;
void setup() {
Serial.begin (9600);
/*Display*/
display.begin();
display.clearDisplay();
/*Wheel*/
attachInterrupt(0, wheelCounter, RISING);
revWheel = 0;
rpmWheel = 0;
timeWheel = 0;
distance = 0;
/*Cadence*/
attachInterrupt(1, crankCounter, RISING);
revCrank = 0;
rpmCrank = 0;
timeCrank = 0;
}
void loop() {
/*Sensor*/
hallSense ();
/*Display*/
displayContrast ();
displayPage1 ();
/*Print to serial monitor*/
//printVal ();
}
void hallSense () {
/*Wheel*/
if (revWheel >= 1) {
detachInterrupt(0);
rpmWheel = 60000.0 / (millis() - timeWheel) * revWheel;
wheelSpeed = (rpmWheel * wheelDiameter * 3.141 * 60) / 1000000;
timeWheel = millis();
revWheel = 0;
attachInterrupt(0, wheelCounter, RISING);
}
/*Cadence*/
if (revCrank >= 1) {
detachInterrupt(1);
rpmCrank = 60000.0 / (millis() - timeCrank) * revCrank;
timeCrank = millis();
revCrank = 0;
attachInterrupt(1, crankCounter, RISING);
}
}
/*Wheel*/
void wheelCounter()
{
revWheel++;
distance = distance + (wheelDiameter * 3.141 / 1000000); // In kilometers
}
/*Cadence*/
void crankCounter()
{
revCrank++;
}
/*Button [unused]*/
void displayPage () {
button = digitalRead(buttonPin);
if (button && !oldButton)
{
if (state == 0)
{
displayPage1 ();
state = 1;
}
else
{
displayPage2 ();
state = 0;
}
oldButton = 1;
}
else if (!button && oldButton)
{
oldButton = 0;
}
}
/*Display*/
void displayContrast () {
short potVal = map(analogRead(A7), 0, 1023, 0, 127);
display.setContrast(potVal);
}
void displayPage1 () {
display.clearDisplay();
display.setTextColor(BLACK);
display.setCursor(0, 0);
display.print("Speed:");
display.print(wheelSpeed);
display.setCursor(0, 10);
display.print("Trip :");
display.print(distance);
display.setCursor(0, 20);
display.print("Average:");
display.print(rpmCrank);
display.setCursor(0, 30);
display.print("Cadence:");
display.print(rpmCrank);
display.display();
}
void displayPage2 () { // [UNUSED]
}
/*Serial monitor
void printVal () {
Serial.print("RPM= ");
Serial.print(rpmWheel);
Serial.print ("\t");
Serial.print ("Km= ");
Serial.print(distance);
Serial.print ("\t");
Serial.print("Cadence= ");
Serial.println(rpmCrank);
}*/