Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "PinChangeInterrupt.h" // enables the interrupts at the other pin except the ones at the digital pins 2 and 3
- #include <avr/sleep.h> // enables the sleep function
- #include <avr/power.h> // power management
- #include <EEPROMex.h> // enables some special functions for writing to and reading from EEPROM
- #include <EEPROMVar.h>
- #include <Wire.h> // IIC LIBRARY
- #include "RTClib.h" // Real Time Clock Library
- #include <math.h> // enables complex math functions
- #include <LiquidCrystal_I2C.h>
- #include <OneWire.h>
- #include <DallasTemperature.h>
- LiquidCrystal_I2C lcd(0x27,20,4);
- RTC_DS1307 rtc;
- OneWire oneWire(9);
- DallasTemperature sensors(&oneWire);
- // variables declaration
- volatile static float vss_pulse_distance = 0.0003816033; // distance coefficient -- change this according to your measurements (km/pulse)
- volatile float LPG_injector_flow; // LPG injector flow coef. -- it is calculated at setup() (litres/microseconds)
- volatile static float unleadedFlow = 1743e-11; // gasoline injector flow coef. -- change this according to your measurements (litres/microseconds)
- byte LPG1, LPG2, LPG3, LPG4, digitLPG, pos = 0; // LPG_injector_flow = (LPG1 * 1000 + LPG2 * 100 + LPG3 * 10 + LPG4) * 1e-11
- volatile unsigned long vss_pulses; //keeps how many pulses "passed" from the vss sensor per second
- volatile float traveled_distance, traveled_distance2, traveled_distance3, seconds_passed, speed, avg_speed, distance_to_LPGstation;
- volatile float used_LPG, used_LPG2, instant_LPG_consumption, avg_LPG_consumption, LPG_in_tank, Full_tank = 49;
- volatile float used_Unleaded, used_Unleaded2;
- volatile float average_L_100km_Unlead;
- volatile unsigned long unleadTime1=0, unleadTime2=0, unleadinj_Open_Duration=0;
- volatile unsigned long LPG_injector_open_duration = 0, injTime1=0, injTime2=0;
- int postemp;
- int vss_pin = 2; // VSS signal input at digital pin 2 (INT0)
- int LPG_pin = 3; // LPG injector signal input at digital pin 3 (INT1)
- int ignition_pin = 9; // ignition signal input
- int unleaded_pin = 12; // Unleaded injector signal input
- boolean buttonState, buttonState2; // variables related to buttons functions
- boolean lastButtonState2 = LOW;
- long lastDebounceTime = 0, logohold, counter, counter2;
- volatile boolean ignition = false;
- boolean ignoreRelease = false;
- boolean inst_disp = true;
- byte menunumber = 0, menunumbermax = 10; // main menu initial value and maximum value -- see below where the "case:"s are
- int h=0, m=0, s, m1; // variables needed for time setting
- boolean timeRead = false, displaychange = true;
- float thermReading, steinhart; //steinhart - hart equation for thermistors
- boolean dots = true;
- int i=0;
- void setup()
- {
- pinMode(10, INPUT); // Button 1
- //rtc.adjust(DateTime(2017,4,23,16,50,0));
- pinMode(vss_pin, INPUT);
- pinMode(LPG_pin, INPUT);
- pinMode(ignition_pin, INPUT);
- pinMode(unleaded_pin, INPUT);
- lcd.begin();
- lcd.clear();
- rtc.begin();
- Serial.begin(9600);
- // below recalls the values stored in case of power loss (change of the car battery or take it off for some modifications at the code)
- // So, the system does not loose the measurements when we take it off
- traveled_distance = EEPROM.readFloat(0);
- traveled_distance2 = EEPROM.readFloat (5);
- used_LPG = EEPROM.readFloat (10);
- used_LPG2 = EEPROM.readFloat(15);
- LPG_in_tank = EEPROM.readFloat(20);
- seconds_passed = EEPROM.readFloat(25);
- used_Unleaded = EEPROM.readFloat(30);
- traveled_distance3 = EEPROM.readFloat (35);
- used_Unleaded2 = EEPROM.readFloat(45);
- LPG1 = EEPROM.readByte (40);
- LPG2 = EEPROM.readByte (41);
- LPG3 = EEPROM.readByte (42);
- LPG4 = EEPROM.readByte (43);
- LPG_injector_flow = (LPG1 * 1000 + LPG2 * 100 + LPG3 * 10 + LPG4) * 1e-11;
- noInterrupts();
- // set and initialize the TIMER1
- TCCR1A = 0; // set entire TCCR1A register to 0
- TCCR1B = 0; // set entire TCCR1B register to 0
- TCCR1B |= (1 << CS12);//prescaler 256 --> Increment time = 256/16.000.000= 16us
- TIMSK1 |= (1 << TOIE1); // enable Timer1 overflow interrupt
- TCNT1 = 3036; // counter initial value so as to overflow every 1sec: 65536 - 3036 = 62500 * 16us = 1sec (65536 maximum value of the timer)
- attachPCINT(digitalPinToPinChangeInterrupt(ignition_pin), ignitionSignal, CHANGE); //enables the ignition signal change detection
- interrupts();
- delay(10);
- }
- void loop()
- {
- sensors.requestTemperatures();
- // When the ignition switch is turned, executes the next two ifs
- if (ignition == true && digitalRead(9) == LOW) // ignition key turned to OFF
- {
- detachInterrupt(digitalPinToInterrupt(vss_pin)); // disables the interrupts
- detachInterrupt(digitalPinToInterrupt(LPG_pin));
- detachPCINT(digitalPinToPinChangeInterrupt(unleaded_pin));
- delay(50);
- ignition = false; // this variable is necessary in order the code inside this "if" statement to run once
- // when the ignition switched off it stores the values to the EEPROM
- EEPROM.writeFloat (0, traveled_distance);
- EEPROM.writeFloat (5, traveled_distance2);
- EEPROM.writeFloat (10, used_LPG);
- EEPROM.writeFloat (15, used_LPG2);
- EEPROM.writeFloat (20, LPG_in_tank);
- EEPROM.writeFloat (25, seconds_passed);
- EEPROM.writeFloat (30, used_Unleaded);
- EEPROM.writeFloat (35, traveled_distance3);
- EEPROM.writeFloat (45, used_Unleaded2);
- sleep_enable(); // enables the sleep mode
- set_sleep_mode(SLEEP_MODE_PWR_DOWN); // set the sleep mode
- cli();
- sleep_bod_disable(); // disables the brown out detector to consume less power while sleeping
- sei();
- sleep_mode(); // microcontroller goes to sleep
- }
- // when it wakes up continues from here -- also the first time we turn the ignition key to ON starts from here
- if (ignition == true && digitalRead(9) == HIGH) // when the ignition key turned to ON
- {
- ignition = false; // this variable is needed in order to run once the code inside this if
- logohold = millis(); // this variable is used to hold the LOGO screen on, for 2 sec -- see below
- inst_disp = true;; // writes the display data to the display
- attachInterrupt(digitalPinToInterrupt(vss_pin), distance, RISING); // attaches the interrupt which related to the VSS signal
- attachPCINT(digitalPinToPinChangeInterrupt(unleaded_pin), UnleadedTime, CHANGE); // petrol injector signal input and interrupt activation
- // every 5sec calculates average LPG consumption, remaining distance accordingly to the calculated remaining fuel in tank, average speed and average Unleaded cons.
- }
- if(millis()%5000 < 50)
- {
- avg_LPG_consumption = 100 * used_LPG2/traveled_distance2;
- distance_to_LPGstation = 100 * LPG_in_tank/avg_LPG_consumption; //remaining distance for LPG
- avg_speed = (traveled_distance3 / seconds_passed)*3600; //average speed
- average_L_100km_Unlead = 100 * used_Unleaded2/traveled_distance2; //average l/100km for unleaded fuel
- }
- // For the short and long press function I consulted: http://jmsarduino.blogspot.gr/2009/05/click-for-press-and-hold-for-b.html
- // There are many differences though, mainly because I have built a hardware debounce for the buttons
- ////////// "button 1" functions /////////////////
- buttonState = digitalRead(11);
- if(buttonState==HIGH){
- if(menunumber<6){
- menunumber++;
- }
- else menunumber=0;
- }
- // if (buttonState2 == LOW && lastButtonState2 == HIGH) lastDebounceTime = millis(); //records the time that button1 pressed
- // if (buttonState2 == HIGH && lastButtonState2 == LOW)
- // {
- // if (ignoreRelease == false) // "button 1" SHORT PRESS functions -- on release
- // {
- // if (menunumber <= menunumbermax) // changes the display indications backwards
- // {
- // if (menunumber == 0) menunumber = menunumbermax;
- // else menunumber = menunumber - 1;
- // }
- // }
- // else ignoreRelease = false;
- // }
- // below are the misc screens
- switch (3)
- {
- case 0: // instant speed
- lcd.clear();
- lcd.setCursor(0,0);
- lcd.print(speed,0);
- lcd.setCursor(4, 0);
- lcd.print(F("km/h"));
- Serial.println((String)speed+" km/h");
- delay(10000);
- break;
- case 1: // avg speed
- lcd.clear();
- lcd.setCursor(0, 0);
- lcd.print(avg_speed, 0);
- lcd.setCursor(4, 0);
- lcd.print(F("km/h"));
- Serial.println((String)avg_speed+" km/h");
- delay(50000);
- break;
- case 2: // traveled distance
- lcd.clear();
- lcd.setCursor(0,0);
- lcd.print(traveled_distance, 1);
- lcd.print("km");
- Serial.println((String)traveled_distance+" km");
- delay(10000);
- break;
- case 3: //RTC and external Temperature
- temp1: if(inst_disp == true) displaychange = false, inst_disp = false;// these variables ensure that it will not go back to time set immediately
- lcd.clear();
- printTemperature();
- printTime();
- delay(10000);
- break;
- case 4: // avg Unleaded consumption
- lcd.clear();
- lcd.setCursor(0,0);
- if(isnan(average_L_100km_Unlead)|| isinf(average_L_100km_Unlead)) lcd.print(F("---"));
- else lcd.print(average_L_100km_Unlead, 1);
- lcd.print(F(" l/100"));
- Serial.println((String)average_L_100km_Unlead+" l/100km");
- delay(10000);
- break;
- case 5: //Unleaded Fuel
- lcd.clear();
- lcd.setCursor(0, 0);
- lcd.print(F("Fogyasztas "));
- lcd.print(used_Unleaded,1);
- lcd.print(F(" l"));
- Serial.println("Total unleaded "+(String)used_Unleaded+" l");
- delay(10000);
- break;
- }
- }
- ISR(TIMER1_OVF_vect){ //TIMER1 overflow interrupt -- occurs every 1sec -- it holds the time (in seconds) and also prevents the overflowing of some variables
- instantSpeed();
- unleadedConsumption();
- unleadinj_Open_Duration = 0;
- seconds_passed++;
- vss_pulses = 0;
- TCNT1 = 3036;
- }
- void distance(){// it is called everytime a pulse produced by the VSS sensor
- vss_pulses++;
- traveled_distance += vss_pulse_distance; // total traveled distance
- traveled_distance2 += vss_pulse_distance; // distance used at average LPG consumption calculations
- traveled_distance3 += vss_pulse_distance; // distance used at average speed calculations
- // we calculate 3 times the same thing in order to reset the distance, the average cons. and average speed independently
- }
- void instantSpeed(){ // current speed
- speed = (vss_pulse_distance * vss_pulses * 3600); // instant speed in km/h
- }
- void UnleadedTime(){// it is called every time a change occurs at the gasoline injector signal and calculates gasoline injector opening time, during the 1sec interval
- if (digitalRead(12) == LOW){
- unleadTime1 = micros();
- }
- if (digitalRead(12) == HIGH){
- unleadTime2 = micros();
- }
- if (unleadTime2 > unleadTime1){
- if ((unleadTime2 - unleadTime1) > 500 && (unleadTime2 - unleadTime1) < 12000){ // some conditions to avoid false readings because of noise
- // my injectors do not open for longer than 12ms = 12000us (you can change this if you want)
- unleadinj_Open_Duration = unleadinj_Open_Duration + (unleadTime2 - unleadTime1); //total useconds that the gasoline injector opens throughout 1sec
- }
- }
- }
- void unleadedConsumption(){
- used_Unleaded = used_Unleaded + (unleadinj_Open_Duration * unleadedFlow); //total litres of gasoline consumed -- calculated every 1sec
- used_Unleaded2 = used_Unleaded2 + (unleadinj_Open_Duration * unleadedFlow); //this is used in average unleaded consumption calculation
- }
- // ignition signal (sleep - wake up) interrupt routine
- void ignitionSignal(){ // this is called everytime the ingintion signal changes -- if the microcontroller is in sleep mode, it will wake up
- ignition = !ignition;
- }
- void printTime(){ // print the time
- DateTime dt = rtc.now();
- lcd.setCursor(5,1);
- lcd.print((String)dt.year()+"."+(String)dt.month()+"."+(String)dt.day());
- lcd.setCursor(7,0);
- lcd.print((String)dt.hour()+":"+(String)dt.minute());
- Serial.println((String)dt.year()+"."+(String)dt.month()+"."+(String)dt.day());
- Serial.println((String)dt.hour()+":"+(String)dt.minute());
- }
- void printTemperature(){ //temperature calcualation
- sensors.requestTemperatures();
- float temp=sensors.getTempCByIndex(0);
- float temp2=sensors.getTempCByIndex(1);
- lcd.setCursor(3,2);
- lcd.print("Belso hom.: "); lcd.print(temp2,0);
- lcd.setCursor(3,3);
- lcd.print("Kulso hom.: "); lcd.print(temp,0);
- Serial.println("Inside: "+(String)temp+" Outside: "+(String)temp2);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement