Motorcycle Data Monitoring project ( need guidance )

dc42:
Is it time to do X yet? If so, do X, and calculate and record when you need to do X again.
Is it time to do Y yet? If so, do Y, and calculate and record when you need to do Y again.

I'd suggest a small change to that. Rather than recording the time you need to do X again, record the time you did X. Deciding whether it's time to do Foo then consists of:

unsigned long currentMillis= millis();
if((currentMillis - lastFooMillis) > fooInterval)
{
    lastFooMillis = currentMillis;
    // do X ...
}

This way deals with timer overflow without any special logic. (Thanks to the many old hands here who have pointed this technique out.)

I am having a little problem with the RPM part.... When the engine stops the RPM is not returning to 0...The last value read by the RPM circuit is kept displayed.... I know that I have to do some sort of lcd.clear() command.. But the thing is that, I do not want the RPM part to me cleared fully.. I would like to display 0 when the engine is off..
I am posting the full code...

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 9, 8);
const int analoginput = 0;
const int tempPin = 1;
float vout = 0.0;
int value = 0;
float R1 = 1000.0;    // !! resistance of R1 !!
float R2 = 470.0;     // !! resistance of R2 !!
float vin = 0.0;
const int ignitionPin = 2;
const int ignitionInterrupt = 0;
const unsigned int pulsesPerRev = 1;

long VpreviousMillis = 0;          // Voltage refresh rate
long Vinterval = 300;

long RPMpreviousMillis = 0;        // RPM refresh rate
long RPMinterval = 200;

long TemppreviousMillis = 0;       // Temperature refresh rate
long Tempinterval = 200;

long printpreviousMillis = 0;       // RPM refresh rate
long printinterval = 400;

unsigned long lastPulseTime = 0;
unsigned long rpm = 0;

void ignitionIsr()
{
  unsigned long now = micros();
  unsigned long interval = now - lastPulseTime;
  if (interval > 2000)
  {
     rpm = 60000000UL/(interval * pulsesPerRev);
     lastPulseTime = now;
  }  
}


void setup()
{
  lcd.begin(16,2);
  lcd.setCursor(3, 0);
  lcd.print("Royal");
  lcd.setCursor(7, 1);
  lcd.print("Enfield");
  delay(3000);
  lcd.clear();
  
  pinMode(analoginput, INPUT);
  pinMode(ignitionPin, INPUT);
  attachInterrupt(ignitionInterrupt, &ignitionIsr, FALLING);
}

void loop()
{
  /**************************************************************/ 
  /*************** THIS PART IS FOR VOLTAGE *********************/
  /**************************************************************/
  
   unsigned long VcurrentMillis = millis();
   if(VcurrentMillis - VpreviousMillis > Vinterval) {
     VpreviousMillis = VcurrentMillis;
  
   
 value = analogRead(analoginput);      // read the value on analog input
 vout= (value * 5.0)/1024.0;           // voltage coming out of the voltage divider
 vin = vout * ((R1 + R2)/R2);          // voltage to display
 
   
 lcd.setCursor(0,0);
 lcd.print(vin, 1);   //Print float "vin" with 1 decimal
 lcd.print("V ");

 
   }
   
 /*************************************************************/
 /*************** THIS PART IS FOR RPM ************************/
 /*************************************************************/
 
    unsigned long RPMcurrentMillis = millis();
   if(RPMcurrentMillis - RPMpreviousMillis > RPMinterval) {
     RPMpreviousMillis = RPMcurrentMillis;
   
  noInterrupts();
  unsigned long rpmToDisplay = rpm;     // take a copy with interrupts disabled in case it changes
  interrupts();
  
      unsigned long printcurrentMillis = millis();
   if(printcurrentMillis - printpreviousMillis > printinterval) {
     printpreviousMillis = printcurrentMillis;
     
  if (rpmToDisplay >= 1000)
  {
    lcd.setCursor(7, 0);
    lcd.print("RPM");
    lcd.print(rpmToDisplay/1000);
    lcd.print(',');
    lcd.print((char)(((rpmToDisplay/100) % 10) + '0'));
    lcd.print((char)(((rpmToDisplay/10) % 10) + '0'));
    lcd.print((char)((rpmToDisplay %10) + '0'));    
  }
  else
  {
    lcd.setCursor(7, 0);
    lcd.print("RPM");
    lcd.print(rpmToDisplay);
    lcd.print("   ");
  }
  }
   }
 
 /*************************************************************/
 /************** THIS PART IS FOR TEMPERATURE *****************/
 /*************************************************************/ 
 
   unsigned long TempcurrentMillis = millis();
    if(TempcurrentMillis - TemppreviousMillis > Tempinterval) {
          TemppreviousMillis = TempcurrentMillis;
  
  float temp = analogRead(tempPin);
  temp = temp * 0.48828125;
  lcd.setCursor(0, 1);
  lcd.print(temp, 0);
  lcd.print((char)223);
  lcd.print("C");
  
  
}
}

