Hackster is hosting Hackster Holidays, Ep. 7: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Friday!Stream Hackster Holidays, Ep. 7 on Friday!
heybill55
Published

Reserve Fuel Tank Monitor and Transfer

This project utilizes a 2.42 OLED display to monitor fuel level in a reserve tank and to move and measure fuel transfer to main tank.

IntermediateFull instructions provided384
Reserve Fuel Tank Monitor and Transfer

Things used in this project

Hardware components

Resistor 220 ohm
Resistor 220 ohm
×2
Optocoupler, Transistor Output
Optocoupler, Transistor Output
×2
MOSFET Transistor, P Channel
MOSFET Transistor, P Channel
×1
Air Flow Sensor, Digital
Air Flow Sensor, Digital
×1
LED Momentary Button
×1
LED Latching Switch
×1
OLED Display 2.42"
×1
Omron Electronic Components LLC Automotive 12V Diode Protected Relay
×1
Arduino Nano R3
Arduino Nano R3
×1
Nano Terminal Adapter
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Solder Wire, Lead Free
Solder Wire, Lead Free

Story

Read more

Schematics

Schematic

Code

Code

Arduino
// set variables needed to translate button states and delay timer
#include <U8g2lib.h> //Include library for 128x64 OLED 2.42 display
#include <Wire.h>

U8G2_SSD1309_128X64_NONAME0_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ 10);
int fuelPin = A0;
int fuelValue = 0;
int level = 0; //29 represents the tank displaying as FULL
int pumpState = 0;
int gallons = 0;
float volume = 0;
byte onPin = 9;
byte modePin = 11; //selects transfer screen with on button
const byte enterPin = 12;  //Starts pump with momentary button
byte enterState = 0; //state of button for committing pump start
byte sensorPin = 2; //flow meter signal input and initiates interrupt
byte upButton = 4;//Up botton to incement fuel volume request
byte downButton = 3;//down button to decrement fuel volume request
int counter = 0;
const byte pumpPin = 13; //output pin to BOB for relay
int dt = 100;
byte sensorInterrupt = 0;  // 0 = digital pin 2 flow meter input
float pulseFactor = 2.5; //milliters per pulse
float gallonFactor = 0.26417; //amount of gallons/Liter

volatile int pulseCount;  //variable must be volitile when used in interrupt routine

float flowRate;
unsigned long int flowMilliLitres;
unsigned long totalMilliLitres;

unsigned long previousTime;
unsigned long elapsedTime;

void setup() {

Serial.begin(9600);
u8g2.begin();
u8g2.clearBuffer();

pinMode (pumpPin, OUTPUT);
pinMode (onPin, OUTPUT);
pinMode (modePin, INPUT_PULLUP); //just need to ground pin to activate (LOW is active)
pinMode (enterPin, INPUT_PULLUP); //just need to ground pin to activate (LOW is active)
pinMode (upButton, INPUT_PULLUP); //just need to ground pin to activate (LOW is active)
pinMode (downButton, INPUT_PULLUP); //just need to ground pin to activate (LOW is active)
digitalWrite(pumpPin, LOW);
  
  pinMode(sensorPin, INPUT);
  digitalWrite(sensorPin, HIGH);

  pulseCount        = 0;
  flowRate          = 0.0;
  flowMilliLitres   = 0;
  totalMilliLitres  = 0;
  previousTime      = 0;

  // The Hall-effect sensor is connected to pin 2 which uses interrupt 0.
  // Configured to trigger on a FALLING state change (transition from HIGH
  // state to LOW state)
 attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
}

void loop() {
checkEnterButton();

if(digitalRead(modePin) == LOW)
{
  calculateAndDisplayFlow();
  checkUpDownButtonCount();
}
else
{  
  readAndDisplayLevel(); //run subroutine when pump switch is off 
  }
}//end loop

