Fuel gauge smoothing help

Hey guys. I'm working on retrofitting my bike from just a low fuel warning light (which doesn't work anyway) to a float level guage from a later year of the same bike. I have the fuel sender and I have a gauge working on a 16x2 LCD. What I want is to smooth the readings so the gauge isn't all over the place going down the road.

I had implemented it in code but the problem is the gauge starts off form the bottom as the readings and average pile up. Also for some reason with the smoothing once the values started to pile up my LCD display would go all screwy and every portion would fill up with a full square and random divide signs and space invader characters would pop in and out.

Here's the code as I have it now which works perfectly, just with no smoothing.

/*
 *LCD Fuel Gauge for Honda SuperHawk 16L Tank
 *http://www.superhawkforum.com/forums/technical-discussion-28/fuel-gauge-mods-33365/
 *Basic concept found at http://www.pddnet.com/articles/2014/01/designing-arduino-fuel-gauge-warning-lights
 *Code by Will Lyon 7/26/2015. Contact: will.lyon12584@gmail.com
 *Uses the LcdBarGraph1.5 Library for Arduino. Author:  Balázs Kelemen. Contact: prampec+arduino@gmail.com
 *LCDBarGraph library can be found here: http://playground.arduino.cc/Code/LcdBarGraph#Download
 *Designed to be used with the Adafruit 16x2 RGB LCD (both negative and positive work properly)
 *5V to fuel sensor Grn/Blk
 *Fuel sensor Gry/Blk to Analog 0 with 10k resistor to GND
*/

#include <LiquidCrystal.h> // Include Liquid Crystal library
#include <LcdBarGraph.h> // Include LCD Bar Graph library

byte lcdNumCols = 16; // 16 columns in the 16x2 LCD
byte sensorPin = A0; // Fuel float sensor 5V input with 10k resistor to GND and Analog 0

LiquidCrystal lcd(7, 8, 9, 10, 11, 12); // LCD connected to digital 7-12
LcdBarGraph lbg(&lcd,16,0,1); // Parameters for LCD bar grah library
const int redPin = 5; // Red LCD backlight on Digital pin 5
const int grnPin = 6; // Green LCD backlight on Digital pin 6

void setup() {
  Serial.begin(9600); // Initialize communication with PC via serial monitor
  pinMode(redPin, OUTPUT); // Configure red LED pin as output
  pinMode(grnPin, OUTPUT); // Configure green LED pin as output
  pinMode(sensorPin, INPUT); // Configure the fuel level sensor pin (A0) as an input
  lcd.begin(2, lcdNumCols); // Define LCD as having 2 rows and refer to the above byte for number of columns
  lcd.clear(); // Clear the LCD display
  delay(100); // Wait 100ms
}

void loop() {
  int level = analogRead(sensorPin); // Label sensor reading as "level"
  level = map(level, 624, 946, 0 ,1023); // Map the sensor's 624E/946F readings to 0-1023 for proper graph display
  lcd.setCursor(0, 0); // Set cursor to top left of display
  lcd.print("E      ||      F"); // Static full/empty readout on the LCD
  lbg.drawValue( level, 1023); // Draw graph as fuel level reading
  if (level < 200) // If the mapped value is below 200 (approx. 3L fuel remaining)
  {
    analogWrite (grnPin, 255); // Turn the green LCD backlight off
    analogWrite (redPin, 0); // Turn the red LCD backlight on
  }
  else // Otherwise
  {
    analogWrite (grnPin, 0); // Turn the green LCD backlight on
    analogWrite (redPin, 255); // turn the red LCD backlight off
  }
  delay(100); // Delay between readings
}

Any help is greatly appreciated. Thanks!

Here's a video of how it works currently: https://photos.google.com/share/AF1QipPTjZQtcFW9HBCw5SEVOGHq9Fh1uWIqKFjy_9rUXuSbnHad5mt_8jSzTAJaN2pwcA?key=Vllfd2JkRTE3ejNVTlFRcG1QbGhUM21lVV9FaDBn

try this ( I removed the most obvious comments for readability)

/*
 *LCD Fuel Gauge for Honda SuperHawk 16L Tank
 *http://www.superhawkforum.com/forums/technical-discussion-28/fuel-gauge-mods-33365/
 *Basic concept found at http://www.pddnet.com/articles/2014/01/designing-arduino-fuel-gauge-warning-lights
 *Code by Will Lyon 7/26/2015. Contact: will.lyon12584@gmail.com
 *Uses the LcdBarGraph1.5 Library for Arduino. Author:  Balázs Kelemen. Contact: prampec+arduino@gmail.com
 *LCDBarGraph library can be found here: http://playground.arduino.cc/Code/LcdBarGraph#Download
 *Designed to be used with the Adafruit 16x2 RGB LCD (both negative and positive work properly)
 *5V to fuel sensor Grn/Blk
 *Fuel sensor Gry/Blk to Analog 0 with 10k resistor to GND
*/


#include <LiquidCrystal.h> 
#include <LcdBarGraph.h> 

byte lcdNumCols = 16; 
byte lcdNumRows = 2; 
byte sensorPin = A0;        // Fuel float sensor 5V input with 10k resistor to GND and Analog 0

LiquidCrystal lcd(7, 8, 9, 10, 11, 12); 
LcdBarGraph lbg(&lcd,16,0,1);         

const int redPin = 5;    // Red LCD backlight on Digital pin 5
const int grnPin = 6;    // Green LCD backlight on Digital pin 6

void setup() {
  Serial.begin(9600); // Initialize communication with PC via serial monitor

  pinMode(redPin, OUTPUT); // Configure red LED pin as output
  pinMode(grnPin, OUTPUT); // Configure green LED pin as output

  lcd.begin(lcdNumRows, lcdNumCols);
  lcd.clear();
  delay(100);
}


void loop() {
  int level = 0;
  for (int i=0; i< 16; i++)   // average 16 readings
  {
    level += analogRead(sensorPin);
  }
  level = level / 16;
  level = map(level, 624, 946, 0, 1023); // Map sensor's 624E/946F readings to 0-1023 for proper graph display

  lcd.setCursor(0, 0);               // Set cursor to top left of display
  lcd.print("E      ||      F");     // Static full/empty readout on the LCD
  lbg.drawValue(level, 1023);        // Draw graph as fuel level reading
  
  if (level < 200)                   // If the mapped value is below 200 (approx. 3L fuel remaining) adjust back color
  {
    analogWrite (grnPin, 255);
    analogWrite (redPin, 0);
  }
  else
  {
    analogWrite (grnPin, 0);
    analogWrite (redPin, 255);
  }
  delay(100); // Delay between readings
}

you can use the colour display also in this way

  if (level > 512)
  {
    analogWrite (grnPin, 0);
    analogWrite (redPin, 255);
  }
  else
  {
    analogWrite (grnPin, 255-level/2);
    analogWrite (redPin, level/2);
  }

the colour now smoothly goes from green to yellow to red

It would seem 16 samples isn't nearly enough as it's still almost instantaneous. I tried upping it to 32 and it worked but anything higher and the screen gets all wonky again.

Also that color change part doesn't work - when full it's red then just under full is green which fades to red at 1/2 tanks, then it's back to green under 1/2 lol

if you need more samples you need to make level of the type long
or use a low pass filter - see code below.

(colour changed too)

/*
 *LCD Fuel Gauge for Honda SuperHawk 16L Tank
 *http://www.superhawkforum.com/forums/technical-discussion-28/fuel-gauge-mods-33365/
 *Basic concept found at http://www.pddnet.com/articles/2014/01/designing-arduino-fuel-gauge-warning-lights
 *Code by Will Lyon 7/26/2015. Contact: will.lyon12584@gmail.com
 *Uses the LcdBarGraph1.5 Library for Arduino. Author:  Balázs Kelemen. Contact: prampec+arduino@gmail.com
 *LCDBarGraph library can be found here: http://playground.arduino.cc/Code/LcdBarGraph#Download
 *Designed to be used with the Adafruit 16x2 RGB LCD (both negative and positive work properly)
 *5V to fuel sensor Grn/Blk
 *Fuel sensor Gry/Blk to Analog 0 with 10k resistor to GND
*/


#include <LiquidCrystal.h> 
#include <LcdBarGraph.h> 

byte lcdNumCols = 16; 
byte lcdNumRows = 2; 
byte sensorPin = A0;        // Fuel float sensor 5V input with 10k resistor to GND and Analog 0

LiquidCrystal lcd(7, 8, 9, 10, 11, 12); 
LcdBarGraph lbg(&lcd,16,0,1);         

const int redPin = 5;    // Red LCD backlight on Digital pin 5
const int grnPin = 6;    // Green LCD backlight on Digital pin 6

int level = 0;

void setup() {
  Serial.begin(9600); // Initialize communication with PC via serial monitor

  pinMode(redPin, OUTPUT); // Configure red LED pin as output
  pinMode(grnPin, OUTPUT); // Configure green LED pin as output

  lcd.begin(lcdNumRows, lcdNumCols);
  lcd.clear();
  delay(100);

  level = analogRead(sensorPin);
}


void loop() {
  // LOW PASS FILTERING; NEW VALUE COUNT FOR 1/16'th

  level = (level*15 + analogRead(sensorPin)) / 16;

  level = map(level, 624, 946, 0, 1023); // Map sensor's 624E/946F readings to 0-1023 for proper graph display

  lcd.setCursor(0, 0);               // Set cursor to top left of display
  lcd.print("E      ||      F");     // Static full/empty readout on the LCD
  lbg.drawValue(level, 1023);        // Draw graph as fuel level reading
  
  if (level < 200)                   // If the mapped value is below 200 (approx. 3L fuel remaining) adjust back color
  {
    analogWrite (grnPin, 0);
    analogWrite (redPin, 255);
  }
  else
  {
    analogWrite (grnPin, 255);
    analogWrite (redPin, 0);
  }
  delay(1000); // Delay between readings
}