Is it that I will have put a condition like..

when there will be interrupts on pin 2 print RPM else print 0...??

You need to use a timeout to detect when RPM pulses are not coming any more. Something like this:

...
unsigned long lastPulseTime = 0;
volatile uint8_t rpmTimeout = 0;
const uint8_t initialTimeout = 5;

volatile unsigned long rpm = 0;

void ignitionIsr()
{
  unsigned long now = micros();
  unsigned long interval = now - lastPulseTime;
  if (interval > 2000)
  {
     rpm = 60000000UL/(interval * pulsesPerRev);
     lastPulseTime = now;
     rpmTimeout = initialTimeout;
  }  
}

...
   
 /*************************************************************/
 /*************** THIS PART IS FOR RPM ************************/
 /*************************************************************/
 
   unsigned long RPMcurrentMillis = millis();
   if(RPMcurrentMillis - RPMpreviousMillis > RPMinterval)
   {
     RPMpreviousMillis = RPMcurrentMillis;
   
     lcd.setCursor(7, 0);
     lcd.print("RPM");
     if (rpmTimeout == 0)
     {
        lcd.print("0   ");
     }
     else
     {
       --rpmTimeout;
       noInterrupts();
       unsigned long rpmToDisplay = rpm;     // take a copy with interrupts disabled in case it changes
       interrupts();
       if (rpmToDisplay >= 1000)
       {
         lcd.print(rpmToDisplay/1000);
         lcd.print(',');
         lcd.print((char)(((rpmToDisplay/100) % 10) + '0'));
         lcd.print((char)(((rpmToDisplay/10) % 10) + '0'));
         lcd.print((char)((rpmToDisplay %10) + '0'));    
       }
       else
       {
         lcd.print(rpmToDisplay);
         lcd.print("   ");    
       }
    }
 }
 
 /*************************************************************/
 /************** THIS PART IS FOR TEMPERATURE *****************/
 /*************************************************************/ 
 
...

Adjust the value of the constant initialTimeout to get it going to 0 at the right point.

I used your code, It works fine...

Now the problem is that I am unable to set the print interval time...

I am attaching the code where you can see that I have commented out the refresh rate code for the RPM print... If I use that code then your modification for the 0 is not working...

/*      unsigned long printcurrentMillis = millis();
   if(printcurrentMillis - printpreviousMillis > printinterval) {
     printpreviousMillis = printcurrentMillis;
     */
  if (rpmToDisplay >= 1000)
  {
    //lcd.setCursor(7, 0);
    //lcd.print("RPM");
    lcd.print(rpmToDisplay/1000);
    lcd.print(',');
    lcd.print((char)(((rpmToDisplay/100) % 10) + '0'));
    lcd.print((char)(((rpmToDisplay/10) % 10) + '0'));
    lcd.print((char)((rpmToDisplay %10) + '0'));    
  }
  else
  {
    //lcd.setCursor(7, 0);
    //lcd.print("RPM");
    lcd.print(rpmToDisplay);
    lcd.print("   ");
  }
  }

So in what other way can I set the interval for the led refresh rate for the RPM...??

Looks like you forgot to attach the code.

