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.
Components and supplies
1
MOSFET Transistor, P Channel
1
Arduino Nano R3
2
Optocoupler, Transistor Output
1
Air Flow Sensor, Digital
1
Automotive 12V Diode Protected Relay
1
LED Momentary Button
1
OLED Display 2.42"
1
Nano Terminal Adapter
2
Resistor 220 ohm
1
LED Latching Switch
Tools and machines
1
Soldering iron (generic)
1
Solder Wire, Lead Free
Apps and platforms
1
Arduino IDE
Project description
Code
Code
arduino
1// set variables needed to translate button states and delay timer 2#include <U8g2lib.h> //Include library for 128x64 OLED 2.42 display 3#include <Wire.h> 4 5U8G2_SSD1309_128X64_NONAME0_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ 10); 6int fuelPin = A0; 7int fuelValue = 0; 8int level = 0; //29 represents the tank displaying as FULL 9int pumpState = 0; 10int gallons = 0; 11float volume = 0; 12byte onPin = 9; 13byte modePin = 11; //selects transfer screen with on button 14const byte enterPin = 12; //Starts pump with momentary button 15byte enterState = 0; //state of button for committing pump start 16byte sensorPin = 2; //flow meter signal input and initiates interrupt 17byte upButton = 4;//Up botton to incement fuel volume request 18byte downButton = 3;//down button to decrement fuel volume request 19int counter = 0; 20const byte pumpPin = 13; //output pin to BOB for relay 21int dt = 100; 22byte sensorInterrupt = 0; // 0 = digital pin 2 flow meter input 23float pulseFactor = 2.5; //milliters per pulse 24float gallonFactor = 0.26417; //amount of gallons/Liter 25 26volatile int pulseCount; //variable must be volitile when used in interrupt routine 27 28float flowRate; 29unsigned long int flowMilliLitres; 30unsigned long totalMilliLitres; 31 32unsigned long previousTime; 33unsigned long elapsedTime; 34 35void setup() { 36 37Serial.begin(9600); 38u8g2.begin(); 39u8g2.clearBuffer(); 40 41pinMode (pumpPin, OUTPUT); 42pinMode (onPin, OUTPUT); 43pinMode (modePin, INPUT_PULLUP); //just need to ground pin to activate (LOW is active) 44pinMode (enterPin, INPUT_PULLUP); //just need to ground pin to activate (LOW is active) 45pinMode (upButton, INPUT_PULLUP); //just need to ground pin to activate (LOW is active) 46pinMode (downButton, INPUT_PULLUP); //just need to ground pin to activate (LOW is active) 47digitalWrite(pumpPin, LOW); 48 49 pinMode(sensorPin, INPUT); 50 digitalWrite(sensorPin, HIGH); 51 52 pulseCount = 0; 53 flowRate = 0.0; 54 flowMilliLitres = 0; 55 totalMilliLitres = 0; 56 previousTime = 0; 57 58 // The Hall-effect sensor is connected to pin 2 which uses interrupt 0. 59 // Configured to trigger on a FALLING state change (transition from HIGH 60 // state to LOW state) 61 attachInterrupt(sensorInterrupt, pulseCounter, FALLING); 62} 63 64void loop() { 65checkEnterButton(); 66 67if(digitalRead(modePin) == LOW) 68{ 69 calculateAndDisplayFlow(); 70 checkUpDownButtonCount(); 71} 72else 73{ 74 readAndDisplayLevel(); //run subroutine when pump switch is off 75 } 76}//end loop 77 78void readAndDisplayLevel() 79{ 80 fuelValue = analogRead(fuelPin); 81 level = map(fuelValue, 510, 119, 0, 29); //510 and 119 represent full and empty levels through voltage divider 82 if(level < 0){ //29 represent toal number of bars (|) for full on display 83 level = 0; 84 } 85 if(level > 29){ 86 level = 29; 87 } 88 gallons = map(fuelValue, 510, 119, 0, 40); //Map same levels to gallon levels in a 40 gallon tank 89 if(gallons < 0){ 90 gallons = 0; 91 } 92 if(gallons > 40){ 93 gallons = 40; 94 } 95 counter = 0; //set trasfer volume and target back to zero if transfer operation switched back to fuel level 96 totalMilliLitres = 0; 97 u8g2.sendBuffer(); 98 char buffer[32] = ""; 99 for(int i=0; i<=level;i++) //this for loop will string indicator bars together to match level set by mapping tank float resistance 100 { 101 strcat(buffer, "|"); 102 } 103 digitalWrite(onPin, LOW); 104 u8g2.clearBuffer(); 105 u8g2.setCursor(1, 10); //position display cursor for first line of text 106 u8g2.setFont(u8g2_font_t0_13_mf); //set font size to 13 107 u8g2.print("Fuel Level Reserve"); 108 u8g2.setCursor(2, 30); //position display cursor for second line of text 109 u8g2.setFont(u8g2_font_helvB08_tf); //set font size to 11 bold 110 u8g2.print(" E---------1/2---------F"); 111 u8g2.setCursor(4, 40); //position display cursor for third line of text 112 u8g2.setFont(u8g2_font_4x6_tf); 113 u8g2.print(buffer); //print the level bars 114 u8g2.setFont(u8g2_font_t0_13_mf); //set font size to 13 115 u8g2.setCursor(40, 60); //position display cursor for forth line of text 116 u8g2.print(gallons); //print fuel level in gallons 117 u8g2.print(" Gal."); 118 u8g2.sendBuffer(); //send buffered text to display 119 delay(2000); 120};//end readAndDisplayLevel 121 122void pulseCounter() //Measure the number of pulses for 1 second into pulse counter 123{ 124 pulseCount++; 125}//end pulseCounter 126 127void checkEnterButton() 128{ 129 // read the state of the pushbutton value: 130 enterState = digitalRead(enterPin); 131 132 // check if the enter button is pressed to start pump. Flow sensor will then pulse interrrupt pin 2 133 if (enterState == LOW) { 134 digitalWrite(pumpPin, !digitalRead(pumpPin)); 135 // debounce: 136 delay(300); 137 } 138} //end checkEnterButton 139 140void calculateAndDisplayFlow() // if on switch latched, transfer mode screen displayed 141{ 142 if((millis() - previousTime) > 1000) // Only process counters once per second 143 { 144 detachInterrupt(sensorInterrupt); 145 digitalWrite(onPin, HIGH); 146 flowMilliLitres = (pulseFactor * pulseCount); //flow volume (mls) during sampling imperval 147 flowRate = flowMilliLitres/((millis() - previousTime)/1000); //flow milliliters/sec 148 flowRate = flowRate * 0.016; // conversion factor to gallons/min. 149 previousTime = millis(); 150 totalMilliLitres += flowMilliLitres; 151 volume = (totalMilliLitres/1000)*gallonFactor; 152 volume = (totalMilliLitres/1000)*.26417; //Convert milliters to Gallons 153 u8g2.clearBuffer(); 154 u8g2.setFont(u8g2_font_t0_13_mf); 155 u8g2.setCursor(4, 33); 156 u8g2.print("Target Vol: "); 157 u8g2.print(counter); 158 u8g2.print(" Gal"); 159 u8g2.setCursor(4, 50); 160 u8g2.print("Flow: "); 161 u8g2.print(flowRate,1); // print to one decimal 162 u8g2.print(" Gal/min"); 163 u8g2.setCursor(4, 18); 164 u8g2.print("Volume: "); 165 u8g2.print(volume); 166 u8g2.print(" Gal"); 167 u8g2.drawFrame(1,1,126,60); //draw a frame around displayed data 168 u8g2.sendBuffer(); 169 // Reset the pulse counter so we can start incrementing again 170 pulseCount = 0; 171 172 if(volume >= counter)//turn off pump if pumped volume is greater than set counted volume 173 { 174 enterState == LOW; 175 digitalWrite(pumpPin, LOW);//turn off pump 176 } 177 178 // Enable the interrupt again now that we've finished sending output to display 179 attachInterrupt(sensorInterrupt, pulseCounter, FALLING); 180 } 181} //end calculateAndDisplayFlow 182 183 void checkUpDownButtonCount() // read the up and down pins: 184 { 185 byte upState = digitalRead(upButton); 186 byte downState = digitalRead(downButton)*-1; 187 188 if (upState == 0) { 189 counter++; 190 delay(400); //delay to prevent bounce from momentary switch 191 } 192 else if (downState == 0) { 193 counter--; 194 delay(400); 195 } 196 if (counter < 0){ 197 counter = 0; 198 } 199 else if(counter >= gallons) { //turn off pump when transferred volume reaches request volume 200 counter = (gallons - 1); 201 } 202} //end checkUpDownButtonCount
Downloadable files
Schematic
Schematic

Schematic
Schematic

Comments
Only logged in users can leave comments