give it a try

Yea that made the LCD go nuts. It's flashing back and forth from red to green and all the boxes are filled once again with randome characters popping in here and there

I modified it slightly so that if the bike is in neutral (neutral indicator on) it will read instantly but if it's in gear (indicator off) I want it to smooth the reading to keep tha gauge steady:

/*
 *LCD Fuel Gauge for Honda SuperHawk 16L Tank
 *http://www.superhawkforum.com/forums/technical-discussion-28/fuel-gauge-mods-33365/
 *Basic concept found at http://www.pddnet.com/articles/2014/01/designing-arduino-fuel-gauge-warning-lights
 *Code by Will Lyon 7/26/2015. Contact: will.lyon12584@gmail.com
 *Uses the LcdBarGraph1.5 Library for Arduino. Author:  Balázs Kelemen. Contact: prampec+arduino@gmail.com
 *LCDBarGraph library can be found here: http://playground.arduino.cc/Code/LcdBarGraph#Download
 *Designed to be used with the Adafruit 16x2 RGB LCD (both negative and positive work properly)
 *5V to fuel sensor Grn/Blk
 *Fuel sensor Gry/Blk to Analog 0 with 10k resistor to GND
*/

#include <LiquidCrystal.h> // Include Liquid Crystal library
#include <LcdBarGraph.h> // Include LCD Bar Graph library

byte lcdNumCols = 16; // 16 columns in the 16x2 LCD
byte sensorPin = A0; // Fuel float sensor 5V input with 10k resistor to GND and Analog 0
byte neutralPin = A1; // Neutral indicator to Analog 1 with 10k resistor to GND

LiquidCrystal lcd(7, 8, 9, 10, 11, 12); // LCD connected to digital 7-12
LcdBarGraph lbg(&lcd,16,0,1); // Parameters for LCD bar grah library
const int redPin = 5; // Red LCD backlight on Digital pin 5
const int grnPin = 6; // Green LCD backlight on Digital pin 6

void setup() {
  Serial.begin(9600); // Initialize communication with PC via serial monitor
  pinMode(redPin, OUTPUT); // Configure red LED pin as output
  pinMode(grnPin, OUTPUT); // Configure green LED pin as output
  pinMode(sensorPin, INPUT); // Configure the fuel level sensor pin (A0) as an input
  pinMode(neutralPin, INPUT); // Configure the neutral indicator pin as an input
  lcd.begin(2, lcdNumCols); // Define LCD as having 2 rows and refer to the above byte for number of columns
  lcd.clear(); // Clear the LCD display
  delay(100); // Wait 100ms
}

void loop() {
  int gear = analogRead(neutralPin); // Label neutral pin as "gear"
  if (gear = HIGH) // If the neutral light is on
  {
    int level = analogRead(sensorPin); // Label sensor reading as "level"
    level = map(level, 624, 946, 0 ,1023); // Map the sensor's 624E/946F readings to 0-1023 for proper graph display
    lcd.setCursor(0, 0); // Set cursor to top left of display
    lcd.print("E      ||      F"); // Static full/empty readout on the LCD
    lbg.drawValue( level, 1023); // Draw graph as fuel level reading
    if (level < 200) // If the mapped value is below 200 (approx. 3L fuel remaining)
    {
      analogWrite (grnPin, 255); // Turn the green LCD backlight off
      analogWrite (redPin, 0); // Turn the red LCD backlight on
    }
    else // Otherwise
    {
      analogWrite (grnPin, 0); // Turn the green LCD backlight on
      analogWrite (redPin, 255); // turn the red LCD backlight off
    }
  }
  else // If the neutral indicator is off (bike in gear)
  {
    int level = analogRead(sensorPin); // Label sensor reading as "level"
    level = map(level, 624, 946, 0 ,1023); // Map the sensor's 624E/946F readings to 0-1023 for proper graph display
    lcd.setCursor(0, 0); // Set cursor to top left of display
    lcd.print("E      ||      F"); // Static full/empty readout on the LCD
    lbg.drawValue( level, 1023); // Draw graph as fuel level reading
    if (level < 200) // If the mapped value is below 200 (approx. 3L fuel remaining)
    {
      analogWrite (grnPin, 255); // Turn the green LCD backlight off
      analogWrite (redPin, 0); // Turn the red LCD backlight on
    }
    else // Otherwise
    {
      analogWrite (grnPin, 0); // Turn the green LCD backlight on
      analogWrite (redPin, 255); // turn the red LCD backlight off
    }
  }
  delay(100); // Delay between readings
}

Your current code doesn't do any smoothing at all. Wasn't that the problem you were trying to solve?

