PHP код:
	
#include <LiquidCrystal.h>
// номинал форсунки 0.0032 мкл/мкс.
// предделитель таймера для максимальной точности берем 1, т.е. при каждом переполнении (256 циклов) будет проходить 16 мкс
// с учетом предделителя берем расход в 16 мкс, т.е. 0.0512мкл/16мкс. Точность (и кратность) замера расхода 0.0512мкл
// поскольку дробные вычисления занимают больше времение и памяти, то от дроби надо избавится
// Также на дисплей будут выводиться не литры в час и литры/100км, а мл/ч и мл/100км. Возможно позже переделаю.
// Нужно реализовать чтение из памяти и запись в память переменной dur, которая хранит кол-во сожженных литров всего (как одометр км).
// Также нужно реализовать фиксацию максимального и минимального мгновенного расхода на 100 км с фиксацией скоростей и оборотов двигателя.
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // параметры подключения дисплея, пины на ардуине
unsigned long dur; // предел = 21500 литров, хранит кол-во сожженноготоплива с момента запуска проекта
unsigned long dur_t; // предел = 215 литров, считает от включения до выключения зажигания
unsigned long cur_ms; //кол-во мс с момента запуска микроконтроллера = мс с момента включения зажигания.
unsigned long prev_ms; // используется для определения интервалов времени, мс.
int ms; //количество прошедших мс
volatile long mks16; //сколько раз по 16 мкс форсунка впрыскивала топливо.
unsigned long m; //одометр
int interval; // интервал обновления экрана и период расчета мгновенного расхода, мс.
unsigned long aver; // переменная для расчета расхода за прошедший заданный интервал
unsigned long aver_temp; // еще одна вспомогательная
int aver_h; //прогнозируемый по последним 3 секундам расход мл/ч
int aver_100; //прогнозируемый по последним 3 секундам расход мл/100км
void setup()
{
lcd.begin(16, 2);
attachInterrupt(2, start, FALLING); //подключаем срабатывание прерывания по внещнему сигналу, при переходе с 1 в 0 будет срабатывать код команды start
// attachInterrupt(3, odometer, CHANGE); //подключаем срабатывание прерывания по внещнему сигналу, при изменении с 0 в 1 и наоборот. будет срабатывать код команды odometer
dur_t = 0;
dur = 0; //вместо обнуления здесь должна быть процедура извлечения данных из памяти EEPROM, общий расход топлива.
mks16 = 0;
TCCR2A = 0; //режим работы таймера, выбран нормальный
TCCR2B = 1; //предделитель тиков таймера = частоте процессора, при каждом переполнении будет проходить 16мкс
TCNT2=0; // это и есть то "место", которое считает такты и будет переполняться по достижению 255+1 и генерировать прерывание.
//с помощью установки этого значения можно менять дробность, например, если постоянно ставить начальное значение 96, то за оставшиеся 160 тиков будет проходить 10мкс
aver = 0;
aver_temp = 0;
aver_h = 0;
aver_100 = 0;
interval = 3000;
}
//обработчик прерывания по переполнению таймера
ISR(TIMER2_OVF_vect) {
    mks16++;
}
//внешнее прерывание
void start() {
    TCNT2=0; //обнуление натикавшего таймера
    TIMSK2 |= (1 << TOIE2); //разрешаем прерывания по переполнению таймера
    attachInterrupt(2, stop, RISING); //переключение режима прерывания
}
//внешнее прерывание
void stop() {
    TIMSK2 &= ~(1<<TOIE2); //запрет прерывания по переполнению таймера
    dur_t = dur_t + mks16; //при каждой остановке полученный замер добавляем в переменную
    mks16 = 0; //обнуляем, чтобы не дублировать и не трогать эту переменную
    //каждые 10 000 000 "тиков" по 16мкс передаем показания для хранения и учета сожженного топлива, что соответствует сожженным 512мл
    if (dur_t > 10000000) {
        dur = (dur + dur_t) / 100; //загрубляем данные, хотя если разделить на 100 000, то точность будет 5мл :) т.е. данная точность - 5мкл
        dur_t = 0; //обнуляем переменную
    }
    attachInterrupt(2, start, FALLING); //переключение режима прерывания    
}
//основная программа
void loop() {
    cur_ms = millis(); //переменной присваиваем значение "натикавшего" таймера 1 в мс, который стартует с момента включения ардуины
    if (cur_ms - prev_ms > interval) { //отбиваем заданный интервал 3с
        prev_ms = cur_ms; //первым делом записываем на каком значении таймера 1 мы начали
        if (dur_t > 1000) { //проверка чтобы мы не сбрасывали показания на дисплее в ноль, можно убрать проверку совсем
            if (dur_t > aver_temp) { //еще одна проверка, чтобы при обнулении dur_t не получить в вычислении отрицательное значение
                aver = dur_t - aver_temp; //определяем суммарную длительность впрысков за прошедший интервал времени
                aver_temp = dur_t; //сохраняем показатель для расчета в следующем цикле
                aver_h = aver / 1000 * 61; //переходим к миллилитрам, 61 - это расчетная величина по паспортному номинальному расходу форсунки
            } else {
            aver_temp = dur_t;
            }
        }
        lcd.clear();
        lcd.setCursor (0,0); //говорим дисплею приготовится выводить с первого символа первой строки нижеследующее
        lcd.print (aver_h); //выводим на дисплей мгновенный расход мл/ч
        lcd.setCursor (8,0);
        lcd.print (mks16); 
        lcd.setCursor (0,1);
        lcd.print (dur_t); //выводим на дисплей суммарное кол-во сожжений по 5мкл
        lcd.setCursor (8,1);
        lcd.print (dur); //выводим на дисплей суммарное кол-во сожжений по 500мкл
    }
}