void readAndDisplayLevel()
{
  fuelValue = analogRead(fuelPin);
  level = map(fuelValue, 510, 119, 0, 29); //510 and 119 represent full and empty levels through voltage divider
  if(level < 0){                           //29 represent toal number of bars (|) for full on display
    level =  0;
  }
  if(level > 29){
    level = 29;
  }
  gallons = map(fuelValue, 510, 119, 0, 40); //Map same levels to gallon levels in a 40 gallon tank
  if(gallons < 0){
    gallons =  0;
  }
  if(gallons > 40){
    gallons =  40;
  }
  counter = 0; //set trasfer volume and target back to zero if transfer operation switched back to fuel level
  totalMilliLitres = 0;
  u8g2.sendBuffer();
  char buffer[32] = "";
  for(int i=0; i<=level;i++) //this for loop will string indicator bars together to match level set by mapping tank float resistance 
   {  
    strcat(buffer, "|");   
    }
  digitalWrite(onPin, LOW);
  u8g2.clearBuffer();
  u8g2.setCursor(1, 10); //position display cursor for first line of text
  u8g2.setFont(u8g2_font_t0_13_mf); //set font size to 13
  u8g2.print("Fuel Level Reserve");
  u8g2.setCursor(2, 30); //position display cursor for second line of text
  u8g2.setFont(u8g2_font_helvB08_tf); //set font size to 11 bold
  u8g2.print(" E---------1/2---------F");
  u8g2.setCursor(4, 40); //position display cursor for third line of text
  u8g2.setFont(u8g2_font_4x6_tf);
  u8g2.print(buffer); //print the level bars
  u8g2.setFont(u8g2_font_t0_13_mf); //set font size to 13
  u8g2.setCursor(40, 60); //position display cursor for forth line of text
  u8g2.print(gallons); //print fuel level in gallons
  u8g2.print(" Gal.");
  u8g2.sendBuffer(); //send buffered text to display
  delay(2000); 
};//end readAndDisplayLevel

void pulseCounter()  //Measure the number of pulses for 1 second into pulse counter
{
  pulseCount++; 
}//end pulseCounter

void checkEnterButton()
{
 // read the state of the pushbutton value:
  enterState = digitalRead(enterPin);

  // check if the enter button is pressed to start pump.  Flow sensor will then pulse interrrupt pin 2
  if (enterState == LOW) {
    digitalWrite(pumpPin, !digitalRead(pumpPin));
    // debounce:
    delay(300);   
  }
} //end checkEnterButton

void calculateAndDisplayFlow() // if on switch latched, transfer mode screen displayed
{
  if((millis() - previousTime) > 1000)    // Only process counters once per second
      { 
        detachInterrupt(sensorInterrupt);
        digitalWrite(onPin, HIGH);
        flowMilliLitres = (pulseFactor * pulseCount);  //flow volume (mls) during sampling imperval
        flowRate = flowMilliLitres/((millis() - previousTime)/1000); //flow milliliters/sec
        flowRate = flowRate * 0.016; // conversion factor to gallons/min.
        previousTime = millis();
        totalMilliLitres += flowMilliLitres;
        volume = (totalMilliLitres/1000)*gallonFactor;
        volume = (totalMilliLitres/1000)*.26417; //Convert milliters to Gallons
        u8g2.clearBuffer();
        u8g2.setFont(u8g2_font_t0_13_mf);
        u8g2.setCursor(4, 33);
        u8g2.print("Target Vol: ");
        u8g2.print(counter);
        u8g2.print(" Gal");
        u8g2.setCursor(4, 50);
        u8g2.print("Flow: ");
        u8g2.print(flowRate,1); // print to one decimal
        u8g2.print(" Gal/min");
        u8g2.setCursor(4, 18);
        u8g2.print("Volume: ");
        u8g2.print(volume);
        u8g2.print(" Gal");
        u8g2.drawFrame(1,1,126,60); //draw a frame around displayed data
        u8g2.sendBuffer(); 
        // Reset the pulse counter so we can start incrementing again
        pulseCount = 0;
        
        if(volume >= counter)//turn off pump if pumped volume is greater than set counted volume
        {
          enterState == LOW;
          digitalWrite(pumpPin, LOW);//turn off pump
        }
    
        // Enable the interrupt again now that we've finished sending output to display
        attachInterrupt(sensorInterrupt, pulseCounter, FALLING);
      }
} //end calculateAndDisplayFlow

  void checkUpDownButtonCount() // read the up and down pins:
  {
  byte upState = digitalRead(upButton);
  byte downState = digitalRead(downButton)*-1;

  if (upState == 0) {
    counter++;
    delay(400);  //delay to prevent bounce from momentary switch
  }
  else if (downState == 0) {
    counter--;
    delay(400);
  }
  if (counter < 0){
    counter = 0;
  }
  else if(counter >= gallons) {  //turn off pump when transferred volume reaches request volume
    counter = (gallons - 1);
  }
} //end checkUpDownButtonCount

Credits

heybill55
1 project • 0 followers

Comments