Try putting this code at the top of loop() to smoothe 'level' over about a second.

    static int rawLevel = 624;  // default to empty
    static unsigned long levelReadTime = 0;
    static int level = 0;   // default to empty

   if (millis() - levelReadTime >= 100) {  // Sample level 10 times per second
     rawLevel = (rawLevel * 9 +  analogRead(sensorPin)) / 10;
    level = map(rawLevel, 624, 946, 0 ,1023); // Map the raw values (624=E, 946=F) to 0-1023 for proper graph display[color=#222222][/color]
    level = constrain(level, 0, 1023);  // Just in case it goes out of the expected range
    levelReadTime = millis();
  }

Yea that's what I want, I've got it split into the two parts so I can add in the smoothing for the second section (in gear/neutral light off)

johnwasser:
Your current code doesn't do any smoothing at all. Wasn't that the problem you were trying to solve?

Try putting this code at the top of loop() to smoothe 'level' over about a second.

    static int rawLevel = 624;  // default to empty

static unsigned long levelReadTime = 0;
    static int level = 0;  // default to empty

if (millis() - levelReadTime >= 100) {  // Sample level 10 times per second
    rawLevel = (rawLevel * 9 +  analogRead(sensorPin)) / 10;
    level = map(rawLevel, 624, 946, 0 ,1023); // Map the raw values (624=E, 946=F) to 0-1023 for proper graph display
    level = constrain(level, 0, 1023);  // Just in case it goes out of the expected range
    levelReadTime = millis();
  }

That doesn't work. If the gauge is all the way down the LCD goes all screwy until the float gues up for a bit so it will amass some readings. Also the calibration is off for some reason now, where 1/2 float height isn't 1/2 on the LCD - it just drops right down to E at 1/2 float height. It's also still way too fast. I may just need a low pass filter on the hardware side I think as any software filtering makes the LCD go all weird.

I see that the example on the page for the bar graph library says:

 // -- do some delay: frequent draw may cause broken visualization

Perhaps if the LCD was updated ten times per second instead of every time through loop() it would not get corrupted. Just move the bar graph call up to where 'level' is calculated.

Ok so I got it working with the delay. I increased the delay to 2 seconds to further slow the graph movement and it works good.

Now I want to implement the neutral light. If the bike is in neutral I don't want any smoothing (similar to a car). But if the bike is in gear I want it to smooth.

So I edited the code to read whether or not the neutral indicator is lit and if it is to read it as I had it previously and if it's nto to use the smoothing code. However it doesn't seem to work, it seems to skip over the smoothing part and just work without it as before. I have a 10k to ground on A1 and a jumper from A1 to ground to simulate the light being off (bike in gear).

/*
 *LCD Fuel Gauge for Honda SuperHawk 16L Tank
 *http://www.superhawkforum.com/forums/technical-discussion-28/fuel-gauge-mods-33365/
 *Basic concept found at http://www.pddnet.com/articles/2014/01/designing-arduino-fuel-gauge-warning-lights
 *Code by Will Lyon 7/26/2015. Contact: will.lyon12584@gmail.com
 *Uses the LcdBarGraph1.5 Library for Arduino. Author:  Balázs Kelemen. Contact: prampec+arduino@gmail.com
 *LCDBarGraph library can be found here: http://playground.arduino.cc/Code/LcdBarGraph#Download
 *Designed to be used with the Adafruit 16x2 RGB LCD (both negative and positive work properly)
 *5V to fuel sensor Grn/Blk
 *Fuel sensor Gry/Blk to Analog 0 with 10k resistor to GND
 *Neutral indicator to Analog 1 with 10k to ground
 *This will smooth the readings while the bike is in gear
*/

#include <LiquidCrystal.h> // Include Liquid Crystal library
#include <LcdBarGraph.h>   // Include LCD Bar Graph library

byte lcdNumCols = 16; // 16 columns in the 16x2 LCD
byte fuelPin = A0;    // Fuel float sensor 5V input with 10k resistor to GND and Analog 0
byte smoothPin = A1;  // Neutral light connected to A1 with 10k to ground

LiquidCrystal lcd(7, 8, 9, 10, 11, 12); // LCD connected to digital 7-12
LcdBarGraph lbg(&lcd,16,0,1);           // Parameters for LCD bar grah library
const int redPin = 5;                   // Red LCD backlight on Digital pin 5
const int grnPin = 6;                   // Green LCD backlight on Digital pin 6
static int rawLevel = 624;              // Default to empty

void setup() {
  pinMode(redPin, OUTPUT);   // Configure red LED pin as output
  pinMode(grnPin, OUTPUT);   // Configure green LED pin as output
  pinMode(fuelPin, INPUT);   // Configure the fuel level sensor pin (A0) as an input
  pinMode(smoothPin, INPUT); // Configure the neutral indicator light (D3) as an input
  lcd.begin(2, lcdNumCols);  // Define LCD as having 2 rows and refer to the above byte for number of columns
  lcd.clear();               // Clear the LCD display
  delay(100);
}

