Trip computer again

It's time to go forward with fuel consumption.

I managed to display instant fuel consumption in a hour and per 100 km, but i am struggling with average fuel consumption in 100 km.

Fuel consumption is in byte 2 and 3 and it is in microlitres.
Roll over should be somewhere 32767, when value is about that 65536 then it goes to back ~ 32000 and i wonder why it does not go back to zero.

I tried to make it with same principle as johnwasser advised to do with distance counter, but no success.

If i am not badly wrong this does not tell average consumption,
trip average consumption = 100 * instant consumption in hour / kilometers

It need to do like this: Average = 100 * fuel used / km.
So it is necessary to store used fuel somehow first.

With this it it add newFuel value to totalFuelUsed which is not correct because newFuel is too small value if comparing to fuelNow.

double fuelCountLitres;
double totalFuelUsed;


void loop() {

if (rxId == 0x480) {
  
      static uint16_t lastFuel = 0;
      uint16_t fuelNow = (uint16_t)rxBuf[3] << 8;
      fuelNow |= rxBuf[2];
      uint16_t newFuel = fuelNow - lastFuel;

          Serial.print("fuel_now: ");
          Serial.println(fuel_now);
          Serial.print("newFuel:" );
          Serial.println(newFuel);
          Serial.print("lastFuel: " );
          Serial.println(lastFuel);
          Serial.print("totalFuelUsed: ");
          Serial.println(totalFuelUsed);
          
      if (newFuel > 32767)
    {
      newFuel = 0;
    }

      totalFuelUsed += newFuel;
    
      lastFuel = fuel_now;

      fuelCountLitres = totalFuelUsed / 1000000;
  }
}

fuelCountLitres should be same as totalFuelUsed until 32767 is reached, newFuel should go to zero, and litres should store to fuelCountlitres but does not happen correctly.