Why are you trying to introduce that code when you already have this code:

   unsigned long RPMcurrentMillis = millis();
   if(RPMcurrentMillis - RPMpreviousMillis > RPMinterval)
   {
     RPMpreviousMillis = RPMcurrentMillis;
...

which does more or less the same thing? btw the timeout code I suggested relies on that piece of code being there, so that the line "--rpmTimeout;" only gets executed at intervals of RPMinterval. If it gets executed too often, the timeout will happen too quickly

Ok ..I got you...

So how will the set the time for the RPM printing refresh rate...??

Now another thing which I am unable to understand is

in this code void ignitionIsr

void ignitionIsr()
{
  unsigned long now = micros();
  unsigned long interval = now - lastPulseTime;
  if (interval > 2000)
  {
     rpm = 60000000UL/(interval * pulsesPerRev);
     lastPulseTime = now;
  }  
}

What does this mean 60000000UL...??

Joy:
Ok ..I got you...

So how will the set the time for the RPM printing refresh rate...??

Surely RPMinterval determines the RPM refresh rate? Unless you are doing something else with the calculated RPM as well as displaying it, you don't need to fetch the RPM more often than you display it.

Joy:
What does this mean 60000000UL...??

That's the constant sixty million, with a note to the compiler ("UL" suffix) that we want it treated as having type "unsigned long".

I asked about this part

What does this mean 60000000UL...??

because now I am trying to work on the Speedometer code...
So i was going through the RPM code as it will me almost the same thing except the RPM is calculated in minuites and the Speed will be calculated in hours...

So will I have to use this line in the code...??

60000000UL

...??

For the speedo, if you only want the speed rounded down to the nearest km/h, then I suggest you calculate it as (C * 3600UL)/t where C is the wheel circumference in mm and t is the interval between pulses in microseconds.

Again there will be a mystery for me... how did you get 3600UL..??

Joy:
Again there will be a mystery for me... how did you get 3600UL..??

The wheel is rotating at 1000000/t revs per second, where t is the pulse interval in microseconds. So the revs per hour are (60 * 60 * 1000000)/t. The distance travelled per hour is (60 * 60 * 1000000 * C)/t mm per hour. Dividing by 1000000 to convert mm to km gives (3600 * C)/t. We want the calculation done in unsigned long mode, hence the UL suffix.

Please check this code for the speedo...:stuck_out_tongue:

#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 9, 8);
int kmph;
const int odometerPin = 3;
const int odometerInterrupt = 1;

const float wheelCircumference = 2035;      // wheel circumference in km
const unsigned int HallPulsesPerRev = 1;

unsigned long lastHallPulseTime = 0;
int Speed = 0;

void speedo()
{
  unsigned long now = micros();
  unsigned long interval = now - lastHallPulseTime;
  if (interval > 2000)
  {
   kmph = (wheelCircumference * 3600UL)/interval;
     
          lastHallPulseTime = now;
  }  
}

void setup()
{
  lcd.begin(16,2);
  pinMode(odometerPin, INPUT);
  attachInterrupt(odometerInterrupt, &speedo, FALLING);
}

void loop()
{
  lcd.setCursor(0, 0);
  lcd.print(kmph);
}

I think i have made a silly mistake in the void speedo... :stuck_out_tongue:

Does it work?

  • I would declare 'kmph" as "volatile unsigned int" rather than "int".
  • You have declared a variable "speed" which is not used.
  • You will need to implement a timeout mechanism, similar to the one for RPM, to handle the speed dropping to zero.
  • If then hall sensor has an open-collector output (e.g. US1881), then unless you have an external pullup resistor for the Hall sensor, you will need to digitalWrite a high to that pin in setup() to enable the internal pullup resistor.

Otherwise, it looks OK to me.

Please check this now...
I have added the code to bring speedo to 0 when the bike has stopped..

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

volatile unsigned int kmph;
const int odometerPin = 3;
const int odometerInterrupt = 1;

const float wheelCircumference = 2035;      // wheel circumference in km
const unsigned int HallPulsesPerRev = 1;

unsigned long lastHallPulseTime = 0;
volatile uint8_t speedTimeout;
const uint8_t initialTimeout = 5;

void speedo()
{
  unsigned long now = micros();
  unsigned long interval = now - lastHallPulseTime;
  if (interval > 2000)
  {
   kmph = (wheelCircumference * 3600UL)/interval * HallPulsesPerRev;
     
          lastHallPulseTime = now;
          speedTimeout = initialTimeout;
  }  
}

void setup()
{
  lcd.begin(16,2);
  pinMode(odometerPin, INPUT);
  attachInterrupt(odometerInterrupt, &speedo, FALLING);
}

void loop()
{
  lcd.setCursor(0, 0);
     
     if (speedTimeout == 0)
     {
        lcd.print("0    ");
     }
     else
     {
       --speedTimeout;
       lcd.print(kmph);
     }
}

The last code which you corrected I was not using this HallPulsesPerRev = 1;
So now I have added this to the calculations here..

kmph = (wheelCircumference * 3600UL)/interval * HallPulsesPerRev;

Is it alright..??

Another question is
What is this part doing..??

if (interval > 2000)

Doing the calculation every 2000 microseconds...??

And if I would like to set the led update rate for the speed will changing the timeout par do the job..??
Please show once where to change...??

Joy:
Another question is
What is this part doing..??

if (interval > 2000)

Doing the calculation every 2000 microseconds...??

That was included in the ISR for the ignition sensor, to allow for possibly getting multiple pulses per ignition instead of just one. You shouldn't need it for the RPM sensor.

That was included in the ISR for the ignition sensor, to allow for possibly getting multiple pulses per ignition instead of just one. You shouldn't need it for the RPM sensor.

Shouldn't need this for RPM sensor or Hall Sensor...??

Some mistakes I found in my code...Please check them and correct them if I am wrong...

const float wheelCircumference = 2035;      // wheel circumference in km

Does not have to be a float..

unsigned long now = micros();

I think millis will do the job as wheel revs will not be as high as the RPM

 kmph = (wheelCircumference * 3600UL)/interval;

here 2035*3600 is a thirteen digits long, and my friend says UL can hold up to 10 digits...:stuck_out_tongue:
So he suggested me this

kmpm=(circumference * 60L)/interval;
 kmph=(kmpm * 60);