void loop() {
  digitalRead(smoothPin);                     // Read the neutral indicator
  if (smoothPin = LOW) {                      // If the neutral light is OFF (in gear)
    static unsigned long levelReadTime = 0;   // Smooth the reading
    static int level = 0;                     // Default to empty
    if (millis() - levelReadTime >= 2000) {   // Sample level once every 2 seconds
    rawLevel = (rawLevel * 9 +  analogRead(fuelPin)) / 10;
    level = map(rawLevel, 624, 946, 0 ,1023); // Map the raw values (624=E, 946=F) to 0-1023 for proper graph display
    level = constrain(level, 0, 1023);        // Just in case it goes out of the expected range
    levelReadTime = millis();
    }
    lcd.setCursor(0, 0);                   // Set cursor to top left of display
    lcd.print("E      ||      F");         // Static full/empty readout on the LCD
    lbg.drawValue( level, 1023);           // Draw graph as fuel level reading
    if (level < 200)                       // If the mapped value is below 200 (approx. 3L fuel remaining)
    {
      analogWrite (grnPin, 255); // Turn the green LCD backlight off
      analogWrite (redPin, 0);   // Turn the red LCD backlight on
    }
    else
    {
      analogWrite (grnPin, 0);   // Turn the green LCD backlight on
      analogWrite (redPin, 255); // turn the red LCD backlight off
    }
  }
  if (smoothPin = HIGH) {                  // If the neutral light is ON (in neutral), don't smooth the reading
    int level = analogRead(fuelPin);       // Label sensor reading as "level"
    level = map(level, 624, 946, 0 ,1023); // Map the sensor's 624E/946F readings to 0-1023 for proper graph display
    lcd.setCursor(0, 0);                   // Set cursor to top left of display
    lcd.print("E      ||      F");         // Static full/empty readout on the LCD
    lbg.drawValue( level, 1023);           // Draw graph as fuel level reading
    if (level < 200)                       // If the mapped value is below 200 (approx. 3L fuel remaining)
    {
      analogWrite (grnPin, 255); // Turn the green LCD backlight off
      analogWrite (redPin, 0);   // Turn the red LCD backlight on
    }
    else
    {
      analogWrite (grnPin, 0);   // Turn the green LCD backlight on
      analogWrite (redPin, 255); // turn the red LCD backlight off
    }
  }
  delay(100);
}

OK I have it working almost 100%. The only problem is that if I hold the float up (full tank) with A1 to 5V (light on) the gauge reads full instantly. However if I then remove the 5V from A1 (light off) while still holding the float up (full) the gauge starts off low until it amasses some readings. How can I get it to stay at the "light on" level when it switches to "light off"?

EDIT: If I leave it in "light off" mode and let it get to full it stays when I go to "light on" then back. However if I start with "light on" as you'd normally start the bike - in neutral - and then switch to "light off" it goes to empty then works it's way back up.

/*
 *LCD Fuel Gauge for Honda SuperHawk 16L Tank
 *http://www.superhawkforum.com/forums/technical-discussion-28/fuel-gauge-mods-33365/
 *Basic concept found at http://www.pddnet.com/articles/2014/01/designing-arduino-fuel-gauge-warning-lights
 *Code by Will Lyon 7/26/2015. Contact: will.lyon12584@gmail.com
 *Uses the LcdBarGraph1.5 Library for Arduino. Author:  Balázs Kelemen. Contact: prampec+arduino@gmail.com
 *LCDBarGraph library can be found here: http://playground.arduino.cc/Code/LcdBarGraph#Download
 *Designed to be used with the Adafruit 16x2 RGB LCD (both negative and positive work properly)
 *5V to fuel sensor Grn/Blk
 *Fuel sensor Gry/Blk to Analog 0 with 10k resistor to GND
 *Neutral indicator to Analog 1 with 10k to ground
 *This will smooth the readings while the bike is in gear
*/

#include <LiquidCrystal.h> // Include Liquid Crystal library
#include <LcdBarGraph.h>   // Include LCD Bar Graph library

byte lcdNumCols = 16; // 16 columns in the 16x2 LCD
byte fuelPin = A0;    // Fuel float sensor 5V input with 10k resistor to GND and Analog 0
byte smoothPin = A1;  // Neutral light connected to A1 with 10k to ground

LiquidCrystal lcd(7, 8, 9, 10, 11, 12); // LCD connected to digital 7-12
LcdBarGraph lbg(&lcd,16,0,1);           // Parameters for LCD bar grah library
const int redPin = 5;                   // Red LCD backlight on Digital pin 5
const int grnPin = 6;                   // Green LCD backlight on Digital pin 6
static int rawLevel = 624;              // Default to empty