if (rxId == 0x480) {
     
      static uint16_t lastFuel = 0;
      uint16_t fuel_now = (uint16_t)rxBuf[3] << 8;
      fuel_now |= rxBuf[2];
      double newFuel = fuel_now;
      
      fuelCountLitres = newFuel / 1000000;

          Serial.print("fuel_now: ");
          Serial.println(fuel_now);
          Serial.print("newFuel:" );
          Serial.println(newFuel);
          //Serial.print("lastFuel: " );
          //Serial.println(lastFuel);
          Serial.print("fuelCountLitres: " );
          Serial.println(fuelCountLitres);
          Serial.print("totalFuelUsed: " );
          Serial.println(totalFuelUsed);
          
      if (newFuel >= 32767)
    {
        totalFuelUsed += fuelCountLitres;
        newFuel = 0;
   }
21:45:27.930 -> fuel_now: 32912
21:45:27.930 -> newFuel:32912.00
21:45:27.930 -> fuelCountLitres: 0.03
21:45:27.930 -> totalFuelUsed: 0.03
21:45:28.566 -> fuel_now: 33032
21:45:28.566 -> newFuel:33032.00
21:45:28.566 -> fuelCountLitres: 0.03
21:45:28.566 -> totalFuelUsed: 0.07
21:45:29.175 -> fuel_now: 33150
21:45:29.175 -> newFuel:33150.00
21:45:29.175 -> fuelCountLitres: 0.03
21:45:29.175 -> totalFuelUsed: 0.10

newFuel is a local variable (and only known inside the if). Everytime that you go through loop() and the if (rxId == 0x480) evaluates to true, your variable is recreated and contains fuel_now.

if i want to store litres to variable, how i prevent it incrementing value when litres does not change?

totalFuelUsed += fuelCountLitres 

I want to store litres before roll over, it happens when litres are 0,06 then it start counting from 0.
If litres are for example 0,01 then totalFuelUsed has something like 0,04 and when litres change from 0,01 to 0,02 then it keeps adding that 0,02 to totalFuelUsed 0,04+0,02+0,02... Again when litres change to 0,03 there is already much more in totalFuelUsed. How to prevent this?

I wonder why it didn't work.


double FuelCountLitres;
uint32_t TotalFuelUsed;  // Fuel used in microliters

void loop()
{
  if (rxId == 0x480)
  {
    static uint16_t lastFuel = 0;  // Make it global
    uint16_t fuelNow = (rxBuf[3] << 8) | rxBuf[2];
    if (lastFuel == 0)  // Probably the first sample.
      lastFuel = fuelNow;

    uint16_t newFuel = fuelNow - lastFuel;

    TotalFuelUsed += newFuel;

    Serial.print("lastFuel: ");
    Serial.println(lastFuel);
    Serial.print("fuelNow: ");
    Serial.println(fuelNow);
    Serial.print("newFuel:");
    Serial.println(newFuel);
    Serial.print("TotalFuelUsed: ");
    Serial.println(TotalFuelUsed);

    lastFuel = fuelNow;

    // Convert from microliters to liters:
    FuelCountLitres = TotalFuelUsed / 1000000.0;

    Serial.print("FuelCountLitres: ");
    Serial.println(FuelCountLitres, 3);
  }
}

Thanks, already better but it jumps from 0,06 liters to 0,09 when fuelNow roll over and i wonder that why it start from ~32000.

It looks like the top bit is always 1 and is not part of the value. The counting starts at 32768 and rolls over after 65535.

Just throw away that bit and you should get correct results.

    uint16_t fuelNow = ((rxBuf[3] << 8) | rxBuf[2]) & 0x7FFF;
    if (lastFuel == 0)  // Probably the first sample.
      lastFuel = fuelNow;

    uint16_t newFuel = (fuelNow - lastFuel) & 0x7FFF;
1 Like

Many thanks, it works!. Now just need to put this together with a trip meter.

To the next problem...
I tried to understand from other posts how to avoid that: invalid operands of types 'double' and 'int' to binary 'operator& '.
Fuel consumption is in double variable, so, should i send that to dash app in 4 bytes?

buf[0] = ((Trip1Fc  & 0xff);
buf[1] = ((Trip1Fc >> 8) & 0xff);
buf[2] = ((Trip1Fc >> 16) & 0xff);
buf[3] = ((Trip1Fc >> 32) & 0xff);

This won't work because 'Trip1Fc' is in double variable?
I want decimal points to that value.

if it's a 'double' that means that it is a double-long so that would be 8 bytes, but i think it will just be an 'unsigned long'

and then it would be like

buf[0] = ((Trip1Fc  & 0xff);
buf[1] = ((Trip1Fc >> 8) & 0xff);
buf[2] = ((Trip1Fc >> 16) & 0xff);
buf[3] = ((Trip1Fc >> 24) & 0xff);  // >> 24 not >> 32 

Probably no much sense in this, but i separated trip meter 1 from general fuel consumption calculations, so can reset trip1.

void tripComputer(){

    //Fuel consumption
       trip1FuelConsumption = (100 * FuelCountLitresTrip1) / trip1;

       static double lastTrip1Fuel = 0;
       if (lastTrip1Fuel == 0)  
        lastTrip1Fuel = FuelCountLitres;

        double newTrip1Fuel = FuelCountLitres - lastTrip1Fuel;
        FuelCountLitresTrip1 += newTrip1Fuel;

        lastTrip1Fuel = FuelCountLitres;

       if (trip1 == 0){
        trip1FuelConsumption = 0;
       }

//tripmeter
        trip1 = DistCountKmTrip1;
       
       static uint16_t lastTrip1Km = 0;
       if (lastTrip1Km == 0) 
        lastTrip1Km = previousKiloMeters;

        uint16_t newTrip1Km = previousKiloMeters - lastTrip1Km;
        DistCountKmTrip1 += newTrip1Km;

        lastTrip1Km = previousKiloMeters;


 //Average speed
  unsigned long timeNow = millis();
  
  double timeElapsed = timeNow - timeLast;

  averageTrip1Speed = trip1 / timeElapsed * 3.6;

  timeLast = timeNow; 
} 

With this it is sent to app, but fuel consumption and average speed values fluctuate fast there. For example fc value goes back and forth 45-50 and very fast.

 // build 8th CAN frame, trip1 & avg speed
  buf[0] = (trip1 & 0xff);
  buf[1] = (trip1 >> 8 & 0xff);
  buf[2] = averageTrip1Speed;
  buf[3] = (0xff);
  buf[4] = (0xff);
  buf[5] = (0xff);
  buf[6] = (0xff);
  buf[7] = (0xff);

  // write 8th CAN frame to serial
  SendCANFrameToSerial(07, buf);


// build 9th CAN frame, fuel consumption
  memcpy(buf, &trip1FuelConsumption, 4);
  
  // write 9th CAN frame to serial
  SendCANFrameToSerial(08, buf);

In XML:

<frame id="3207">
		<value targetId="311" offset="0" length="2"></value> <!--Trip1-->
		<value name="Trip1 average speed" offset="2" length="1"></value> 
	</frame>
  
	<frame id="3208">
		<value name="Trip1 fuel consumption" offset="0" length="4" float="true"></value> 
		<value name="Trip2 fuel consumption" offset="4" length="4" float="true"></value> 
	</frame>

Because there is no target IDs for fuel consumption and average speed, need to name own, then can map these in dash app.
I get values to text gauges, but fc and avg speed fluctuate fast for some reason.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.