void setup() {
  pinMode(redPin, OUTPUT);   // Configure red LED pin as output
  pinMode(grnPin, OUTPUT);   // Configure green LED pin as output
  pinMode(fuelPin, INPUT);   // Configure the fuel level sensor pin (A0) as an input
  pinMode(smoothPin, INPUT); // Configure the neutral indicator light (D3) as an input
  lcd.begin(2, lcdNumCols);  // Define LCD as having 2 rows and refer to the above byte for number of columns
  lcd.clear();               // Clear the LCD display
  delay(100);
}

void loop() {
  int light = digitalRead(smoothPin);         // Read the neutral indicator
  if (light == LOW) {                         // If the neutral light is OFF (in gear)
    static unsigned long levelReadTime = 0;   // Smooth the reading
    static int level = 0;                     // Default to empty
    if (millis() - levelReadTime >= 2000) {   // Sample level once every 2 seconds
    rawLevel = (rawLevel * 9 +  analogRead(fuelPin)) / 10;
    level = map(rawLevel, 624, 946, 0 ,1023); // Map the raw values (624=E, 946=F) to 0-1023 for proper graph display
    level = constrain(level, 0, 1023);        // Just in case it goes out of the expected range
    levelReadTime = millis();
    }
    lcd.setCursor(0, 0);                   // Set cursor to top left of display
    lcd.print("E      ||      F");         // Static full/empty readout on the LCD
    lbg.drawValue( level, 1023);           // Draw graph as fuel level reading
    if (level < 200)                       // If the mapped value is below 200 (approx. 3L fuel remaining)
    {
      analogWrite (grnPin, 255); // Turn the green LCD backlight off
      analogWrite (redPin, 0);   // Turn the red LCD backlight on
    }
    else
    {
      analogWrite (grnPin, 0);   // Turn the green LCD backlight on
      analogWrite (redPin, 255); // turn the red LCD backlight off
    }
  }
  delay(100);
  if (light == HIGH) {                     // If the neutral light is ON (in neutral), don't smooth the reading
    int level = analogRead(fuelPin);       // Label sensor reading as "level"
    level = map(level, 624, 946, 0 ,1023); // Map the sensor's 624E/946F readings to 0-1023 for proper graph display
    lcd.setCursor(0, 0);                   // Set cursor to top left of display
    lcd.print("E      ||      F");         // Static full/empty readout on the LCD
    lbg.drawValue( level, 1023);           // Draw graph as fuel level reading
    if (level < 200)                       // If the mapped value is below 200 (approx. 3L fuel remaining)
    {
      analogWrite (grnPin, 255); // Turn the green LCD backlight off
      analogWrite (redPin, 0);   // Turn the red LCD backlight on
    }
    else
    {
      analogWrite (grnPin, 0);   // Turn the green LCD backlight on
      analogWrite (redPin, 255); // turn the red LCD backlight off
    }
  }
  delay(100);
}

OK so I decided to ditch to LCD and go for a 10-segment LED instead due to size. I've got it working in dot mode however I want to see if I can change it at all. What I'd like is for it to dot through the first 5 (green) then through the next 3 (yellow). However when it gets tot he last two (red) I want them to both come on then as the level drops be left with a single blinking red LED. How can I do this? Here's my modified code (still have to add smoothing back in):

/*
 *LED Fuel Gauge for Honda SuperHawk 16L Tank
 *http://www.superhawkforum.com
 *Code by Will Lyon 7/24/2015. Contact: will.lyon12584@gmail.com
 *5V to fuel sensor Grn/Blk
 *Fuel sensor Gry/Blk to Analog 0 with 10k resistor to GND
 *220 ohm resistor to each led and GND
*/

const int sensorPin = A0;   // the pin that the potentiometer is attached to
const int ledCount = 10;    // the number of LEDs in the bar graph

int ledPins[] = { 
  2, 3, 4, 5, 6, 7,8,9,10,11 };   // an array of pin numbers to which LEDs are attached


void setup() {
  // loop over the pin array and set them all to output:
  for (int thisLed = 0; thisLed < ledCount; thisLed++) {
    pinMode(ledPins[thisLed], OUTPUT); 
  }
}

void loop() {
  // read the potentiometer:
  int level = analogRead(sensorPin);
  // map the result to a range from 0 to the number of LEDs:
  level = map(level, 575, 945, 0, ledCount);

  // loop over the LED array:
  for (int thisLed = 0; thisLed < ledCount; thisLed++) {
    // if the array element's index is less than ledLevel,
    // turn the pin for this element on:
    if (thisLed == level-1) {
      digitalWrite(ledPins[thisLed], HIGH);
    } 
    // turn off all pins higher than the ledLevel:
    else {
      digitalWrite(ledPins[thisLed], LOW); 
    }
  }
  delay(100);
}

Got it working nicely :slight_smile:

/*
 *LED Fuel Gauge for Honda SuperHawk 16L Tank
 *http://www.superhawkforum.com
 *Code by Will Lyon 9/23/2015. Contact: will.lyon12584@gmail.com
 *5V to fuel sensor Grn/Blk
 *Fuel sensor Gry/Blk to Analog 0 with 10k resistor to GND
 *220 ohm resistor to each led and GND
*/

const int sensorPin = A0;       // the pin that the potentiometer is attached to
const int ledCount = 10;        // the number of LEDs in the bar graph
const int numReadings = 30;     // use this value to determine the size of the readings array

int ledPins[] = { 
  2, 3, 4, 5, 6, 7,8,9,10,11 }; // an array of pin numbers to which LEDs are attached
int readings[numReadings];      // the readings from teh fuel level gauge
int readIndex = 0;              // the index of the current reading
int total = 0;                  // the running total
int average = 0;                // the average


void setup() {
  for (int thisLed = 0; thisLed < ledCount; thisLed++) {  // loop over the pin array and set them all to output:
    pinMode(ledPins[thisLed], OUTPUT);
  }
  Serial.begin(9600);
  for (int thisReading = 0; thisReading < numReadings; // initialize all readings to zero
thisReading++) {
  readings[thisReading] = 0;
  }
}

void loop() {
  total = total - readings[readIndex];        // subtract the last reading
  readings[readIndex] = analogRead(sensorPin);// read from the sensor
  total = total + readings[readIndex];        // add the reading to the total
  readIndex = readIndex + 1;                  // advance to the next position in the array
  if (readIndex >= numReadings) {             // if we're at the end of the array
    readIndex = 0;                            // wrap around to the beginning
  }
  average = total / numReadings;              // calculate the average
  Serial.println(average);                    // send it to the pc as ASCII digits
  delay(1000);                                // delay in between readings for stability
//  int level = analogRead(sensorPin);  // read the potentiometer:
  average = map(average, 580, 913, 0, ledCount); // map the result to a range from 0 to the number of LEDs:

  // loop over the LED array:
  for (int thisLed = 0; thisLed < ledCount; thisLed++) {
    // if the array element's index is less than ledLevel,
    // turn the pin for this element on:
    if (thisLed == average-1) {
      digitalWrite(ledPins[thisLed], HIGH);
    } 
    // turn off all pins higher than the ledLevel:
    else {
      digitalWrite(ledPins[thisLed], LOW); 
    }
  }
  delay(100);
}

Ok so I got the smoothing implemented:

/*
 *LED Fuel Gauge for Honda SuperHawk 16L Tank
 *http://www.superhawkforum.com
 *Code by Will Lyon 9/23/2015. Contact: will.lyon12584@gmail.com
 *5V to fuel sensor Grn/Blk
 *Fuel sensor Gry/Blk to Analog 0 with 10k resistor to GND
 *220 ohm resistor to each led and GND
*/

const int sensorPin = A0;       // the pin that the potentiometer is attached to
const int ledCount = 10;        // the number of LEDs in the bar graph
const int numReadings = 30;     // use this value to determine the size of the readings array

int ledPins[] = { 
  2, 3, 4, 5, 6, 7,8,9,10,11 }; // an array of pin numbers to which LEDs are attached
int readings[numReadings];      // the readings from teh fuel level gauge
int readIndex = 0;              // the index of the current reading
int total = 0;                  // the running total
int average = 0;                // the average


void setup() {
  for (int thisLed = 0; thisLed < ledCount; thisLed++) {  // loop over the pin array and set them all to output:
    pinMode(ledPins[thisLed], OUTPUT);
  }
  Serial.begin(9600);
  for (int thisReading = 0; thisReading < numReadings; // initialize all readings to zero
thisReading++) {
  readings[thisReading] = 0;
  }
}

void loop() {
  total = total - readings[readIndex];        // subtract the last reading
  readings[readIndex] = analogRead(sensorPin);// read from the sensor
  total = total + readings[readIndex];        // add the reading to the total
  readIndex = readIndex + 1;                  // advance to the next position in the array
  if (readIndex >= numReadings) {             // if we're at the end of the array
    readIndex = 0;                            // wrap around to the beginning
  }
  average = total / numReadings;              // calculate the average
  Serial.println(average);                    // send it to the pc as ASCII digits
  delay(1000);                                // delay in between readings for stability
//  int level = analogRead(sensorPin);  // read the potentiometer:
  average = map(average, 580, 913, 0, ledCount); // map the result to a range from 0 to the number of LEDs:

  // loop over the LED array:
  for (int thisLed = 0; thisLed < ledCount; thisLed++) {
    // if the array element's index is less than ledLevel,
    // turn the pin for this element on:
    if (thisLed == average-1) {
      digitalWrite(ledPins[thisLed], HIGH);
    } 
    // turn off all pins higher than the ledLevel:
    else {
      digitalWrite(ledPins[thisLed], LOW); 
    }
  }
  delay(100);
}

And a video: https://goo.gl/photos/WMbeiffdJmd5DYsT8

The video runs a little faster than the code I posted as I increased both the delay between readings and the number of readings.

Now here's what I want to do. When it first powers on it takes 10 or so seconds for it to build up enough readings to work the gauge. How can I make it so that on startup it takes a single reading and uses that for the display (so it's instant) and just holds that reading for 10 or so seconds while it's building up enough readings for the average, then switch to using the average for the display?

Either that or use the neutral light to switch between modes, like a car does. In neural the gauge moves fast but once you put it in gear it implements some smoothing. I had it working (sorta) before but when it would switch to in-gear it would start from the bottom as it would need to build up readings instead of continuously building readings and only relying on the average function if it's not in gear (neutral light off/input pin LOW).

Use millis() and a 'flag'.
When the flag = 0, use the initial value you get from wherever.

When millis() is > your startTime - add startTime = millis(); at the end of setup() - then make the flag = 1 and start using real numbers.

I get the basic idea and I've read through the millis() reference but I've got no idea how to implement it. I added "unsigned long startTime;" in the header. and added "startTime = millis;" at the end of "setup()". I'm not sure how to go about the flag part though.

Ok so I got some help over at the Element 14 forums. It's working exacty how I want now. Here's the final code with some added delays to further smooth the display and also a sequence to run the LED's during stup() just for aesthetic effect only. Now I jsut need to design a PCB and design/3D print an enclosure for it and I'm good to go! I'm still thinking of having it turn on the factory low fuel LED when it gets to the last two bars so there might be another revision!

/*
*LED Fuel Gauge for Honda SuperHawk 16L Tank
*http://www.superhawkforum.com
*Code by Will Lyon 10/3/2015. Contact: will.lyon12584@gmail.com
*Help from user Doug Jefferies on the Element 14 Forums
*5V to fuel sensor Grn/Blk
*Fuel sensor Gry/Blk to Analog 0 with 10k resistor to GND
*220 ohm resistor to each led and GND
*/

const int sensorPin = A0;       // the pin that the potentiometer is attached to
const int ledCount = 10;        // the number of LEDs in the bar graph
const int numReadings = 35;     // use this value to determine the size of the readings array

int ledPins[] = {
  2, 3, 4, 5, 6, 7,8,9,10,11 }; // an array of pin numbers to which LEDs are attached
int readings[numReadings];      // the readings from the fuel level gauge
int readIndex = 0;              // the index of the current reading
int total = 0;                  // the running total
int average = 0;                // the average
int averagingCount = 0;         // checks the number of values in the Index
int timer = 75;                 // timer for inital LED sweep
int pinCount = 10;              // number of LED pins

void setup() {
  for (int thisLed = 0; thisLed < ledCount; thisLed++) {      // loop over the pin array and set them all to output
    pinMode(ledPins[thisLed], OUTPUT);
  }
  for (int thisReading = 0; thisReading < numReadings;        // initialize all readings to zero
  thisReading++) {
  readings[thisReading] = 0;
  }
  for (int thisPin = 0; thisPin < pinCount; thisPin++) {      // loop from the lowest pin to the highest
    digitalWrite(ledPins[thisPin], HIGH);                     // turn the pin on
    delay(timer);                                             // delay for time set bove
    digitalWrite(ledPins[thisPin], LOW);                      // turn the pin off
  }
  for (int thisPin = pinCount - 1; thisPin >= 0; thisPin--) { // loop from the highest pin to the lowest
    digitalWrite(ledPins[thisPin], HIGH);                     // turn the pin on
    delay(timer);                                             // delay for time set above
    digitalWrite(ledPins[thisPin], LOW);                      // turn the pin off
  }
}

void loop() {
  total = total - readings[readIndex];            // subtract the last reading
  readings[readIndex] = analogRead(sensorPin);    // read from the sensor
  total = total + readings[readIndex];            // add the reading to the total
  readIndex = readIndex + 1;                      // advance to the next position in the array
  if (readIndex >= numReadings) {                 // if we're at the end of the array
    readIndex = 0;                                // wrap around to the beginning
  }
  averagingCount = averagingCount + 1;            // increments the count for averaging
  if (averagingCount >= numReadings) {            // caps the averaging count to the array
    averagingCount = numReadings;                           
  }
  average = total / averagingCount;               // calculate the average
  delay(3000);                                    // delay in between readings so the gauge doesn't fluctuate too fast
  average = map(average, 580, 925, 0, ledCount);  // map the result to a range from 0 to the number of LEDs:
  for (int thisLed = 0; thisLed < ledCount; thisLed++) {  // loop over the LED array
    if (thisLed == average-1) {                   // if the array element's index is less than ledLevel
      digitalWrite(ledPins[thisLed], HIGH);       // turn the pin for this element on:
    }
    else {
      digitalWrite(ledPins[thisLed], LOW);        // turn off all pins higher than the ledLevel:
    }
  }
  delay(100);
}

I do PCB design work if you need that. Also in MA.