Бортовой компьютер для Опель Зафира.

Sergei H.
Offline
Зарегистрирован: 17.11.2018

Попробовал это не то.А вот когда пробовал удалять конвертацию из галлонов в литры и наоборот, чтобы совсем убрать СТРОКА 2679 и так далее .Вместо -$1,325+     получилось -10,0какой то символ+ .Где то здесь наверное нужно изменять.GasConst 3355 это я понял для расчёта расхода топлива. Ещё такой вопрос,здесь контрастность меняется по шим сигналу.Где в коде можно увеличить частоту ,чтобы мерцание было меньше.Спасибо.

Sergei H.
Offline
Зарегистрирован: 17.11.2018

Или где то здесь.

 

cd_cls_print_P(PSTR("Fuel Price ("));
4000
          oldUIntValue = params.gas_price;
4001
 
4002
 
4003
          fuelUnits = params.gas_price;
4004
          // convert in gallons if requested
4005
 
4006
 
4007
        #ifdef AllowChangeUnits
4008
          if(params.use_metric)
4009
          {
4010
            lcd_print_P(PSTR("L)"));
4011
          }
4012
          else
4013
          {
4014
            // Convert unit price to litres for the cost per gallon. (ie $1 a litre = $3.785 per gallon)
4015
            fuelUnits = (fuelUnits * 378L) / 100L; //convertToLitres(params.gas_price);
4016
            lcd_print_P(PSTR("G)"));
4017
          }
4018
        #else
4019
          #ifdef UseSI
4020
            lcd_print_P(PSTR("L)"));
4021
          #endif 
4022
          #ifdef UseUS
4023
            // Convert unit price to litres for the cost per gallon. (ie $1 a litre = $3.785 per gallon)
4024
            fuelUnits = (fuelUnits * 378L) / 100L; //convertToLitres(params.gas_price);
4025
            lcd_print_P(PSTR("G)"));
4026
          #endif 
4027
        #endif

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

я вроде нашел косяк. Для того, чтобы данные на экран обновлялись только при их изменении, ты ввёл переменные с постфиксом _last

Дак вот в том числе и для переменной Fuel ты сделал Fuel_last  для такого вывода на экран.   

 А переменная Fuel_last у нас уже была и использовалась в бортовике для расчёта среднего расхода и расстояния до заправки. А при выводе на экран ты эту переменную портишь, поэтому все расчёты в гавно. 

исправил

//------------все для связи по K-line (тут настраиваем UARTы к-лайников, адреса блоков, скорость инита и отладку) 
#include <SoftwareSerial.h>
 #define TX_PCM 13
 SoftwareSerial K_LINE_PCM   (12, TX_PCM); //RХ,TХ    //UART на котором висит K_line к PCM

#define K_LINE_GAUGE Serial2   //UART     на котором висит K_line к приборке 
#define TX_gauge 16            //TX UARTa на котором висит K_line к приборке 

#define PCM_address  0x11      // адрес PCM 
#define DIAG_address 0xF1      // адрес диагностики

const byte BAUD=200;           // init baudrate - скорость инита при подключении к приборке 
const byte addressGUAGE = 0xB8;// init GAUGE address - адрес щитка приборов при ините (установке связи)

#define debugPCM             // раскоментировать эту строку для отладки в Serial порту обмена с PCM
//#define debugGAUGE             // раскоментировать эту строку для отладки в Serial порту обмена co щитком приборов
//#define debugTRIP             // раскоментировать эту строку для отладки в Serial порту данных бортовика
 
uint32_t curmillis = 0;        // снимок текущего времени 
 
//------------------------------------------переменные для организации протокола связи с PCM

uint32_t prevRequest  = 0;     // таймер периодических запосов на PCM
uint16_t RequestPeriod = 3500; // периодичность запросов на PCM
byte header = 0;               // состояние заголовка
bool NOanswer_timer = 0;       // таймер контроля неответов от ЭБУ после подачи запросов
uint32_t prev_NOanswer=0;      // таймер контроля неответов от ЭБУ после подачи запросов
// возможные варианты запросов на ЭБУ:
enum REQUEST {INIT, PID, DTCERASE, DTCREAD, PRESENT,};

#ifdef debugPCM 
// текстовки запросов для отладки 
char* textRequest[] = {"INIT", "PID_2101", "DTC_ERASE", "DTC_READ", "PRESENT",} ;
#endif 

 // сами запросы
 byte PCM_Message_TX[][5] = {
 {1,  0x81,           0,0,0},    // запрос инициализации
 {2,  0x21,0x01,        0,0},    // запрос пид 2101
 {3,  0x14,0xFF,0x00,     0},    // запрос на стирание ошибок
 {4,  0x18,0x00,0xFF,0x00  },    // запрос на чтение ошибок
 {1,  0x3E,           0,0,0},    // запрос присутствия 
                            };
byte request = INIT;             // переменная, показывающая какой запрос будем делать
static byte headerGAUGE = 0;            // состояние заголовка сообщений щитка  приборов

const byte bufsize = 150;           // размер буфера принятого сообщения
byte MessageRx_PCM [bufsize] = {0}; // буфер принятого сообщения


//-------------------------------------------переменные бортовика

 float L100M = 0;      //расход на 100 км измеренный за поездку
 float L100 = 0;       //мгновенный расход литров на 100км
 float LHor = 0;       //мгновенный расход топлива литров в час
 float L100SR = 0;     //расход литров на 100км измеренный раз в интервал kmL  
 float L100SR_TFT = 0; // самый средний из расходов на 100км, он выводится на экран

 int L100_Eeprom[11]= {10,10,10,10,10,10,10,10,10,10,10};
 int FuelZamer[10]= {0};  // массив для измерения уровня (количества) топлива 
 int ZamerNumber = 0;     // номер замера уровня (количества) топлива 
 
 
 int MAF = 0;            //26,27 байты   Sensor de flujo de aire en masa
 float BoostPres = 0;    //28,29 байты   Presión de refuerzo
 int RPM = 0;            //32,33 байты   Velocidad del motor
 int EGRmg = 0;          //34,35 байты   Comando EGR (Comando de recirculación de gases de escape)
 float BoostPresCom = 0; //38,39 байты   Comando de presión de refuerzo
 int Speed = 0;          //44,45 байты   Velocidad del vehículo
 float DesaInjQua = 0;   //50,51 байты   Cantidad de inyección deseada
 float InjQua = 0;       //52,53 байты   Cantidad de la inyección
 float StaDaliv = 0;     //54,55 байты   Inicio de la entrega
 int PumpRPM = 0;        //56,57 байты   Velocidad de la bomba
 float EGRPul = 0;       //62,63 байты   Relación de impulsos EGR (recirculación de gases de escape
 float SolenPul = 0;     //64,65 байты   Velocidad de solenoide de control de nivel de remolino Relación de impulsos
 float SolenPre = 0;     //70,71 байты   Relación de impulsos Presión Electroválvula de presión
 float DesInj = 0;       //72,73 байты   Inyección deseada Inicio
 float ActInj = 0;       //16,17 байты   Inicio de la inyección real
 int TempAir = 0;        //74,75 байты   Temperatura del aire de admisión
 int Temp = 0;           //14,15 байты   Temperatura del refrigerante
 int TempOil = 0;        //18,19 байты   Temperatura del aceite del motor
 int TempFuel = 0;       //58,59 байты   Temperatura del combustible
 int IntTemp = 0;        //Температура улицы
 
 //все что касается топлива
 float Fuel = 0;       //остаток топлива 
 float Fuel2 = 0;    float Fuel2_last = 1; //остаток мгновенного топлива байт 16 , датчика в баке
 int FuelIGN = 0;      // количество топлива в баке на момент включения зажигания
 float fuel_last = 0;    // для формул
 bool flagFuelIGN = 0; // флаг записан ли остаток топлива в момент вкл. зажигания 
 float FuelTrip = 0; float FuelTrip_last = 1;    // количество литров топлива, израсходованное за один цикл включения зажигания
 
 //все что касается километража
 float kmAge = 0;           //пробег, полученный со щитка приборов
 int kmAgeIGN = 0;          //пробег который был в момент включения зажигания 
 int kmAge_last = 0;        // для формул
 bool flagkmAgeIGN = 0;     //флаг записан ли пробег в момент вкл. зажигания 
 float kmTrip = 0; float kmTrip_last = 1;           //пробег за один цикл включения зажигания
 const int kmL = 10;              // интервал, через который будет происходить обновление среднего расхода на 100км
 int km = 0;                // переменная для расчетов
 const int kmeeprom = 15;         // интервал, через который будет происходить подсчет среднеарифмитического расхода  L100SR_TFT
 int kmTFT =  0;     // переменная для расчетов периодического подсчета среднеарифмитического расхода топлива L100SR_TFT
 int kmREFUELING = 0; int kmREFUELING_last = 1;     // пробег до заправки на остатке топлива 
 
 unsigned long prevWatch = 0;
 unsigned long prevDvoet = 0;
 

//----------------------------------------------для экрана 
#include <Adafruit_GFX.h>
 #include <MCUFRIEND_kbv.h>
 #include <UTFTGLUE.h>//use GLUE class and constructor
 #include "TouchScreen.h"
 #include <stdint.h>
 #include <SPI.h>
 #include <EEPROM.h>
 //#include "Fonts/Chosence_Bold16pt7b.h";

#define MINPRESSURE 200
#define MAXPRESSURE 1000

//pin 20 SCL , 21 SDA датчик реального времени
 #include <Wire.h>
 #include "RTClib.h"
 RTC_DS3231 rtc;       

UTFTGLUE myGLCD(0x1581,A2,A1,A3,A4,A0); //all dummy args
 
 const int XP = 6, XM = A2, YP = A1, YM = 7; 
 const int TS_LEFT = 136, TS_RT = 907, TS_TOP = 139, TS_BOT = 942;
 TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
 uint16_t ID;
 int x, y;
 char currentPage;
 float h; int h_last = 1; 
 float t; int t_last = 1; 
 bool Dvoet = 0;
 bool reNew = 0;
 #define BLACK 0x0000
 #define WHITE 0xFFFF
 #define RED   0xF800
 #define GREEN 0x07E0

 //--------------------------------------датчики t

byte DSaddress[] = {0x28, 0xFF, 0xA6, 0x19, 0xA8, 0x15, 0x01, 0xD2};
//датчик внутринней температуры и влаги
 #include "DHT.h"
 #define DHTPIN 26   
 #define DHTTYPE DHT22 
 DHT dht(DHTPIN, DHTTYPE);
#include <OneWire.h>
 #define ONE_WIRE_BUS 22   
 OneWire ds(ONE_WIRE_BUS);



 
void setup() {
   uint16_t ID = myGLCD.readID();
   if (ID == 0xD3D3) ID = 0x1581; // write-only shield
   myGLCD.begin(ID);  
   myGLCD.InitLCD(3);
   myGLCD.clrScr();
   myGLCD.setTextSize(2);
   //myGLCD.setFont(&Chosence_Bold16pt7b);
   Wire.begin();
   rtc.begin();
   dht.begin();
   //загрузка стартовой страницы
   currentPage = '0';       
   drawHomeScreen();  

   //подсчет среднеарифметического усредненного расхода
   int summ=0;
 for (int i = 0; i < 11; i++) summ +=  EEPROM.read(i);
 L100SR_TFT = summ / 110.00;
   if (L100SR_TFT<0) L100SR_TFT = 0;
   if (L100SR_TFT>99) L100SR_TFT = 99;
  
   // строка ниже используется для настройки даты и времени часов 
   // раскоментировать, выставить времая и дату, залить в ардуино. в скетче закоментировать
   // обратно и залить еще раз, иначе каждый раз будет по новой выствлятся это же время и дата
   // (год, месяц, день, часы, минуты, секунды)
   //rtc.adjust(DateTime(2019, 7, 2, 10, 48, 0));
  
 #if defined debugPCM or defined debugGAUGE or defined debugTRIP
   Serial.begin(115200);
 #endif
   K_LINE_PCM.begin(10400);
   pinMode(TX_PCM, OUTPUT);
  
             }


    void loop() 
                {
                  
curmillis = millis();              // снимок текущего времени

if (curmillis - prevRequest > RequestPeriod && header == 0 ) 
    {
  if (request == INIT) fastinit();                                          // при необходимости делаем переподключение к PCM
  else {sendMessagePCM(request);                                            // отправляем на PCM текущий запрос
         if (request == PID) RequestPeriod = 600; 
         if (request == DTCERASE || request == DTCREAD) RequestPeriod = 2500;} 
  prevRequest = curmillis;
    }

receivePCM ();   // приём сообщений от PCM
receiveGAUGE (); // приём сообщений от щитка приборов
if (header == 0 && headerGAUGE == 0) {Menu ();}
if (curmillis - prevWatch > 4000)  { Watch (); prevWatch = curmillis; Trip (); h = dht.readHumidity(); t = dht.readTemperature();Temperature ();}
//if (curmillis - prevDvoet > 500)  { if (!Dvoet) {myGLCD.setTextColor(WHITE); } else {myGLCD.setTextColor(BLACK); }  myGLCD.print(":", 290, 5); prevDvoet = curmillis; Dvoet=!Dvoet;}                
if (millis() - prevDvoet > 500)  { if (!Dvoet) {myGLCD.print(":", 280, 5);} else {myGLCD.print(" ", 290, 5);} prevDvoet = millis(); Dvoet=!Dvoet;}
                }// end loop

 void fastinit() {
   digitalWrite (TX_PCM, HIGH);  // bus idle
   delay(1500);              
   digitalWrite (TX_PCM, LOW);  // first part fastinit  (25 ms LOW)
   delay(25);
   digitalWrite (TX_PCM, HIGH); // second part fastinit (25 ms HIGH)
   delay(25);               
   K_LINE_PCM.begin(10400);
   sendMessagePCM(INIT);        // send start communication message 
      }  
 
  
  void receivePCM () {

static uint32_t prevRESETheader=0;    // таймер сброса сообщения, если данные оборвались посередине сообщения 
static bool RESETheader_timer;        // таймер сброса сообщения, если данные оборвались посередине сообщения 
static byte noanswers = 0;            // количество подряд неответов от ЭБУ 
static byte message_size = 0;         // размер тела сообщения
static byte j = 3;                    // инкремент
static byte n = 3;                    // количество старт байт
static byte crc =0;                   // байт контрольной суммы 



 if (K_LINE_PCM.available() ){
    
 // первый старт байт
 if (header == 0){ MessageRx_PCM[0]=K_LINE_PCM.read();  
         if (MessageRx_PCM[0]!=0xFF && bitRead (MessageRx_PCM[0],7)){header = 1; RESETheader_timer = 1; prevRESETheader = curmillis; 
               #ifdef debugPCM
                  Serial.print (F("Receive PCM: ")); printDebugRX(MessageRx_PCM[0]);
               #endif               
                                                }
                          }                  

 // второй старт байт
 else if (header == 1){ MessageRx_PCM[1]=K_LINE_PCM.read(); 
 #ifdef debugPCM
      printDebugRX (MessageRx_PCM[1]);
 #endif
      if (MessageRx_PCM[1]==DIAG_address){ header = 2;} 
      else {
        #ifdef debugPCM 
        Serial.println(F(" PCM Message fail address")); 
        #endif
        header = 0; RESETheader_timer = 0;}} 

 // третий старт байт
 else if (header == 2){ 
  MessageRx_PCM[2]=K_LINE_PCM.read(); 
  #ifdef debugPCM
  printDebugRX (MessageRx_PCM[2]);
  #endif
  if (MessageRx_PCM[2]==PCM_address){ message_size = MessageRx_PCM[0]; prevRESETheader = curmillis;
       if (MessageRx_PCM[0] !=0x80) {header = 4;  bitWrite (message_size, 7 , 0);j=3;n=3;}
       else {header = 3; j=4;n=4;}
       if (message_size > bufsize) message_size = bufsize;  crc = 0;} 
  else {header = 0; 
        #ifdef debugPCM 
        Serial.println(F("PCM Message fail address")); 
        #endif
        RESETheader_timer = 0;}
  
                          }  
// если размер сообщения указан в дополнительном байте (нулевой байт 0x80) читаем этот дополнительный байт:
else if (header == 3){
   prevRESETheader = curmillis;
  MessageRx_PCM[3]=K_LINE_PCM.read(); 
  #ifdef debugPCM
  printDebugRX(MessageRx_PCM[3]);
  #endif
  message_size = MessageRx_PCM[3]; 
  if (message_size > bufsize) message_size = bufsize;  
  crc = 0; header = 4;  
                         }

  // пишем тело сообщения 
 else if (header == 4 && j< message_size+n+1) {
 MessageRx_PCM[j] = K_LINE_PCM.read(); prevRESETheader = curmillis;
 if (j<message_size+n) crc+= MessageRx_PCM[j]; // подсчёт КС
 
 if (j==message_size+n) header = 5; 
 #ifdef debugPCM
 printDebugRX(MessageRx_PCM[j]);
 #endif  
 j++;                                             } 
 }

 // сообщение приняли, действуем
 if (header == 5) {
 #ifdef debugPCM
 Serial.println();
 #endif  
 NOanswer_timer = 0; noanswers = 0;              // сбрасываем таймер контроля неответов 
  
for(byte i = 0; i<n; i++) crc+=MessageRx_PCM[i]; // прибавляем к контрольной сумме старт байты

 // если контрольная сумма верна: 
if ( crc == MessageRx_PCM[message_size+n]) 
{  
  #ifdef debugPCM
  Serial.print (F("Received message is OK! Checksum is correct!"));  Serial.print (F("  ")); Serial.println (millis()); // Если КС совпала, тут чёнибудь нужное делаем
  printDebugRX_CSgood(n); 
  #endif
      if (MessageRx_PCM[n]==0xC1 && MessageRx_PCM[n+1]==0x6B && MessageRx_PCM[n+2]==0x8F) {
              if (currentPage!=3) {request = PID; RequestPeriod = 70;} else request = PRESENT, RequestPeriod = 4000; prevRequest = curmillis; // receive good INIT
                                                                                          }
 else if (MessageRx_PCM[n]==0x58) Troublecodes (n); // DTC
 else if (MessageRx_PCM[n]==0x54 && MessageRx_PCM[n+1]==0xFF && MessageRx_PCM[n+2]==0x00){ request = PRESENT; RequestPeriod = 4000; prevRequest = curmillis;} // DTC are cleared
 else if (MessageRx_PCM[n]==0x61 && MessageRx_PCM[n+1]==0x01) {dataVars(n) ; RequestPeriod = 70; prevRequest = curmillis; }           // receive DataStream
 
 
 }   

// если контрольная сумма не совпала: 
#ifdef debugPCM
  else Serial.println("CRC fail!!!" );
#endif
message_size = 0; header=0; RESETheader_timer = 0; j=3; crc = 0;
}

// таймер сброса целостности сообщения (если данные оборвались посередине сообщения)
if (RESETheader_timer && curmillis - prevRESETheader > 200) { 
  #ifdef debugPCM 
  Serial.println(F("Message fail timeout")); 
  #endif 
  RESETheader_timer = 0; header = 0;}   

 
// если нет ответа после запроса: +1 к счетчику неответов. Если накопилось 6 и более: делаем реинит.  
if (request!=INIT && NOanswer_timer && curmillis - prev_NOanswer > RequestPeriod - RequestPeriod/10) 
         {
     NOanswer_timer = 0; noanswers++; 
     if (noanswers>=6) { noanswers = 0; request = INIT; RequestPeriod = 3500;}
         }
}// end receivePCM


void Troublecodes (const byte &n) 
{
  if (MessageRx_PCM[n]==0x58 && MessageRx_PCM[n+1]==0x00){
    myGLCD.clrScr();             
    drawscreen_three();      
    myGLCD.print("NO DTC", 180, 145);
    
                         }
 
  // при получении сообщения о наличии ошибок DTC разберем сообщение выведем на экран ошибки
  if (MessageRx_PCM[n]==0x58 && MessageRx_PCM[n+1]>0){
     
     myGLCD.clrScr();             
     drawscreen_three();       

  for (int i=0; i<MessageRx_PCM[n+8-7]; i++ ) {
     int y = i*35;
     bool nolA=0; bool nolB =0;
  if (!bitRead(MessageRx_PCM[n+11-7+(i*3)],6) && bitRead(MessageRx_PCM[n+11-7+(i*3)],7)){ myGLCD.setTextColor(GREEN, BLACK); 
     myGLCD.print(" -Passive-", 300, (75+y));} // если DTC пасивныый делаем цвет зеленый 
  if (bitRead(MessageRx_PCM[n+11-7+(i*3)],7) && bitRead(MessageRx_PCM[n+11-7+(i*3)],6)) { myGLCD.setTextColor(RED, BLACK);  
     myGLCD.print(" -Active-", 300, (75+y));} // если DTC активный, делаем цвет красный 
     myGLCD.print("ERROR ", 50, (75+y));
     myGLCD.printNumI((i+1), 150, (75+y));
     
  if (!bitRead(MessageRx_PCM[n+9-7+(i*3)],6) && !bitRead(MessageRx_PCM[n+9-7+(i*3)],7)) myGLCD.print(": P", 170, (75+y));
  if (bitRead(MessageRx_PCM[n+9-7+(i*3)],6) && !bitRead(MessageRx_PCM[n+9-7+(i*3)],7)) myGLCD.print(": C", 170, (75+y));
  if (!bitRead(MessageRx_PCM[n+9-7+(i*3)],6) && bitRead(MessageRx_PCM[n+9-7+(i*3)],7)) myGLCD.print(": B", 170, (75+y));
  if (bitRead(MessageRx_PCM[n+9-7+(i*3)],6) && bitRead(MessageRx_PCM[n+9-7+(i*3)],7)) myGLCD.print(": U", 170, (75+y));

  if (MessageRx_PCM[n+9-7+(i*3)]==0x00) {myGLCD.print("00", 230, (75+y)); nolA = 1;}
  if (MessageRx_PCM[n+9-7+(i*3)]<=0x0F&&MessageRx_PCM[n+9-7+(i*3)]!=0) {myGLCD.print("0", 230, (75+y)); nolA = 1;} 
  if (nolA)myGLCD.print(String (MessageRx_PCM[n+9-7+(i*3)],HEX), 246, (75+y)); 
  else myGLCD.print(String (MessageRx_PCM[n+9-7+(i*3)],HEX), 230, (75+y));

  if (MessageRx_PCM[n+10-7+(i*3)]==0x00) {myGLCD.print("00", 262, (75+y)); nolB = 1;}
  if (MessageRx_PCM[n+10-7+(i*3)]<=0x0F&&MessageRx_PCM[n+10-7+(i*3)]!=0) {myGLCD.print("0", 262, (75+y)); nolB = 1;}
  if (nolB)myGLCD.print(String (MessageRx_PCM[n+10-7+(i*3)]),HEX, 278, (75+y)); 
  else myGLCD.print(String (MessageRx_PCM[n+10-7+(i*3)],HEX), 262, (75+y));}} 

request = PRESENT; RequestPeriod = 4000;  prevRequest = curmillis;

}



void dataVars(const byte &n) 
{

static float L100M_last = 1;              //расход на 100 км измеренный за поездку
static float L100_last = 1;               //мгновенный расход литров на 100км
static float LHor_last = 1;               //мгновенный расход топлива литров в час
static float L100SR_TFT_last = 1;         // самый средний из расходов на 100км, он выводится на экран

static int MAF_last = 1;           //26,27 байты   Sensor de flujo de aire en masa
static float BoostPres_last = 1;   //28,29 байты   Presión de refuerzo
static int RPM_last = 1;           //32,33 байты   Velocidad del motor
static int EGRmg_last = 1;         //34,35 байты   Comando EGR (Comando de recirculación de gases de escape)
static float BoostPresCom_last = 1;//38,39 байты   Comando de presión de refuerzo
static int Speed_last = 1;         //44,45 байты   Velocidad del vehículo
static float DesaInjQua_last = 1;  //50,51 байты   Cantidad de inyección deseada
static float InjQua_last = 1;      //52,53 байты   Cantidad de la inyección
static float StaDaliv_last = 1;    //54,55 байты   Inicio de la entrega
static int PumpRPM_last = 1;       //56,57 байты   Velocidad de la bomba
static float EGRPul_last = 1;      //62,63 байты   Relación de impulsos EGR (recirculación de gases de escape
static float SolenPul_last = 1;    //64,65 байты   Velocidad de solenoide de control de nivel de remolino Relación de impulsos
static float SolenPre_last = 1;    //70,71 байты   Relación de impulsos Presión Electroválvula de presión
static float DesInj_last = 1;      //72,73 байты   Inyección deseada Inicio
static float ActInj_last = 1;      //16,17 байты   Inicio de la inyección real
static int TempAir_last = 1;       //74,75 байты   Temperatura del aire de admisión
static int Temp_last = 1;          //14,15 байты   Temperatura del refrigerante
static int TempOil_last = 1;       //18,19 байты   Temperatura del aceite del motor
static int TempFuel_last = 1;      //58,59 байты   Temperatura del combustible
static int IntTemp_last =  1;      //Температура улицы
static float Fuel_last =  1;         //уровень топлива в баке 



  
  //Barom = MessageRx_PCM[39];
   LHor = (float)RPM* (float)InjQua*2.00/1000.0*60.00/1000.0/0.85;
   L100 = (float)LHor*100.0/(float)Speed;
   MAF =  ((MessageRx_PCM[n+22]*256)+MessageRx_PCM[n+23])/10;
   BoostPres =  ((MessageRx_PCM[n+24]*256)+MessageRx_PCM[n+25])/1000.0;
   RPM =  (MessageRx_PCM[n+35-7]*256)+MessageRx_PCM[n+36-7];
   EGRmg =  ((MessageRx_PCM[n+37-7]*256)+MessageRx_PCM[n+38-7])/10.0;
   BoostPresCom =  ((MessageRx_PCM[n+41-7]*256)+MessageRx_PCM[n+42-7])/1000.0;
   Speed =  ((MessageRx_PCM[n+47-7]*256)+MessageRx_PCM[n+48-7])/100;
   DesaInjQua =  ((MessageRx_PCM[n+53-7]*256)+MessageRx_PCM[n+54-7])/100.0;
   InjQua =  ((MessageRx_PCM[n+55-7]*256)+MessageRx_PCM[n+56-7])/100.0;
   StaDaliv =  ((MessageRx_PCM[n+57-7]*256)+MessageRx_PCM[n+58-7])/100.0;
   PumpRPM =  (MessageRx_PCM[n+59-7]*256)+MessageRx_PCM[n+60-7];
   EGRPul =  ((MessageRx_PCM[n+65-7]*256)+MessageRx_PCM[n+66-7])/100.0;
   SolenPul =  ((MessageRx_PCM[n+67-7]*256)+MessageRx_PCM[n+68-7])/100.0;
   SolenPre =  ((MessageRx_PCM[n+73-7]*256)+MessageRx_PCM[n+74-7])/100.0;
   DesInj =  ((MessageRx_PCM[n+75-7]*3)+(MessageRx_PCM[n+76-7])/100.0)+0.3;
   ActInj =  ((MessageRx_PCM[n+19-7]*3)+(MessageRx_PCM[n+20-7])/100.0)+0.3;
   //TempAir =  ((MessageRx_PCM[n+77-7]*26)-278)+MessageRx_PCM[n+78-7]/10.0;
   //Temp =  ((MessageRx_PCM[n+17-7]*26)-278)+MessageRx_PCM[n+18-7]/10.0;
   //TempOil =  ((MessageRx_PCM[n+21-7]*26)-278)+MessageRx_PCM[n+22-7]/10.0;
   //TempFuel =  ((MessageRx_PCM[n+61-7]*26)-278)+MessageRx_PCM[n+62-7]/10.0;
   //ниже идут расчетные формулы более точные чем те что закоментированы выше
   int A = 0;
   if  (MessageRx_PCM[n+77-7]<=0x0A) A = 277;
   if  (MessageRx_PCM[n+77-7]==0x0B || MessageRx_PCM[n+77-7]==0x0C) A = 278;
   if  (MessageRx_PCM[n+77-7]>=0x0D) A = 279;
   double B = MessageRx_PCM[n+78-7]/10.0;
   double cel , drob ;
   drob = modf(B, &cel);
   if (drob>0.6) cel++;
     TempAir =  ((MessageRx_PCM[n+77-7]*26)-A)+cel;
   
   if  (MessageRx_PCM[n+17-7]<=0x0A) A = 277;
   if  (MessageRx_PCM[n+17-7]==0x0B || MessageRx_PCM[n+17-7]==0x0C) A = 278;
   if  (MessageRx_PCM[n+17-7]>=0x0D) A = 279;
   B = MessageRx_PCM[n+18-7]/10.0;
   drob = modf(B, &cel);
   if (drob>0.6) cel++;
     Temp =  ((MessageRx_PCM[n+17-7]*26)-A)+cel;


   if  (MessageRx_PCM[n+21-7]<=0x0A) A = 277;
   if  (MessageRx_PCM[n+21-7]==0x0B || MessageRx_PCM[n+21-7]==0x0C) A = 278;
   if  (MessageRx_PCM[n+21-7]>=0x0D) A = 279;
   B = MessageRx_PCM[n+22-7]/10.0;
   drob = modf(B, &cel);
   if (drob>0.6) cel++;
     TempOil =  ((MessageRx_PCM[n+21-7]*26)-A)+cel;


   if  (MessageRx_PCM[n+61-7]<=0x0A) A = 277;
   if  (MessageRx_PCM[n+61-7]==0x0B || MessageRx_PCM[n+61-7]==0x0C) A = 278;
   if  (MessageRx_PCM[n+61-7]>=0x0D) A = 279;
   B = MessageRx_PCM[n+62-7]/10.0;
   drob = modf(B, &cel);
   if (drob>0.6) cel++;
     TempFuel =  ((MessageRx_PCM[n+61-7]*26)-A)+cel;   
     
  //----------------------------------------------------------
  //страниц HOME
  //----------------------------------------------------------
     
     //myGLCD.setBackColor(RED);
     myGLCD.setTextColor(WHITE, BLACK);
     //myGLCD.setBackColor(RED);
     if ((Speed != Speed_last) || reNew) {myGLCD.printNumI(Speed, 360, 7, 3); Speed_last=Speed;}
  if (currentPage == '0') {
     if ((LHor != LHor_last) || reNew) {myGLCD.printNumF(LHor, 1, 75, 40, '.',4); LHor_last=LHor;}
     if ((L100 != L100_last) || reNew) {myGLCD.printNumF(L100, 1, 225, 40,'.',4 ); L100_last=L100;}
     if ((L100M != L100M_last) || reNew) {myGLCD.printNumF(L100M, 1, 75, 75,'.',4 ); L100M_last=L100M;}
     if ((L100SR_TFT != L100SR_TFT_last) || reNew) {myGLCD.printNumF(L100SR_TFT, 1, 225, 75,'.',4 ); L100SR_TFT_last=L100SR_TFT;}
     if ((kmREFUELING != kmREFUELING_last) || reNew) {myGLCD.printNumI(kmREFUELING, 90, 110,3 ); kmREFUELING_last=kmREFUELING;} 
     //if (Fuel<53) 
     if ((Fuel != Fuel_last) || reNew) {myGLCD.printNumF(Fuel, 1, 225, 110,'.',4); Fuel_last=Fuel;}
     //else myGLCD.print("MAX", 210, 110); 
     if ((kmTrip != kmTrip_last) || reNew) {myGLCD.printNumF(kmTrip, 1, 60, 145,'.',5); kmTrip_last=kmTrip;}
     if ((FuelTrip != FuelTrip_last) || reNew) {myGLCD.printNumF(FuelTrip, 1, 210, 145,'.',5); FuelTrip_last=FuelTrip;}
     if ((PumpRPM != PumpRPM_last) || reNew) {myGLCD.printNumI(PumpRPM, 230, 180,4); PumpRPM_last=PumpRPM;}
     if ((RPM != RPM_last) || reNew) {myGLCD.printNumI(RPM, 230, 215,4); RPM_last=RPM;}
     if ((Fuel2 != Fuel2_last) || reNew) {myGLCD.printNumF(Fuel2, 1, 10, 215,'.',4); Fuel2_last=Fuel2;}      
     if ((Temp != Temp_last) || reNew) {myGLCD.printNumI(Temp, 415, 40, 3); Temp_last=Temp;}
     if ((TempOil != TempOil_last) || reNew) {myGLCD.printNumI(TempOil, 415, 75, 3); TempOil_last=TempOil;}
     if ((TempFuel != TempFuel_last) || reNew) {myGLCD.printNumI(TempFuel, 415, 110,3); TempFuel_last=TempFuel;} 
     if ((IntTemp != IntTemp_last) || reNew)   {myGLCD.printNumI(IntTemp, 415, 145 , 3); IntTemp_last=IntTemp;} 
     if ((t != t_last) || reNew) {myGLCD.printNumI(t, 415, 180, 3); t_last=t;}
     if ((TempAir != TempAir_last) || reNew) {myGLCD.printNumI(TempAir, 415, 215, 3); TempAir_last=TempAir;}
     reNew = 0; 
     }
   //----------------------------------------------------------
   //страниц INF1
   //----------------------------------------------------------
   if (currentPage == '1') {
     if ((StaDaliv != StaDaliv_last) || reNew) {myGLCD.printNumF(StaDaliv,1, 385, 40,'.', 4); StaDaliv_last=StaDaliv;}
     if ((DesInj != DesInj_last) || reNew) {myGLCD.printNumF(DesInj,1, 385, 75, '.', 4); DesInj_last=DesInj;}
     if ((ActInj != ActInj_last) || reNew) {myGLCD.printNumF(ActInj,1, 385, 110,'.', 4); ActInj_last=ActInj;} 
     if ((DesaInjQua != DesaInjQua_last) || reNew) {myGLCD.printNumF(DesaInjQua,1, 385, 145,'.', 4);DesaInjQua_last=DesaInjQua;}  
     if ((InjQua != InjQua_last) || reNew) {myGLCD.printNumF(InjQua,1, 385, 180,'.', 4); InjQua_last=InjQua;} 
     if ((MAF != MAF_last) || reNew) {myGLCD.printNumI(MAF, 170, 215, 4); MAF_last=MAF;}
     if ((h != h_last) || reNew) {myGLCD.printNumF(h, 1, 430, 215, 3); h_last=h;}
     reNew = 0; 
     }
   //----------------------------------------------------------
   //страниц INF2
   //----------------------------------------------------------
   if (currentPage == '2') {    
     if ((BoostPres != BoostPres_last) || reNew) {myGLCD.printNumF(BoostPres,1, 400, 40,'.', 4); BoostPres_last=BoostPres;}  
     if ((BoostPresCom != BoostPresCom_last) || reNew) {myGLCD.printNumF(BoostPresCom,1, 400, 75,'.', 4); BoostPresCom_last=BoostPresCom;} 
     if ((EGRmg != EGRmg_last) || reNew) {myGLCD.printNumI(EGRmg, 400, 110, 4); EGRmg_last=EGRmg;}  
     if ((EGRPul != EGRPul_last) || reNew) {myGLCD.printNumF(EGRPul,1, 400, 145,'.', 4); EGRPul_last=EGRPul;}
     if ((SolenPul != SolenPul_last) || reNew) {myGLCD.printNumF(SolenPul, 1, 400, 180,'.', 4); SolenPul_last=SolenPul;} 
     if ((SolenPre != SolenPre_last) || reNew) {myGLCD.printNumF(SolenPre, 0, 400, 215,'.', 4); SolenPre_last=SolenPre;}
     reNew = 0; 
     }
 //reNew = 0;
}



 void sendMessagePCM(const byte &command)
{
 #ifdef debugPCM                         
Serial.print (F("Send request "));  Serial.print (textRequest[command]); Serial.print (F(" to PCM  ")); Serial.println (millis());
 #endif
if (command != INIT) {NOanswer_timer = 1; prev_NOanswer = curmillis;}  //т.к. сейчас будем делать запрос, то запускаем таймер контроля неответов 
  byte size =  PCM_Message_TX[command][0];
  const byte siZe = size+4;
  byte Mes[siZe];
  byte Checksum = 0;
  for(byte i=0; i<siZe; i++) {
    if (i==0) {Mes[i]=size; bitWrite(Mes[i], 7 , 1);}
    if (i==1) Mes[i] = PCM_address;
    if (i==2) Mes[i] = DIAG_address;    
    if (i==3) {for (byte t=1; t<size+1; t++ ) {
           Mes[i]=PCM_Message_TX [command][t]; 
           Checksum+=Mes[i] ; 
           K_LINE_PCM.write (Mes[i]); 
           if (command == INIT) delay (5); else delay (1);  
           K_LINE_PCM.read(); 
           i++;}}
    if (i!=siZe-1) Checksum+=Mes[i];
    else Mes[i] = Checksum;    
    K_LINE_PCM.write (Mes[i]);
   if (command == INIT) delay (5); else delay (1);
    K_LINE_PCM.read();
                             }
}// end sendMessagePCM



void Trip () {

 
 
 if (flagkmAgeIGN){

 FuelTrip = FuelIGN - Fuel;                          
  if (kmAge>kmAgeIGN) kmTrip = kmAge - kmAgeIGN;
  if (kmAge<kmAgeIGN) kmTrip = 2000 - (kmAgeIGN - kmAge);  // 2000 это через сколько км у тебя суточный пробег сбрасывается на ноль, поменяй если другое число
  if (kmAge==kmAgeIGN) kmTrip = 0;


 //подсчет расхода на 100км за поездку
 L100M = ((float)FuelTrip*100.00)/(float)kmTrip;
  if (L100M<0) L100M = 0;
  if (L100M>99) L100M = 99;

 // ниже цикл считает среднеарифметический расход из еепром раз в пробег, указанный в переменной kmeeprom
  if (kmTrip-kmTFT>kmeeprom) {kmTFT = kmTrip; 

 // тут считаем среднеарифметический усредненного расхода из ячеек еепром 
int summ = 0;
 for (int i = 0; i < 11; i++) summ +=  EEPROM.read(i);
 L100SR_TFT = summ / 110.00;
 if (L100SR_TFT<0) L100SR_TFT = 0;
 if (L100SR_TFT>99) L100SR_TFT = 25;}
 
 // ниже цикл считает расход топлива за пробег, указанный в переменной kmL, здесь же запись в ячейки еепром 
  if (kmTrip-km>kmL) {km=kmTrip; 
 L100SR = ((float)(fuel_last-Fuel)*100.00)/(float)kmL; // расход/100км  - обновляется раз в 10км, меняется км в int kmL = 10;
 fuel_last = Fuel;      // сохранение параметров с последнего измерениея 
  if (L100SR<0) L100SR = 0;
  if (L100SR>99) L100SR = 99;

 //расчет расстояния до заправки
 if (L100SR>0) kmREFUELING=((float)Fuel*100.0)/(float)L100SR; //если средний расход больше нуля, то расчитывать расстояние до заправки из него
 else kmREFUELING=((float)Fuel*100.00)/(float)L100SR_TFT;    //если ноль или меньше то расчитывать расстояние до заправки с усредненного расхода

 // тут записываем  L100SR последовательно в одну из 11 ячеек еепром
 //EEPROM.write (12,n_eeprom);      // ЗДЕСЬ ВНИМАТЕЛЬНО. ЗАГРУЗИТЬ ПРОШИВКУ С ЭТОЙ СТРОКОЙ ОДИН РАЗ, ПОТОМ ЗАКОМЕНТИРОВАТЬ И ЕЩЁ РАЗ ЗАГРУЗИТЬ
 byte n_eeprom = EEPROM.read (12);    // в ячейке 12 хранится № текущей ячейки для записи расхода, чтобы где остановился при выкл питания, от туда и продолжил
 EEPROM.write(n_eeprom, L100SR*10); 
 n_eeprom++; if (n_eeprom>10) n_eeprom=0;
 EEPROM.write (12,n_eeprom); 
 
 #ifdef debugTRIP
Serial.println (" I am heer:  if (kmTrip-km>kmL) {}  "); 
Serial.print (" L100SR = "); Serial.print (L100SR) ; Serial.println (" L/100km");
Serial.print (" kmREFUELING = "); Serial.print (kmREFUELING) ; Serial.println (" km");
#endif
 
 
 }
 
 #ifdef debugTRIP
Serial.print (" FuelTrip = "); Serial.print (FuelTrip); Serial.println (" L");
Serial.print (" kmTrip = "); Serial.print (kmTrip); Serial.println (" km");
Serial.print (" L100SR_TFT = "); Serial.print (L100SR_TFT); Serial.println (" L/100km");
#endif
 
 }}

void receiveGAUGE () {


static uint32_t prevRESETheaderGAUGE=0; // таймер сброса сообщения, если данные оборвались посередине сообщения 
static bool RESETheader_timerGAUGE;     // таймер сброса сообщения, если данные оборвались посередине сообщения  

static uint32_t prevNoconnect = 0;      // таймер периодической проверки наличия связи со щитком приборов
static byte NoconnectsGAUGE = 0 ;       // счетчик неответов от щитка приборов 
static byte message_sizeGAUGE = 0;      // размер тела сообщения
static byte jGAUGE = 3;                 // инкремент
static byte nGAUGE = 3;                 // количество старт байт
static int ChecksumGAUGE =0;            // байт контрольной суммы 
static byte InitGauge = 0;              // автомат состояния инита щитка приборов 
const byte bufsizeG = 100;              // размер буфера принятого сообщения
static byte MessageRx_GAUGE [bufsizeG] = {0};   // буфер принятого сообщения
byte PIDgauge[] = {0x02,0x11,0x00,0x13}; // запрос параметоров щитка приборов



 if (K_LINE_GAUGE.available() ){
    
 // первый старт байт
 if (headerGAUGE == 0){ MessageRx_GAUGE[0]=K_LINE_GAUGE.read();  
   if ((InitGauge ==1 && MessageRx_GAUGE[0]==0x55) || (InitGauge ==2 && MessageRx_GAUGE[0]!=0xFF && MessageRx_GAUGE[0]!=0x7F)
   || (InitGauge ==3 && MessageRx_GAUGE[0]==0x23)
      )
          {headerGAUGE = 1; RESETheader_timerGAUGE = 1; prevRESETheaderGAUGE = curmillis; 
               #ifdef debugGAUGE
                  Serial.print (F("Receive GAUGE: ")); printDebugRX(MessageRx_GAUGE[0]);
               #endif               
          }
                                    }                  

 // второй старт байт
 else if (headerGAUGE == 1){ MessageRx_GAUGE[1]=K_LINE_GAUGE.read(); 
 #ifdef debugGAUGE
      printDebugRX (MessageRx_GAUGE[1]);
 #endif
      if ( (InitGauge ==1 && MessageRx_GAUGE[1]==0x52)  ||     (InitGauge ==2 && (MessageRx_GAUGE[1]==0xA0 || MessageRx_GAUGE[1]==0xF0))  
      || (InitGauge == 3 && MessageRx_GAUGE[1]==0xA1)){ headerGAUGE = 2;} 
      else {
        #ifdef debugGAUGE 
        Serial.println(F(" GAUGE Message fail address")); 
        #endif
        headerGAUGE = 0; RESETheader_timerGAUGE = 0;}} 

 // третий старт байт
 else if (headerGAUGE == 2){ 
  
  MessageRx_GAUGE[2]=K_LINE_GAUGE.read(); 
  #ifdef debugGAUGE
  printDebugRX (MessageRx_GAUGE[2]);
  #endif
  if ((InitGauge ==2 && (MessageRx_GAUGE[2]==0x48 || MessageRx_GAUGE[2]==0x55 || MessageRx_GAUGE[2]==0xAA)) || (InitGauge == 3 && MessageRx_GAUGE[2]==0x04)){ message_sizeGAUGE = MessageRx_GAUGE[0]-2; prevRESETheaderGAUGE = curmillis;
       headerGAUGE = 4;  jGAUGE=3; nGAUGE=3;
      
       if (message_sizeGAUGE > bufsizeG) message_sizeGAUGE = bufsizeG;  ChecksumGAUGE = 0;} 
  else if (InitGauge ==1 && MessageRx_GAUGE[2]==0x80) {InitGauge = 2; K_LINE_GAUGE.write(0x7F); delay (2); K_LINE_GAUGE.read();  headerGAUGE = 0; RESETheader_timerGAUGE = 0; 
             #ifdef debugGAUGE
             Serial.println ("Gauge INIT is good!"); 
             #endif
                                                      }     
  else {headerGAUGE = 0; 
        #ifdef debugGAUGE 
        Serial.println(F("GAUGE Message fail address")); 
        #endif
        RESETheader_timerGAUGE = 0;}
  
                          }  

  // пишем тело сообщения 
 else if (headerGAUGE == 4 && jGAUGE< message_sizeGAUGE+nGAUGE+1) {
 MessageRx_GAUGE[jGAUGE] = K_LINE_GAUGE.read(); prevRESETheaderGAUGE = curmillis;
 if (jGAUGE<message_sizeGAUGE+nGAUGE-1) ChecksumGAUGE+= MessageRx_GAUGE[jGAUGE]; // подсчёт КС
 
 if (jGAUGE==message_sizeGAUGE+nGAUGE) headerGAUGE = 5; 
  
 #ifdef debugGAUGE
 printDebugRX(MessageRx_GAUGE[jGAUGE]);
 #endif  
 jGAUGE++;                                             } 
 }

 // сообщение приняли, действуем
 if (headerGAUGE == 5) {  
 #ifdef debugGAUGE
 Serial.println();
 #endif  
 
  
for(byte i = 0; i<nGAUGE; i++) ChecksumGAUGE+=MessageRx_GAUGE[i]; // прибавляем к контрольной сумме старт байты
int ChecksumG =  ( ( unsigned int )MessageRx_GAUGE[message_sizeGAUGE+nGAUGE-1] << 8 ) | MessageRx_GAUGE[message_sizeGAUGE+nGAUGE]; // парсинг контрольной суммы из 2 последних байт 
 // если контрольная сумма верна: 
if ( ChecksumGAUGE == ChecksumG) 
{  NoconnectsGAUGE = 0; // сбрасываем на 0 отсутствие связи с панелью
  #ifdef debugGAUGE
  Serial.print (F("Received message is OK! Checksum is correct!"));  Serial.print (F("  ")); Serial.println (millis()); // Если КС совпала, тут чёнибудь нужное делаем
  #endif

      if (MessageRx_GAUGE[1]== 0xA0 && MessageRx_GAUGE[2]== 0x48) {
           #ifdef debugGAUGE
           Serial.println ("ID panel receive! Send request PIDGauge"); 
           #endif
           InitGauge = 3; 
           for (byte i=0; i<sizeof(PIDgauge); i++) { K_LINE_GAUGE.write (PIDgauge[i]); delay (1); K_LINE_GAUGE.read();}
                                                                  }

       if (MessageRx_GAUGE[1]== 0xF0 && (MessageRx_GAUGE[2]== 0xAA || MessageRx_GAUGE[2]== 0x55)) {
           #ifdef debugGAUGE
           Serial.println ("receive present from Gauge. I send PID to Gauge"); 
           #endif
           InitGauge = 3; 
           for (byte i=0; i<sizeof(PIDgauge); i++) { K_LINE_GAUGE.write (PIDgauge[i]); delay (1); K_LINE_GAUGE.read();}
                                                                  }

                                                                  

      if (MessageRx_GAUGE[1]== 0xA1 && MessageRx_GAUGE[2]== 0x04) {
           #ifdef debugGAUGE
           Serial.println (" receive Datastream Gauge!");
           #endif
 Fuel2 = MessageRx_GAUGE[nGAUGE + 16]/2.0; 
 if (!flagFuelIGN) {  Fuel = MessageRx_GAUGE[nGAUGE + 16]/2.0;  kmREFUELING=((float)Fuel*100.00)/(float)L100SR_TFT;} //стартовая запись литров в баке для подсчета затраченных литро
 else Fuel = MessageRx_GAUGE[nGAUGE + 17]/2.0; //для усреднения болтания в баке закоментировать эту строку, а раскоментировать ниже
            
 //для усреднения болтания топлива в баке, раскоментировать, высчитывает среднее
 /*else { FuelZamer[ZamerNumber] = MessageRxGauge[17]/2.00;
 if (ZamerNumber==9) {
 Fuel = 0 ;
 for (int i = 0; i < 10; i++) Fuel = Fuel + FuelZamer[i];
 Fuel = (float)Fuel/10.0;}
 ZamerNumber++; if (ZamerNumber>9) ZamerNumber = 0;}
*/

  kmAge = (MessageRx_GAUGE[nGAUGE + 23]+(MessageRx_GAUGE[nGAUGE + 24]*256))/10.0; //суточный пробег с панели приборов

  //бак у меня на 59 литров, а датчик показывает максимально 53 литра. для этого эта формула
  //если у вас тоже датчик имеет лимит то подправте 53 на свой лимит. 
  //если ваш датчик показывает одинаково с полным баком то закоментировать три нижние строки. 
  if (Fuel<53){
  if (!flagkmAgeIGN) { kmAgeIGN = kmAge; flagkmAgeIGN =1;}
  if (!flagFuelIGN) { FuelIGN = Fuel; fuel_last = Fuel; flagFuelIGN = 1;}}

#ifdef debugTRIP
Serial.print (" Fuel = "); Serial.print (Fuel); Serial.println (" L");
Serial.print (" kmAge = "); Serial.print (kmAge); Serial.println (" km");
#endif

           
                                                                  }
 }   

// если контрольная сумма не совпала: 
#ifdef debugGAUGE
  else Serial.println("CRC fail!!!" );
#endif
message_sizeGAUGE = 0; headerGAUGE=0; RESETheader_timerGAUGE = 0; jGAUGE=3; ChecksumGAUGE = 0;
}

// таймер сброса целостности сообщения (если данные оборвались посередине сообщения)
if (RESETheader_timerGAUGE && curmillis - prevRESETheaderGAUGE > 300) { 
  #ifdef debugGAUGE 
  Serial.println(F("Message fail timeout")); 
  #endif 
  RESETheader_timerGAUGE = 0; headerGAUGE = 0;}   

 if (curmillis - prevNoconnect > 500) {NoconnectsGAUGE ++ ; if (NoconnectsGAUGE>=8){
 #ifdef debugGAUGE 
  Serial.println (F("       Connect GAUGE failed!!! ")) ;
 #endif
  NoconnectsGAUGE = 0 ;InitGauge = 0 ; } prevNoconnect = curmillis; }
 
 InitBusGAUGE (InitGauge);
}// end receiveGAUGE


void InitBusGAUGE (byte &InitGauge) 
{
  uint32_t prevInitbusGauge = 0;   // таймер для инита щитка приборов
  
    if (InitGauge == 0){
#ifdef debugGAUGE 
  Serial.println ("Send startsession - address Gauge");
#endif   
  K_LINE_GAUGE.end();
   pinMode(TX_gauge, OUTPUT);
   digitalWrite (TX_gauge, HIGH);                                           // BUS IDLE
   InitGauge = 5; prevInitbusGauge = curmillis;
   }  
 if (InitGauge == 5 && curmillis - prevInitbusGauge>1500)  {InitGauge = 6;} // BUS IDLE
 if (InitGauge == 6)
 {    
   byte boudrate = 1000/BAUD;
   digitalWrite (TX_gauge, LOW);   delay (boudrate); // старт бит
   for (byte i=0; i<8; i++){digitalWrite (TX_gauge, bitRead(addressGUAGE, i)); delay (boudrate);} // биты тела адреса 
   digitalWrite (TX_gauge, HIGH);  delay (boudrate); // стоп бит
   K_LINE_GAUGE.begin(9600);
   InitGauge = 1; 
 }
}




#if defined debugPCM or defined debugGAUGE
void printDebugRX (const byte &inbyte) {if (inbyte<=15) Serial.print(F("0")); Serial.print (inbyte, HEX);  Serial.print (F(" "));}
#endif

#ifdef debugPCM
void printDebugRX_CSgood(const byte &n){
if (MessageRx_PCM[n]==0xC1 && MessageRx_PCM[n+1]==0x6B && MessageRx_PCM[n+2]==0x8F) {Serial.println (F("   Initialization OK!!!!")); }
 else if (MessageRx_PCM[n]==0x58 && MessageRx_PCM[n+1]==0x00) {Serial.println (F("     NO DTC  "));}
 else if (MessageRx_PCM[n]==0x58 && MessageRx_PCM[n+1] >0x00) {Serial.println (F("     DTC is found!"));} 
 else if (MessageRx_PCM[n]==0x54 && MessageRx_PCM[n+1]==0xFF && MessageRx_PCM[n+2]==0x00){Serial.println (F("     DTC CLEARED  "));}
 else if (MessageRx_PCM[n]==0x61 && MessageRx_PCM[n+1]==0x01) {Serial.println (F("     Receive PCM DATAstream"));}}
#endif                          



void Menu () {
     TouchHOME();
    if (currentPage == '0') {
     
     TouchINF1();
     TouchINF2();
     TouchCHECK(); }
    if (currentPage == '1') { 
     
     TouchINF2();
     TouchCHECK(); }
    if (currentPage == '2') { 
     
     TouchINF1();
     TouchCHECK(); }
    if (currentPage == '3') { 
     
     TouchREAD();
     TouchERASE(); }}   
 
 
  void drawHomeScreen() {
    line() ;
    //myGLCD.print(":", 290, 5);
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setTextColor(RED, BLACK); // цвет линии и текста красный
    myGLCD.drawLine(295,35,295,248); // линия вертикальная
    myGLCD.drawLine(145,35,145,178); // линия вертикальная
    myGLCD.drawLine(80,178,80,247); // линия вертикальная
    myGLCD.print("L/H", 10, 40);
    myGLCD.print("L/A", 148, 40);
    myGLCD.print("L/V", 10, 75);
    myGLCD.print("L/M", 148, 75);
    myGLCD.print("D/K", 10, 110);
    myGLCD.print("D/L", 148, 110);
    myGLCD.print("V/K", 10, 145);
    myGLCD.print("V/L", 148, 145);
    myGLCD.print("PUMP  RPM", 82, 180);
    myGLCD.print("ENGI   RPM", 82, 215);
    myGLCD.print("D/L/A", 10, 180);
    myGLCD.print("Motor C", 300, 40);
    myGLCD.print("OIL     C", 300, 75);
    myGLCD.print("FUEL   C", 300, 110);
    myGLCD.print("FUERA  C", 300, 145);
    myGLCD.print("DENTRO  C", 300, 180);
    myGLCD.print("INTAIR  C", 300, 215);
    //myGLCD.setTextColor(RED); 
    myGLCD.drawRoundRect (15, 255, 145, 310);
    myGLCD.print("INF 1", 55, 270);
    myGLCD.drawRoundRect (175, 255, 305, 310);
    myGLCD.print("INF 2", 215, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("CHECK", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 7);
    myGLCD.print("Km/h", 410, 7);
    reNew = 1;
    Watch ();
  }
 //-------------------------------------------------
   void drawscreen_one() {
    line() ;
    //myGLCD.print(":", 290, 5);
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setTextColor(RED, BLACK); // цвет линии и текста красный
    myGLCD.print("Start of Delivery   *CA:", 10, 40);
    myGLCD.print("Desir inject Start  *CA:", 10, 75);
    myGLCD.print("Actua Inject Start  *CA:", 10, 110);
    myGLCD.print("Desir Inject Quan  mg/s:", 10, 145);
    myGLCD.print("Actu Inject Quant mg/s:", 10, 180);
    myGLCD.print("MAF  mg/s:", 10, 215);
    myGLCD.print("Humedad %:", 255, 215);
    //myGLCD.setTextColor(RED);
    myGLCD.drawRoundRect (175, 255, 305, 310);
    myGLCD.print("INF 2", 215, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("CHECK", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 7);
    myGLCD.print("Km/h", 410, 7);
    reNew = 1;
    Watch ();
    }
 //-------------------------------------------------
  void drawscreen_two() {
    line() ;
    //myGLCD.print(":", 290, 5);
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setTextColor(RED, BLACK); // цвет линии и текста красный
    myGLCD.print("Boost Press       Bar:", 10, 40);
    myGLCD.print("Boost Press Com  Bar:", 10, 75);
    myGLCD.print("EGR command     mg/s:", 10, 110);
    myGLCD.print("EGR Pulse Ratio      %:", 10, 145);
    myGLCD.print("Solenoide Pulse      %:", 10, 180);
    myGLCD.print("Solenoide Boost      %:", 10, 215);
    //myGLCD.setColor(RED);
    myGLCD.drawRoundRect (15, 255, 145, 310);
    myGLCD.print("INF 1", 55, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("CHECK", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 7);
    myGLCD.print("Km/h", 410, 7);
    reNew = 1;
    Watch ();
    }
 //----------------------------------------------------------------------------
  void drawscreen_three() {
    //myGLCD.print(":", 290, 5);
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setTextColor(RED, BLACK); // цвет линии красный
    myGLCD.drawLine(1,35,479,35); // линия горизонтальная
    myGLCD.drawLine(1,248,479,248); // линия горизонтальная
    //myGLCD.setTextColor(RED);
    myGLCD.drawRoundRect (15, 255, 145, 310);
    myGLCD.print("ERASE", 55, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("READ", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 5);
    reNew = 1;
    Watch ();
   }

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//кнопки тач . координаты и переходы
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void TouchHOME(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {if (p.x > 140 && p.x < 320 && p.y > 140 && p.y < 260 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (1, 1, 77, 37);
        currentPage = '0';     
        request = PID; RequestPeriod = 10; prevRequest = curmillis; // на PCM в этом окне посылается запрос текущих параметров
        myGLCD.clrScr();             
        drawHomeScreen();
        x = 0;
        y = 0;
        p.z = 0;}}}

void TouchINF1(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
      if (p.x > 150 && p.x < 450 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (15, 255, 145, 310);
        currentPage = '1';    
        request = PID; RequestPeriod = 10; prevRequest = curmillis; // на PCM в этом окне посылается запрос текущих параметров       
        myGLCD.clrScr();             
        drawscreen_one();
        x = 0;
        y = 0;
        p.z = 0;}}}
    
void TouchINF2(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
    if (p.x > 450 && p.x < 680 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (175, 255, 305, 310);
        currentPage = '2';     
        request = PID; RequestPeriod = 600; prevRequest = curmillis; // на PCM в этом окне посылается запрос текущих параметров      
        myGLCD.clrScr();             
        drawscreen_two();
        x = 0;
        y = 0;
        p.z = 0;}}}

void TouchCHECK(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
if (p.x > 690 && p.x < 950 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (335, 255, 465, 310);
        currentPage = '3';  
  //     request = DTCREAD; RequestPeriod = 10; prevRequest = curmillis; // на PCM в этом окне посылается запрос чтения ошибок  
        myGLCD.clrScr();             
        drawscreen_three();
        x = 0;
        y = 0;
        p.z = 0;}}}

void TouchREAD(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
if (p.x > 690 && p.x < 950 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (335, 255, 465, 310);
        request = DTCREAD; RequestPeriod = 300; prevRequest = curmillis; // на PCM при нажатии этой кнопки посылается запрос чтения ошибок  
        x = 0;
        y = 0;
        p.z = 0;}}}

void TouchERASE(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
if (p.x > 150 && p.x < 450 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      {myGLCD.drawRoundRect (15, 255, 145, 310);
       request = DTCERASE; RequestPeriod = 300;  prevRequest = curmillis; // на PCM при нажатии этой кнопки посылается запрос удаления ошибок
       myGLCD.clrScr();
       drawscreen_three();
       myGLCD.print("DTC BORRADO", 180, 145);
       
        x = 0;
        y = 0;
        p.z = 0;}}}
 ////////////////////////////////////////////////////////////////////////////////////////
 //прорисовка линий
 ///////////////////////////////////////////////////////////////////////////////////////
 void line() {
    //myGLCD.setTextColor(RED); // цвет линии красный
    myGLCD.drawLine(1,35,479,35); // линия горизонтальная
    myGLCD.drawLine(1,73,479,73); // линия горизонтальная
    myGLCD.drawLine(1,108,479,108); // линия горизонтальная
    myGLCD.drawLine(1,143,479,143); // линия горизонтальная
    myGLCD.drawLine(1,178,479,178); // линия горизонтальная
    myGLCD.drawLine(1,212,479,212); // линия горизонтальная
    myGLCD.drawLine(1,248,479,248); // линия горизонтальная
             }


void Watch (){
   DateTime now = rtc.now();
   int minut = now.minute(); 
   int hour = now.hour();
   int mon = now.month();
   int date = now.day();
   int Year = now.year();
 static  int minut_last; 
 static  int hour_last;
 static  int mon_last;
 static  int date_last;
 static  int Year_last;
 myGLCD.setTextColor(WHITE, BLACK); //белый цвет цифры

 if (date != date_last || reNew){ myGLCD.printNumI(date, 85, 7, 2, '0'); date_last = date; }

 if (mon!=mon_last || reNew){myGLCD.printNumI(mon, 130, 7, 2, '0'); mon_last = mon; }  
 
 if (Year!=Year_last || reNew) {  myGLCD.printNumI(Year, 175, 7); Year_last = Year; }
   
 if (hour!=hour_last || reNew){ myGLCD.printNumI(hour, 255, 7, 2, '0'); hour_last = hour; } 
   
 if (minut!=minut_last || reNew ){ myGLCD.printNumI(minut, 300, 7, 2, '0'); minut_last = minut; }
   } 

void Temperature () { 

     static boolean p=0; // флаг работы: запрос температуры или её чтение
p=!p;
if (p) {ds.reset();      // сброс шины
        ds.write(0xCC);  // обращение ко всем датчикам
        ds.write(0x44);  // начать преобразование (без паразитного питания)  
       }
else   {
 
        int Temper_= 20;  byte buff[9];
        ds.reset();
        ds.select(DSaddress);    
        ds.write(0xBE); // Read Scratchpad (чтение регистров)  
        for (byte j = 0; j<9; j++) buff[j]= ds.read(); //читаем все 9 байт от датчика 
        ds.reset();
        if (OneWire::crc8(buff, 8) == buff[8]){        // если контрольная сумма совпадает
        Temper_ =  buff[0] | (buff[1]<<8);             // читаем температуру из первых двух байт (остальные были нужны для проверки CRC)
        Temper_ = Temper_ / 16;
        if  (Temper_ < 150 && Temper_ > -50 && Temper_ !=85 && Temper_!=-127)  IntTemp =  Temper_;
                 
                                              }
                                                      
}
   }

код похож, конечно, на говнокод с ужасным количеством глобальных переменных, потому что я писал его очень давно и не шарил толком, поэтому такие косяки сейчас  и возникают. 

viki13viki
Offline
Зарегистрирован: 14.11.2016

понял, блин у меня была такая мысль что может last-ы чета мутят . но боялся уже чета трогать, чтобы не напортачить. уже на следующей недели в понедельник проверю на работе. отпишусь, спасибо

Sergei H.
Offline
Зарегистрирован: 17.11.2018

С мерцанием разобрался.Поставил конденсатор на 2 и 3 пин дисплея.Где по умолчанию стоит стоимость за литр бензина так и не могу найти в коде.

MaksVV
Offline
Зарегистрирован: 06.08.2015

Сергей, что именно имеется ввиду про стоимость топлива? Проблема непонятна. Сними видео

viki13viki
Offline
Зарегистрирован: 14.11.2016

Он ищет как задать стоимость топлива в рублях для расчетов, вместо долларов. Типа сколько рублей потрачено за поездку или на данный момент сколко стоит его пройденый путь, типа того

Sergei H.
Offline
Зарегистрирован: 17.11.2018

viki13viki да так и есть.Не могу в коде найти где стоимость устанавливается с одного доллара.Стоит в меню -$1.234+.Хочу сразу переделать ,чтобы с -P40.00+ устанавливалось.По одной сотой прибавлять очень долго.Стоимость записывается в память.В принципе не нужная функция ,только ради интереса.Спасибо ,что отвечаете.

viki13viki
Offline
Зарегистрирован: 14.11.2016

Попробуй без сотых поставить, 40 что получится?

Sergei H.
Offline
Зарегистрирован: 17.11.2018

В меню я могу поставить -$40.000+   .Выставить кнопкой, долго нажимая, с одного доллара. Я не могу в коде найти  почему по умолчанию стоит стоимость за 1литр от одного доллара (1.000 с тысячными), где это изменить, и чтобы ещё тысячные убрать до сотых.  Бак по умолчанию в настройках стоит 45 литров, и все остальные настройки уже прописаны, где они в коде подскажите пожалуйста.

viki13viki
Offline
Зарегистрирован: 14.11.2016

В коде где у тебя доллар 1.234 оставь 1 без сотых. Попробуй так

Sergei H.
Offline
Зарегистрирован: 17.11.2018

Так в том то и дело,что я не могу понять где в коде этот доллар  стоит. И все остальные начальные настройки. Пример-(Бак в литрах уже стоит по умолчанию 45литров.)

viki13viki
Offline
Зарегистрирован: 14.11.2016

последняя моя догадка, дальше я бессилен. Мне все таки кажется что задается именно здесь

/**************************/
/* GASOLINE ENGINE CONFIG */
/**************************/
// [CONFIRMED] For gas car use 3355 (1/14.7/730*3600)*10000
#define GasConst 3355
#define GasMafConst 107310 // 14.7*730*10

тебе нужно заменить 3355 на 42250 что значит у низ 3.355  и у тебя 42.25

когда заменил на 43350 изменилась цена с 1.234 доллара на другое чтото?

и в этой строке cents =  fuel * params.gas_price / 1000; //now have $$$$cc

попробуй 1000 заменить на 100, станет ли цена 12.34 

я одного не могу найти где прописан params.gas_price

и еще смотри здесь вроде конвертация в галоны но может от нее и пляшет

в галонах цена 3.785 и прога конвертирует в бензин и выходит 1.234 доллара

// Convert unit price to litres for the cost per gallon. (ie $1 a litre = $3.785 per gallon)
4015
	            fuelUnits = (fuelUnits * 378L) / 100L; //convertToLitres(params.gas_price);
4016
	            lcd_print_P(PSTR("G)"));
4017
	          }
4018
	        #else
4019
	          #ifdef UseSI
4020
	            lcd_print_P(PSTR("L)"));
4021
	          #endif 
4022
	          #ifdef UseUS
4023
	            // Convert unit price to litres for the cost per gallon. (ie $1 a litre = $3.785 per gallon)
4024
	            fuelUnits = (fuelUnits * 378L) / 100L; //convertToLitres(params.gas_price);
4025
	            lcd_print_P(PSTR("G)"));
4026
	          #endif 
4027
	        #endif

378L это у них 3.785 доллара из которого выходит 1.234 доллара, примерно половина. поиграй с этим значением. поставь например 2110L что есть половина 4225 . там в двух местьах нудно поменять в коде выше.

если нет, то значит, что в другом месте нужно менять. если да то эксперементируй. дальше я пас, я безпонятия.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Sergei H. 961 строка - начальная цена  (умноженная на 1000 вроде).

Строки с 951 по 1004 задают начальные данные.

Вижу также запись и чтение в EEPROM - видимо есть возможность настроить с кнопок и сохранить настройки, а потом уже с них и стартовать.

Шаг настройки с кнопок надо менять в строках с 4033 по 4067.

viki13viki
Offline
Зарегистрирован: 14.11.2016

О Командир :). Я пытаюсь помочь но из мен програмист еще тот, могу только догадывтася. в 961 строке это 1090, чет не поляшет. думпешь что это типа стоимость литра 1.9 долларов, знвяит ему нужно подставить 40025 это 40.25 в рублях?

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

viki13viki ты методом тыка пробуешь ... 5000+ строк таким методом до старости можно гонять.

Я краем глаза глянул логику скетча и нашел где задаются начальные данные. А вот коэффициент 1000 или 100 пока не увидел ...

viki13viki
Offline
Зарегистрирован: 14.11.2016

вот вроде cents =  fuel * params.gas_price / 1000; //now have $$$$cc

просто пытаюсь помчь как могу, метод тыка долгий с таким кодом я знаю.

Sergei H.
Offline
Зарегистрирован: 17.11.2018

Спасибо всем.Komandir с шагом настройки разобрался,теперь на много проще.Постоянные я так понял сразу записываются в память.После заливки кода как изменишь,остаются в памяти, после можно только подстраивать.Точно снёс память смог изменять строки 951 по 1004. Теперь вопрос где изменить в коде чтобы было 42,00 рубля а не 42,000. Строка 961 это стоимость топлива значит у меня было 1,090 доллара.Это я viki13viki  в заблуждение ввёл извините.

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

4073 3:1 на 2:1 или "fuelUnits > 999 ? 3 : 1" на 2

viki13viki
Offline
Зарегистрирован: 14.11.2016

Макс залил 2053. Нужен прогон. Сегодня вечером и звтра утром пргоню и утром отпишусь.

viki13viki
Offline
Зарегистрирован: 14.11.2016

Макс выехал домой , километров в баке 0 и средний расход 0.0. Надеялся что пробег даст первые записи и все будет норм. проехал, через 10 км показало километры в баке, средний расход 0.0. Утром включаю зажигание, литры в баке 0 и средний расход 0.0. Поехал на работу. Прогнал 30 км, как всегда после 10 км показало километры в баке, средний расход так и остался 0. Заглушил, включил, километров в баке 0 и средний расход 0.0. Вот такая вот картина.

MaksVV
Offline
Зарегистрирован: 06.08.2015

тогда на экран что-нибудь выведи, в строках 604-610 и в строках 614-635, чтобы узнать заходит ли сюда программа. 

в 611 строке выведи на экран значение переменной L100SR_TFT

между 615 и 614 выведи L100SR 

viki13viki
Offline
Зарегистрирован: 14.11.2016

Макс по порядку. 604-610 это у нас расчет L100SR_TFT он у нас на экране и он всегда в ноль. 614-631 это у нас L100SR (может не работает), остатки километров через 10 км начинает показывать (работает если в конце формулы 6.7 а не L100SR_TFT, не помню или с L100SR_TFT работало или нет, сегондня проверю),  а вот в строчках 625-628 от туда и "продолжаем последнее значение данных" (не работает, всегда с нуля начинает). Значит заходит и считает , видно по формуле киллометров в баке если стоит 6.7, но чтото не чиатет. Остается проверить L100SR ну и на всякий случай выведу там же и L100SR_TFT, ща выведу их между 604-631, узнаем или заходит сюда прога и работает ли они. Еще одно увидел что L100SR_TFT его расчеты прописаны два раза в setup 174-179 и в voidtrip 606-610 (не знаю, может так нужно.....). Завтра скажу че да как.

Вообщем вывел я это

myGLCD.printNumF(L100SR, 1, 10, 215,'.',4);

 if ((L100SR_TFT != L100SR_TFT_last) || reNew) {myGLCD.printNumF(L100SR_TFT, 1, 225, 75,'.',4 ); L100SR_TFT_last=L100SR_TFT;}

 L100SR_TFT = (float)L100SR_TFT/110.00;
  if (L100SR_TFT<0) L100SR_TFT = 0;
  if (L100SR_TFT>99) L100SR_TFT = 99;}
 
 // ниже цикл считает расход топлива за пробег, указанный в переменной kmL, здесь же запись в ячейки еепром 
  if (kmTrip-km>kmL) {km=kmTrip; 
 L100SR = ((float)(Fuel_last-Fuel)*100.00)/(float)kmL; // расход/100км  - обновляется раз в 10км, меняется км в int kmL = 10;
 Fuel_last = Fuel;      // сохранение параметров с последнего измерениея 
  if (L100SR<0) L100SR = 0;
  if (L100SR>99) L100SR = 99;

myGLCD.printNumF(L100SR, 1, 10, 215,'.',4);

 //расчет остатка километров в баке
 if (L100SR>0) kmREFUELING=((float)Fuel*100.0)/(float)L100SR; //если средний расход больше нуля, то расчитывать км в баке из него
 else kmREFUELING=((float)Fuel*100.00)/(float)L100SR_TFT;    //L100SR_TFT если ноль или ментше то расчитывать км в баке с устредненного расхода

 // тут записываем  L100SR последовательно в одну из 11 ячеек еепром
 //EEPROM.write (12,n_eeprom);      // ЗДЕСЬ ВНИМАТЕЛЬНО. ЗАГРУЗИТЬ ПРОШИВКУ С ЭТОЙ СТРОКОЙ ОДИН РАЗ, ПОТОМ ЗАКОМЕНТИРОВАТЬ И ЕЩЁ РАЗ ЗАГРУЗИТЬ
 n_eeprom = EEPROM.read (12);    // в ячейке 12 хранится № текущей ячейки для записи расхода, чтобы где остановился при выкл питания, от туда и продолжил
 EEPROM.write(n_eeprom, L100SR*10); 
 n_eeprom++; if (n_eeprom>10) n_eeprom=0;
 EEPROM.write (12,n_eeprom); 
 
 if ((L100SR_TFT != L100SR_TFT_last) || reNew) {myGLCD.printNumF(L100SR_TFT, 1, 225, 75,'.',4 ); L100SR_TFT_last=L100SR_TFT;}
 

между 604-631 на экране не отображеются эти данные, думаешь значит что не заходит сюда? тогда почму если в формуле километров в баке, которая находится межу этимх строк ставить 6.7 вместо L100SR_TFT расчет ведется? значит заходит, хз.

MaksVV
Offline
Зарегистрирован: 06.08.2015

залей такой скетч для чисти еепром, покажи что он в сериал выведет. 


#include <EEPROM.h>


void setup() {
  
  Serial.begin(115200);
  for (int i =0; i<12; i++) EEPROM.write(i, 255);
  EEPROM.write(12,0);
  for (int i =0; i<13; i++){ Serial.print (EEPROM.read(i)); Serial.print(" ");}
}

void loop() {

 
}

Потом я исправил 2053. заливай его после чистки еепром. По идее средний расход сразу должен показать 25.5. Потом начать уменьшаться раз в 15 км. и L100SR где нибудь выведи. От него средний ведь считается в ячейки еепром. Нужно посмотреть как он меняется раз в 10 км. Может ты координаты корявые при выводе сделал. Сделай маленький скетч. Проверь как эти строки на экран выводят, работает ли вывод этих строк

MaksVV
Offline
Зарегистрирован: 06.08.2015

у тебя с такими же координатами как ты сделал вывод L100SR что то другое на экран выводится:

if ((Fuel2 != Fuel2_last) || reNew) {myGLCD.printNumF(Fuel2, 1, 10, 215,'.',4); Fuel2_last=Fuel2;}      

а оно ведь часто обновляется, вот и перекрывает

viki13viki
Offline
Зарегистрирован: 14.11.2016

залил очиску вывод

255 255 255 255 255 255 255 255 255 255 255 255 0

залил скетч 2053, да средний показал 25.5

вывел L100SR вместо актуального топлива, поглядим после пробега пока 0.0

остальное утром скажу после пробега

Fuel2 это актуальное топливо в баке.

MaksVV
Offline
Зарегистрирован: 06.08.2015

ок

MaksVV
Offline
Зарегистрирован: 06.08.2015

а вообще слишком маленькие интервалы (10км) для измерения . Ведь при расходе менее 10л/100км, за этот отрезок менее 1 литра  израсходуется, а значит если десятые литра откинуть, то израсходаванных литров будет 0. Соответственно и средний расход поэтому 0. нужно делать бОльшие интервалы, хотя бы раз в 30 км. 

MaksVV
Offline
Зарегистрирован: 06.08.2015

ещё раз поправил 2053, так как при расчёте L100SR использовалась промежуточная переменная fuel_last, а она была типа int , т.е. без учёта десятых литра. а при маленьких отрезках измерения (10км) тут десятые очень важны. Исправил это 

 

Komandir
Komandir аватар
Offline
Зарегистрирован: 18.08.2018

Расход надо считать по количеству импульсов на форсунке.

viki13viki
Offline
Зарегистрирован: 14.11.2016

Понял, принял. Перезалью сейчас.

MaksVV
Offline
Зарегистрирован: 06.08.2015

Komandir пишет:

Расход надо считать по количеству импульсов на форсунке.

такой расход есть и считается. Это мгновенный расход

MaksVV
Offline
Зарегистрирован: 06.08.2015

можно ещё  попробовать новый подход. Заливаем этот скетч для чистки еепром. Там ставим текущие данные с панели.

//------------все для связи по K-line (тут настраиваем UARTы к-лайников, адреса блоков, скорость инита и отладку) 
#include <SoftwareSerial.h>
 #define TX_PCM 13
 SoftwareSerial K_LINE_PCM   (12, TX_PCM); //RХ,TХ    //UART на котором висит K_line к PCM

#define K_LINE_GAUGE Serial2   //UART     на котором висит K_line к приборке 
#define TX_gauge 16            //TX UARTa на котором висит K_line к приборке 

#define PCM_address  0x11      // адрес PCM 
#define DIAG_address 0xF1      // адрес диагностики

const byte BAUD=200;           // init baudrate - скорость инита при подключении к приборке 
const byte addressGUAGE = 0xB8;// init GAUGE address - адрес щитка приборов при ините (установке связи)

#define debugPCM             // раскоментировать эту строку для отладки в Serial порту обмена с PCM
//#define debugGAUGE             // раскоментировать эту строку для отладки в Serial порту обмена co щитком приборов
//#define debugTRIP             // раскоментировать эту строку для отладки в Serial порту данных бортовика
 
uint32_t curmillis = 0;        // снимок текущего времени 
 
//------------------------------------------переменные для организации протокола связи с PCM

uint32_t prevRequest  = 0;     // таймер периодических запосов на PCM
uint16_t RequestPeriod = 3500; // периодичность запросов на PCM
byte header = 0;               // состояние заголовка
bool NOanswer_timer = 0;       // таймер контроля неответов от ЭБУ после подачи запросов
uint32_t prev_NOanswer=0;      // таймер контроля неответов от ЭБУ после подачи запросов
// возможные варианты запросов на ЭБУ:
enum REQUEST {INIT, PID, DTCERASE, DTCREAD, PRESENT,};

#ifdef debugPCM 
// текстовки запросов для отладки 
char* textRequest[] = {"INIT", "PID_2101", "DTC_ERASE", "DTC_READ", "PRESENT",} ;
#endif 

 // сами запросы
 byte PCM_Message_TX[][5] = {
 {1,  0x81,           0,0,0},    // запрос инициализации
 {2,  0x21,0x01,        0,0},    // запрос пид 2101
 {3,  0x14,0xFF,0x00,     0},    // запрос на стирание ошибок
 {4,  0x18,0x00,0xFF,0x00  },    // запрос на чтение ошибок
 {1,  0x3E,           0,0,0},    // запрос присутствия 
                            };
byte request = INIT;             // переменная, показывающая какой запрос будем делать
static byte headerGAUGE = 0;            // состояние заголовка сообщений щитка  приборов

const byte bufsize = 150;           // размер буфера принятого сообщения
byte MessageRx_PCM [bufsize] = {0}; // буфер принятого сообщения


//-------------------------------------------переменные бортовика

 float L100M = 0;      //расход на 100 км измеренный за поездку
 float L100 = 0;       //мгновенный расход литров на 100км
 float LHor = 0;       //мгновенный расход топлива литров в час
 float L100SR = 0;     //расход литров на 100км измеренный раз в интервал kmL  
 float L100SR_TFT = 0; // самый средний из расходов на 100км, он выводится на экран

 //int L100_Eeprom[11]= {10,10,10,10,10,10,10,10,10,10,10};
 //int FuelZamer[10]= {0};  // массив для измерения уровня (количества) топлива 
 //int ZamerNumber = 0;     // номер замера уровня (количества) топлива 
 
 
 int MAF = 0;            //26,27 байты   Sensor de flujo de aire en masa
 float BoostPres = 0;    //28,29 байты   Presión de refuerzo
 int RPM = 0;            //32,33 байты   Velocidad del motor
 int EGRmg = 0;          //34,35 байты   Comando EGR (Comando de recirculación de gases de escape)
 float BoostPresCom = 0; //38,39 байты   Comando de presión de refuerzo
 int Speed = 0;          //44,45 байты   Velocidad del vehículo
 float DesaInjQua = 0;   //50,51 байты   Cantidad de inyección deseada
 float InjQua = 0;       //52,53 байты   Cantidad de la inyección
 float StaDaliv = 0;     //54,55 байты   Inicio de la entrega
 int PumpRPM = 0;        //56,57 байты   Velocidad de la bomba
 float EGRPul = 0;       //62,63 байты   Relación de impulsos EGR (recirculación de gases de escape
 float SolenPul = 0;     //64,65 байты   Velocidad de solenoide de control de nivel de remolino Relación de impulsos
 float SolenPre = 0;     //70,71 байты   Relación de impulsos Presión Electroválvula de presión
 float DesInj = 0;       //72,73 байты   Inyección deseada Inicio
 float ActInj = 0;       //16,17 байты   Inicio de la inyección real
 int TempAir = 0;        //74,75 байты   Temperatura del aire de admisión
 int Temp = 0;           //14,15 байты   Temperatura del refrigerante
 int TempOil = 0;        //18,19 байты   Temperatura del aceite del motor
 int TempFuel = 0;       //58,59 байты   Temperatura del combustible
 int IntTemp = 0;        //Температура улицы
 
 //все что касается топлива
 float Fuel = 0;       //остаток топлива 
 float Fuel2 = 0;    float Fuel2_last = 1; //остаток мгновенного топлива байт 16 , датчика в баке
 float FuelIGN = 0;      // количество топлива в баке на момент включения зажигания
 float fuel_last = 0;    // для формул
 bool flagFuelIGN = 0; // флаг записан ли остаток топлива в момент вкл. зажигания 
 float FuelTrip = 0; float FuelTrip_last = 1;    // количество литров топлива, израсходованное за один цикл включения зажигания
 
 //все что касается километража
 float kmAge = 0;           //пробег, полученный со щитка приборов
 float kmAgeIGN = 0;          //пробег который был в момент включения зажигания 
 bool flagkmAgeIGN = 0;     //флаг записан ли пробег в момент вкл. зажигания 
 float kmTrip = 0; float kmTrip_last = 1;           //пробег за один цикл включения зажигания
 const int kmL = 50;              // интервал, через который будет происходить обновление среднего расхода на 100км
// int km = 0;                // переменная для расчетов
// const int kmeeprom = 15;         // интервал, через который будет происходить подсчет среднеарифмитического расхода  L100SR_TFT
// int kmTFT =  0;     // переменная для расчетов периодического подсчета среднеарифмитического расхода топлива L100SR_TFT
 int kmREFUELING = 0; int kmREFUELING_last = 1;     // пробег до заправки на остатке топлива 
 
 unsigned long prevWatch = 0;
 unsigned long prevDvoet = 0;
 

//----------------------------------------------для экрана 
#include <Adafruit_GFX.h>
 #include <MCUFRIEND_kbv.h>
 #include <UTFTGLUE.h>//use GLUE class and constructor
 #include "TouchScreen.h"
 #include <stdint.h>
 #include <SPI.h>
 #include <EEPROM.h>
 //#include "Fonts/Chosence_Bold16pt7b.h";

#define MINPRESSURE 200
#define MAXPRESSURE 1000

//pin 20 SCL , 21 SDA датчик реального времени
 #include <Wire.h>
 #include "RTClib.h"
 RTC_DS3231 rtc;       

UTFTGLUE myGLCD(0x1581,A2,A1,A3,A4,A0); //all dummy args
 
 const int XP = 6, XM = A2, YP = A1, YM = 7; 
 const int TS_LEFT = 136, TS_RT = 907, TS_TOP = 139, TS_BOT = 942;
 TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
 uint16_t ID;
 int x, y;
 char currentPage;
 float h; int h_last = 1; 
 float t; int t_last = 1; 
 bool Dvoet = 0;
 bool reNew = 0;
 #define BLACK 0x0000
 #define WHITE 0xFFFF
 #define RED   0xF800
 #define GREEN 0x07E0

 //--------------------------------------датчики t

byte DSaddress[] = {0x28, 0xFF, 0xA6, 0x19, 0xA8, 0x15, 0x01, 0xD2};
//датчик внутринней температуры и влаги
 #include "DHT.h"
 #define DHTPIN 26   
 #define DHTTYPE DHT22 
 DHT dht(DHTPIN, DHTTYPE);
#include <OneWire.h>
 #define ONE_WIRE_BUS 22   
 OneWire ds(ONE_WIRE_BUS);



 
void setup() {
   uint16_t ID = myGLCD.readID();
   if (ID == 0xD3D3) ID = 0x1581; // write-only shield
   myGLCD.begin(ID);  
   myGLCD.InitLCD(3);
   myGLCD.clrScr();
   myGLCD.setTextSize(2);
   //myGLCD.setFont(&Chosence_Bold16pt7b);
   Wire.begin();
   rtc.begin();
   dht.begin();
   //загрузка стартовой страницы
   currentPage = '0';       
   drawHomeScreen();  

   //подсчет среднеарифметического усредненного расхода
 float summar = 0;
 for (int i = 0; i < 20; i+=4) {float summar_;   EEPROM.get (i, summar_);   summar +=summar_;} 
 L100SR_TFT = summar/5.00;    
 L100SR = L100SR_TFT;
   
   /*
   
   int summ=0;
 for (int i = 0; i < 11; i++) summ +=  EEPROM.read(i);
 L100SR_TFT = summ / 110.00;
   if (L100SR_TFT<0) L100SR_TFT = 0;
   if (L100SR_TFT>99) L100SR_TFT = 99;
  */
   // строка ниже используется для настройки даты и времени часов 
   // раскоментировать, выставить времая и дату, залить в ардуино. в скетче закоментировать
   // обратно и залить еще раз, иначе каждый раз будет по новой выствлятся это же время и дата
   // (год, месяц, день, часы, минуты, секунды)
   //rtc.adjust(DateTime(2019, 7, 2, 10, 48, 0));
  
 #if defined debugPCM or defined debugGAUGE or defined debugTRIP
   Serial.begin(115200);
 #endif
   K_LINE_PCM.begin(10400);
   pinMode(TX_PCM, OUTPUT);
  
             }


    void loop() 

                
                {
                  
curmillis = millis();              // снимок текущего времени

if (curmillis - prevRequest > RequestPeriod && header == 0 ) 
    {
  if (request == INIT) fastinit();                                          // при необходимости делаем переподключение к PCM
  else {sendMessagePCM(request);                                            // отправляем на PCM текущий запрос
         if (request == PID) RequestPeriod = 600; 
         if (request == DTCERASE || request == DTCREAD) RequestPeriod = 2500;} 
  prevRequest = curmillis;
    }

receivePCM ();   // приём сообщений от PCM
receiveGAUGE (); // приём сообщений от щитка приборов
if (header == 0 && headerGAUGE == 0) {Menu ();}
if (curmillis - prevWatch > 4000)  { Watch (); prevWatch = curmillis;  h = dht.readHumidity(); t = dht.readTemperature();Temperature ();}
//if (curmillis - prevDvoet > 500)  { if (!Dvoet) {myGLCD.setTextColor(WHITE); } else {myGLCD.setTextColor(BLACK); }  myGLCD.print(":", 290, 5); prevDvoet = curmillis; Dvoet=!Dvoet;}                
if (curmillis - prevDvoet > 500)  { if (!Dvoet) {myGLCD.print(":", 280, 5);} else {myGLCD.print(" ", 290, 5);} prevDvoet = curmillis; Dvoet=!Dvoet;}
Trip ();
                }// end loop

 void fastinit() {
   digitalWrite (TX_PCM, HIGH);  // bus idle
   delay(1500);              
   digitalWrite (TX_PCM, LOW);  // first part fastinit  (25 ms LOW)
   delay(25);
   digitalWrite (TX_PCM, HIGH); // second part fastinit (25 ms HIGH)
   delay(25);               
   K_LINE_PCM.begin(10400);
   sendMessagePCM(INIT);        // send start communication message 
      }  
 
  
  void receivePCM () {

static uint32_t prevRESETheader=0;    // таймер сброса сообщения, если данные оборвались посередине сообщения 
static bool RESETheader_timer;        // таймер сброса сообщения, если данные оборвались посередине сообщения 
static byte noanswers = 0;            // количество подряд неответов от ЭБУ 
static byte message_size = 0;         // размер тела сообщения
static byte j = 3;                    // инкремент
static byte n = 3;                    // количество старт байт
static byte crc =0;                   // байт контрольной суммы 



 if (K_LINE_PCM.available() ){
    
 // первый старт байт
 if (header == 0){ MessageRx_PCM[0]=K_LINE_PCM.read();  
         if (MessageRx_PCM[0]!=0xFF && bitRead (MessageRx_PCM[0],7)){header = 1; RESETheader_timer = 1; prevRESETheader = curmillis; 
               #ifdef debugPCM
                  Serial.print (F("Receive PCM: ")); printDebugRX(MessageRx_PCM[0]);
               #endif               
                                                }
                          }                  

 // второй старт байт
 else if (header == 1){ MessageRx_PCM[1]=K_LINE_PCM.read(); 
 #ifdef debugPCM
      printDebugRX (MessageRx_PCM[1]);
 #endif
      if (MessageRx_PCM[1]==DIAG_address){ header = 2;} 
      else {
        #ifdef debugPCM 
        Serial.println(F(" PCM Message fail address")); 
        #endif
        header = 0; RESETheader_timer = 0;}} 

 // третий старт байт
 else if (header == 2){ 
  MessageRx_PCM[2]=K_LINE_PCM.read(); 
  #ifdef debugPCM
  printDebugRX (MessageRx_PCM[2]);
  #endif
  if (MessageRx_PCM[2]==PCM_address){ message_size = MessageRx_PCM[0]; prevRESETheader = curmillis;
       if (MessageRx_PCM[0] !=0x80) {header = 4;  bitWrite (message_size, 7 , 0);j=3;n=3;}
       else {header = 3; j=4;n=4;}
       if (message_size > bufsize) message_size = bufsize;  crc = 0;} 
  else {header = 0; 
        #ifdef debugPCM 
        Serial.println(F("PCM Message fail address")); 
        #endif
        RESETheader_timer = 0;}
  
                          }  
// если размер сообщения указан в дополнительном байте (нулевой байт 0x80) читаем этот дополнительный байт:
else if (header == 3){
   prevRESETheader = curmillis;
  MessageRx_PCM[3]=K_LINE_PCM.read(); 
  #ifdef debugPCM
  printDebugRX(MessageRx_PCM[3]);
  #endif
  message_size = MessageRx_PCM[3]; 
  if (message_size > bufsize) message_size = bufsize;  
  crc = 0; header = 4;  
                         }

  // пишем тело сообщения 
 else if (header == 4 && j< message_size+n+1) {
 MessageRx_PCM[j] = K_LINE_PCM.read(); prevRESETheader = curmillis;
 if (j<message_size+n) crc+= MessageRx_PCM[j]; // подсчёт КС
 
 if (j==message_size+n) header = 5; 
 #ifdef debugPCM
 printDebugRX(MessageRx_PCM[j]);
 #endif  
 j++;                                             } 
 }

 // сообщение приняли, действуем
 if (header == 5) {
 #ifdef debugPCM
 Serial.println();
 #endif  
 NOanswer_timer = 0; noanswers = 0;              // сбрасываем таймер контроля неответов 
  
for(byte i = 0; i<n; i++) crc+=MessageRx_PCM[i]; // прибавляем к контрольной сумме старт байты

 // если контрольная сумма верна: 
if ( crc == MessageRx_PCM[message_size+n]) 
{  
  #ifdef debugPCM
  Serial.print (F("Received message is OK! Checksum is correct!"));  Serial.print (F("  ")); Serial.println (millis()); // Если КС совпала, тут чёнибудь нужное делаем
  printDebugRX_CSgood(n); 
  #endif
      if (MessageRx_PCM[n]==0xC1 && MessageRx_PCM[n+1]==0x6B && MessageRx_PCM[n+2]==0x8F) {
              if (currentPage!=3) {request = PID; RequestPeriod = 70;} else request = PRESENT, RequestPeriod = 4000; prevRequest = curmillis; // receive good INIT
                                                                                          }
 else if (MessageRx_PCM[n]==0x58) Troublecodes (n); // DTC
 else if (MessageRx_PCM[n]==0x54 && MessageRx_PCM[n+1]==0xFF && MessageRx_PCM[n+2]==0x00){ request = PRESENT; RequestPeriod = 4000; prevRequest = curmillis;} // DTC are cleared
 else if (MessageRx_PCM[n]==0x61 && MessageRx_PCM[n+1]==0x01) {dataVars(n) ; RequestPeriod = 70; prevRequest = curmillis; }           // receive DataStream
 
 
 }   

// если контрольная сумма не совпала: 
#ifdef debugPCM
  else Serial.println("CRC fail!!!" );
#endif
message_size = 0; header=0; RESETheader_timer = 0; j=3; crc = 0;
}

// таймер сброса целостности сообщения (если данные оборвались посередине сообщения)
if (RESETheader_timer && curmillis - prevRESETheader > 200) { 
  #ifdef debugPCM 
  Serial.println(F("Message fail timeout")); 
  #endif 
  RESETheader_timer = 0; header = 0;}   

 
// если нет ответа после запроса: +1 к счетчику неответов. Если накопилось 6 и более: делаем реинит.  
if (request!=INIT && NOanswer_timer && curmillis - prev_NOanswer > RequestPeriod - RequestPeriod/10) 
         {
     NOanswer_timer = 0; noanswers++; 
     if (noanswers>=6) { noanswers = 0; request = INIT; RequestPeriod = 3500;}
         }
}// end receivePCM


void Troublecodes (const byte &n) 
{
  if (MessageRx_PCM[n]==0x58 && MessageRx_PCM[n+1]==0x00){
    myGLCD.clrScr();             
    drawscreen_three();      
    myGLCD.print("NO DTC", 180, 145);
    
                         }
 
  // при получении сообщения о наличии ошибок DTC разберем сообщение выведем на экран ошибки
  if (MessageRx_PCM[n]==0x58 && MessageRx_PCM[n+1]>0){
     
     myGLCD.clrScr();             
     drawscreen_three();       

  for (int i=0; i<MessageRx_PCM[n+8-7]; i++ ) {
     int y = i*35;
     bool nolA=0; bool nolB =0;
  if (!bitRead(MessageRx_PCM[n+11-7+(i*3)],6) && bitRead(MessageRx_PCM[n+11-7+(i*3)],7)){ myGLCD.setTextColor(GREEN, BLACK); 
     myGLCD.print(" -Passive-", 300, (75+y));} // если DTC пасивныый делаем цвет зеленый 
  if (bitRead(MessageRx_PCM[n+11-7+(i*3)],7) && bitRead(MessageRx_PCM[n+11-7+(i*3)],6)) { myGLCD.setTextColor(RED, BLACK);  
     myGLCD.print(" -Active-", 300, (75+y));} // если DTC активный, делаем цвет красный 
     myGLCD.print("ERROR ", 50, (75+y));
     myGLCD.printNumI((i+1), 150, (75+y));
     
  if (!bitRead(MessageRx_PCM[n+9-7+(i*3)],6) && !bitRead(MessageRx_PCM[n+9-7+(i*3)],7)) myGLCD.print(": P", 170, (75+y));
  if (bitRead(MessageRx_PCM[n+9-7+(i*3)],6) && !bitRead(MessageRx_PCM[n+9-7+(i*3)],7)) myGLCD.print(": C", 170, (75+y));
  if (!bitRead(MessageRx_PCM[n+9-7+(i*3)],6) && bitRead(MessageRx_PCM[n+9-7+(i*3)],7)) myGLCD.print(": B", 170, (75+y));
  if (bitRead(MessageRx_PCM[n+9-7+(i*3)],6) && bitRead(MessageRx_PCM[n+9-7+(i*3)],7)) myGLCD.print(": U", 170, (75+y));

  if (MessageRx_PCM[n+9-7+(i*3)]==0x00) {myGLCD.print("00", 230, (75+y)); nolA = 1;}
  if (MessageRx_PCM[n+9-7+(i*3)]<=0x0F&&MessageRx_PCM[n+9-7+(i*3)]!=0) {myGLCD.print("0", 230, (75+y)); nolA = 1;} 
  if (nolA)myGLCD.print(String (MessageRx_PCM[n+9-7+(i*3)],HEX), 246, (75+y)); 
  else myGLCD.print(String (MessageRx_PCM[n+9-7+(i*3)],HEX), 230, (75+y));

  if (MessageRx_PCM[n+10-7+(i*3)]==0x00) {myGLCD.print("00", 262, (75+y)); nolB = 1;}
  if (MessageRx_PCM[n+10-7+(i*3)]<=0x0F&&MessageRx_PCM[n+10-7+(i*3)]!=0) {myGLCD.print("0", 262, (75+y)); nolB = 1;}
  if (nolB)myGLCD.print(String (MessageRx_PCM[n+10-7+(i*3)]),HEX, 278, (75+y)); 
  else myGLCD.print(String (MessageRx_PCM[n+10-7+(i*3)],HEX), 262, (75+y));}} 

request = PRESENT; RequestPeriod = 4000;  prevRequest = curmillis;

}



void dataVars(const byte &n) 
{

static float L100M_last = 1;              //расход на 100 км измеренный за поездку
static float L100_last = 1;               //мгновенный расход литров на 100км
static float LHor_last = 1;               //мгновенный расход топлива литров в час
static float L100SR_TFT_last = 1;         // самый средний из расходов на 100км, он выводится на экран

static int MAF_last = 1;           //26,27 байты   Sensor de flujo de aire en masa
static float BoostPres_last = 1;   //28,29 байты   Presión de refuerzo
static int RPM_last = 1;           //32,33 байты   Velocidad del motor
static int EGRmg_last = 1;         //34,35 байты   Comando EGR (Comando de recirculación de gases de escape)
static float BoostPresCom_last = 1;//38,39 байты   Comando de presión de refuerzo
static int Speed_last = 1;         //44,45 байты   Velocidad del vehículo
static float DesaInjQua_last = 1;  //50,51 байты   Cantidad de inyección deseada
static float InjQua_last = 1;      //52,53 байты   Cantidad de la inyección
static float StaDaliv_last = 1;    //54,55 байты   Inicio de la entrega
static int PumpRPM_last = 1;       //56,57 байты   Velocidad de la bomba
static float EGRPul_last = 1;      //62,63 байты   Relación de impulsos EGR (recirculación de gases de escape
static float SolenPul_last = 1;    //64,65 байты   Velocidad de solenoide de control de nivel de remolino Relación de impulsos
static float SolenPre_last = 1;    //70,71 байты   Relación de impulsos Presión Electroválvula de presión
static float DesInj_last = 1;      //72,73 байты   Inyección deseada Inicio
static float ActInj_last = 1;      //16,17 байты   Inicio de la inyección real
static int TempAir_last = 1;       //74,75 байты   Temperatura del aire de admisión
static int Temp_last = 1;          //14,15 байты   Temperatura del refrigerante
static int TempOil_last = 1;       //18,19 байты   Temperatura del aceite del motor
static int TempFuel_last = 1;      //58,59 байты   Temperatura del combustible
static int IntTemp_last =  1;      //Температура улицы
static float Fuel_last =  1;         //уровень топлива в баке 



  
  //Barom = MessageRx_PCM[39];
   
   MAF =  ((MessageRx_PCM[n+22]*256)+MessageRx_PCM[n+23])/10;
   BoostPres =  ((MessageRx_PCM[n+24]*256)+MessageRx_PCM[n+25])/1000.0;
   RPM =  (MessageRx_PCM[n+35-7]*256)+MessageRx_PCM[n+36-7];
   EGRmg =  ((MessageRx_PCM[n+37-7]*256)+MessageRx_PCM[n+38-7])/10.0;
   BoostPresCom =  ((MessageRx_PCM[n+41-7]*256)+MessageRx_PCM[n+42-7])/1000.0;
   Speed =  ((MessageRx_PCM[n+47-7]*256)+MessageRx_PCM[n+48-7])/100;
   DesaInjQua =  ((MessageRx_PCM[n+53-7]*256)+MessageRx_PCM[n+54-7])/100.0;
   InjQua =  ((MessageRx_PCM[n+55-7]*256)+MessageRx_PCM[n+56-7])/100.0;
   StaDaliv =  ((MessageRx_PCM[n+57-7]*256)+MessageRx_PCM[n+58-7])/100.0;
   PumpRPM =  (MessageRx_PCM[n+59-7]*256)+MessageRx_PCM[n+60-7];
   EGRPul =  ((MessageRx_PCM[n+65-7]*256)+MessageRx_PCM[n+66-7])/100.0;
   SolenPul =  ((MessageRx_PCM[n+67-7]*256)+MessageRx_PCM[n+68-7])/100.0;
   SolenPre =  ((MessageRx_PCM[n+73-7]*256)+MessageRx_PCM[n+74-7])/100.0;
   DesInj =  ((MessageRx_PCM[n+75-7]*3)+(MessageRx_PCM[n+76-7])/100.0)+0.3;
   ActInj =  ((MessageRx_PCM[n+19-7]*3)+(MessageRx_PCM[n+20-7])/100.0)+0.3;
   //TempAir =  ((MessageRx_PCM[n+77-7]*26)-278)+MessageRx_PCM[n+78-7]/10.0;
   //Temp =  ((MessageRx_PCM[n+17-7]*26)-278)+MessageRx_PCM[n+18-7]/10.0;
   //TempOil =  ((MessageRx_PCM[n+21-7]*26)-278)+MessageRx_PCM[n+22-7]/10.0;
   //TempFuel =  ((MessageRx_PCM[n+61-7]*26)-278)+MessageRx_PCM[n+62-7]/10.0;
   //ниже идут расчетные формулы более точные чем те что закоментированы выше
   LHor = (float)RPM* (float)InjQua*2.00/1000.0*60.00/1000.0/0.85;
   if (Speed!=0) L100 = (float)LHor*100.0/(float)Speed;
   else L100 = 99;
      
   int A = 0;
   if  (MessageRx_PCM[n+77-7]<=0x0A) A = 277;
   if  (MessageRx_PCM[n+77-7]==0x0B || MessageRx_PCM[n+77-7]==0x0C) A = 278;
   if  (MessageRx_PCM[n+77-7]>=0x0D) A = 279;
   double B = MessageRx_PCM[n+78-7]/10.0;
   double cel , drob ;
   drob = modf(B, &cel);
   if (drob>0.6) cel++;
     TempAir =  ((MessageRx_PCM[n+77-7]*26)-A)+cel;
   
   if  (MessageRx_PCM[n+17-7]<=0x0A) A = 277;
   if  (MessageRx_PCM[n+17-7]==0x0B || MessageRx_PCM[n+17-7]==0x0C) A = 278;
   if  (MessageRx_PCM[n+17-7]>=0x0D) A = 279;
   B = MessageRx_PCM[n+18-7]/10.0;
   drob = modf(B, &cel);
   if (drob>0.6) cel++;
     Temp =  ((MessageRx_PCM[n+17-7]*26)-A)+cel;


   if  (MessageRx_PCM[n+21-7]<=0x0A) A = 277;
   if  (MessageRx_PCM[n+21-7]==0x0B || MessageRx_PCM[n+21-7]==0x0C) A = 278;
   if  (MessageRx_PCM[n+21-7]>=0x0D) A = 279;
   B = MessageRx_PCM[n+22-7]/10.0;
   drob = modf(B, &cel);
   if (drob>0.6) cel++;
     TempOil =  ((MessageRx_PCM[n+21-7]*26)-A)+cel;


   if  (MessageRx_PCM[n+61-7]<=0x0A) A = 277;
   if  (MessageRx_PCM[n+61-7]==0x0B || MessageRx_PCM[n+61-7]==0x0C) A = 278;
   if  (MessageRx_PCM[n+61-7]>=0x0D) A = 279;
   B = MessageRx_PCM[n+62-7]/10.0;
   drob = modf(B, &cel);
   if (drob>0.6) cel++;
     TempFuel =  ((MessageRx_PCM[n+61-7]*26)-A)+cel;   
     
  //----------------------------------------------------------
  //страниц HOME
  //----------------------------------------------------------
     
     //myGLCD.setBackColor(RED);
     myGLCD.setTextColor(WHITE, BLACK);
     //myGLCD.setBackColor(RED);
     if ((Speed != Speed_last) || reNew) {myGLCD.printNumI(Speed, 360, 7, 3); Speed_last=Speed;}
  if (currentPage == '0') {
     if ((LHor != LHor_last) || reNew) {myGLCD.printNumF(LHor, 1, 75, 40, '.',4); LHor_last=LHor;}
     if ((L100 != L100_last) || reNew) {myGLCD.printNumF(L100, 1, 225, 40,'.',4 ); L100_last=L100;}
     if ((L100M != L100M_last) || reNew) {myGLCD.printNumF(L100M, 1, 75, 75,'.',4 ); L100M_last=L100M;}
     if ((L100SR_TFT != L100SR_TFT_last) || reNew) {myGLCD.printNumF(L100SR_TFT, 1, 225, 75,'.',4 ); L100SR_TFT_last=L100SR_TFT;}
     if ((kmREFUELING != kmREFUELING_last) || reNew) {myGLCD.printNumI(kmREFUELING, 90, 110,3 ); kmREFUELING_last=kmREFUELING;} 
     //if (Fuel<53) 
     if ((Fuel != Fuel_last) || reNew) {myGLCD.printNumF(Fuel, 1, 225, 110,'.',4); Fuel_last=Fuel;}
     //else myGLCD.print("MAX", 210, 110); 
     if ((kmTrip != kmTrip_last) || reNew) {myGLCD.printNumF(kmTrip, 1, 60, 145,'.',5); kmTrip_last=kmTrip;}
     if ((FuelTrip != FuelTrip_last) || reNew) {myGLCD.printNumF(FuelTrip, 1, 210, 145,'.',5); FuelTrip_last=FuelTrip;}
     if ((PumpRPM != PumpRPM_last) || reNew) {myGLCD.printNumI(PumpRPM, 230, 180,4); PumpRPM_last=PumpRPM;}
     if ((RPM != RPM_last) || reNew) {myGLCD.printNumI(RPM, 230, 215,4); RPM_last=RPM;}
     if ((Fuel2 != Fuel2_last) || reNew) {myGLCD.printNumF(Fuel2, 1, 10, 215,'.',4); Fuel2_last=Fuel2;}      
     if ((Temp != Temp_last) || reNew) {myGLCD.printNumI(Temp, 415, 40, 3); Temp_last=Temp;}
     if ((TempOil != TempOil_last) || reNew) {myGLCD.printNumI(TempOil, 415, 75, 3); TempOil_last=TempOil;}
     if ((TempFuel != TempFuel_last) || reNew) {myGLCD.printNumI(TempFuel, 415, 110,3); TempFuel_last=TempFuel;} 
     if ((IntTemp != IntTemp_last) || reNew)   {myGLCD.printNumI(IntTemp, 415, 145 , 3); IntTemp_last=IntTemp;} 
     if ((t != t_last) || reNew) {myGLCD.printNumI(t, 415, 180, 3); t_last=t;}
     if ((TempAir != TempAir_last) || reNew) {myGLCD.printNumI(TempAir, 415, 215, 3); TempAir_last=TempAir;}
     reNew = 0; 
     }
   //----------------------------------------------------------
   //страниц INF1
   //----------------------------------------------------------
   if (currentPage == '1') {
     if ((StaDaliv != StaDaliv_last) || reNew) {myGLCD.printNumF(StaDaliv,1, 385, 40,'.', 4); StaDaliv_last=StaDaliv;}
     if ((DesInj != DesInj_last) || reNew) {myGLCD.printNumF(DesInj,1, 385, 75, '.', 4); DesInj_last=DesInj;}
     if ((ActInj != ActInj_last) || reNew) {myGLCD.printNumF(ActInj,1, 385, 110,'.', 4); ActInj_last=ActInj;} 
     if ((DesaInjQua != DesaInjQua_last) || reNew) {myGLCD.printNumF(DesaInjQua,1, 385, 145,'.', 4);DesaInjQua_last=DesaInjQua;}  
     if ((InjQua != InjQua_last) || reNew) {myGLCD.printNumF(InjQua,1, 385, 180,'.', 4); InjQua_last=InjQua;} 
     if ((MAF != MAF_last) || reNew) {myGLCD.printNumI(MAF, 170, 215, 4); MAF_last=MAF;}
     if ((h != h_last) || reNew) {myGLCD.printNumF(h, 1, 430, 215, 3); h_last=h;}
     reNew = 0; 
     }
   //----------------------------------------------------------
   //страниц INF2
   //----------------------------------------------------------
   if (currentPage == '2') {    
     if ((BoostPres != BoostPres_last) || reNew) {myGLCD.printNumF(BoostPres,1, 400, 40,'.', 4); BoostPres_last=BoostPres;}  
     if ((BoostPresCom != BoostPresCom_last) || reNew) {myGLCD.printNumF(BoostPresCom,1, 400, 75,'.', 4); BoostPresCom_last=BoostPresCom;} 
     if ((EGRmg != EGRmg_last) || reNew) {myGLCD.printNumI(EGRmg, 400, 110, 4); EGRmg_last=EGRmg;}  
     if ((EGRPul != EGRPul_last) || reNew) {myGLCD.printNumF(EGRPul,1, 400, 145,'.', 4); EGRPul_last=EGRPul;}
     if ((SolenPul != SolenPul_last) || reNew) {myGLCD.printNumF(SolenPul, 1, 400, 180,'.', 4); SolenPul_last=SolenPul;} 
     if ((SolenPre != SolenPre_last) || reNew) {myGLCD.printNumF(SolenPre, 0, 400, 215,'.', 4); SolenPre_last=SolenPre;}
     reNew = 0; 
     }
 //reNew = 0;
}



 void sendMessagePCM(const byte &command)
{
 #ifdef debugPCM                         
Serial.print (F("Send request "));  Serial.print (textRequest[command]); Serial.print (F(" to PCM  ")); Serial.println (millis());
 #endif
if (command != INIT) {NOanswer_timer = 1; prev_NOanswer = curmillis;}  //т.к. сейчас будем делать запрос, то запускаем таймер контроля неответов 
  byte size =  PCM_Message_TX[command][0];
  const byte siZe = size+4;
  byte Mes[siZe];
  byte Checksum = 0;
  for(byte i=0; i<siZe; i++) {
    if (i==0) {Mes[i]=size; bitWrite(Mes[i], 7 , 1);}
    if (i==1) Mes[i] = PCM_address;
    if (i==2) Mes[i] = DIAG_address;    
    if (i==3) {for (byte t=1; t<size+1; t++ ) {
           Mes[i]=PCM_Message_TX [command][t]; 
           Checksum+=Mes[i] ; 
           K_LINE_PCM.write (Mes[i]); 
           if (command == INIT) delay (5); else delay (1);  
           K_LINE_PCM.read(); 
           i++;}}
    if (i!=siZe-1) Checksum+=Mes[i];
    else Mes[i] = Checksum;    
    K_LINE_PCM.write (Mes[i]);
   if (command == INIT) delay (5); else delay (1);
    K_LINE_PCM.read();
                             }
}// end sendMessagePCM


void Trip ()
{
static uint32_t prevRefueling = 0; 
if (curmillis - prevRefueling>1000)
  {   static float rashod [60]={0};
      static byte yacheyka_numer = 0;
  rashod[yacheyka_numer] = L100;
  

  if (yacheyka_numer == 59) 
    {
//-----------------расчет среднего расхода 
float km_prev = 0;
  EEPROM.get (130, km_prev);    // считываем из еепром пробег  прошлого измерения каждую минуту
   
 float kmTrip_refuel = 0;
 if (kmAge>km_prev) kmTrip_refuel = kmAge - km_prev;
 if (kmAge<km_prev)  kmTrip_refuel = 2000 - (km_prev - kmAge);
 if (kmAge==km_prev) kmTrip_refuel = 0; 
 
if (kmTrip_refuel >=kmL) {
  float l_prev = 0;
  EEPROM.get (140, l_prev);   // считываем из еепром уровень топлива прошлого измерения
  if (l_prev-Fuel > 0) L100SR = ((float)(l_prev-Fuel)*100.00)/(float)kmL;
  EEPROM.put (140, Fuel);    // записываем в еепром уровень топлива текущего измерения
  EEPROM.put (130, kmAge);   // записываем в еепром пробег текущего измерения

 byte n_eeprom = EEPROM.read (150);    // в ячейке 150 хранится № текущей ячейки для записи расхода, чтобы где остановился при выкл питания, от туда и продолжил
 EEPROM.put(n_eeprom, L100SR); 
 n_eeprom+=4; if (n_eeprom>16) n_eeprom=0;
 EEPROM.write (150,n_eeprom); 
 float summar = 0.0;
 for (int i = 0; i < 20; i+=4) {float summar_=0.0;   EEPROM.get (i, summar_);   summar +=summar_;} 
 L100SR_TFT = summar/5.00;                 
}
//-----------------расчет пробега до заправки
  
      static byte yacheyka_number=0;
      static float rashod_sr[20]={0};
       float summa = 0.00;
       for (int i = 0; i<60; i++) {summa+=rashod [i];}  
        summa/=60.00; 
       rashod_sr[yacheyka_number] = summa;
      
      if (yacheyka_number == 19) {
        float summasr = 0.00;
       for (int i = 0; i<20; i++) {summasr+=rashod_sr [i];}  
        summasr/=20.00; 
        
        kmREFUELING=Fuel*100.00/summasr;}// end of 20 minuts;
      
     yacheyka_number++; if (yacheyka_number>19) yacheyka_number = 0;   
        
    }  // end of 1 minuts

//---------------расчёт пробега и расхода за поездку 

if (yacheyka_numer == 5) {
if (flagkmAgeIGN){

 FuelTrip = FuelIGN - Fuel;                          
  if (kmAge>kmAgeIGN) kmTrip = kmAge - kmAgeIGN;
  if (kmAge<kmAgeIGN) kmTrip = 2000 - (kmAgeIGN - kmAge);  // 2000 это через сколько км у тебя суточный пробег сбрасывается на ноль, поменяй если другое число
  if (kmAge==kmAgeIGN) kmTrip = 0;


 //подсчет расхода на 100км за поездку
 L100M = ((float)FuelTrip*100.00)/(float)kmTrip;
  if (L100M<0) L100M = 0;
  if (L100M>99) L100M = 99;
                 }}
  
  yacheyka_numer++; if (yacheyka_numer>59) yacheyka_numer = 0;
      prevRefueling = curmillis;
  }
}


/*
void Trip () {

 
 
 if (flagkmAgeIGN){

 FuelTrip = FuelIGN - Fuel;                          
  if (kmAge>kmAgeIGN) kmTrip = kmAge - kmAgeIGN;
  if (kmAge<kmAgeIGN) kmTrip = 2000 - (kmAgeIGN - kmAge);  // 2000 это через сколько км у тебя суточный пробег сбрасывается на ноль, поменяй если другое число
  if (kmAge==kmAgeIGN) kmTrip = 0;


 //подсчет расхода на 100км за поездку
 L100M = ((float)FuelTrip*100.00)/(float)kmTrip;
  if (L100M<0) L100M = 0;
  if (L100M>99) L100M = 99;

 // ниже цикл считает среднеарифметический расход из еепром раз в пробег, указанный в переменной kmeeprom
  if (kmTrip-kmTFT>kmeeprom) {kmTFT = kmTrip; 

 // тут считаем среднеарифметический усредненного расхода из ячеек еепром 
int summ = 0;
 for (int i = 0; i < 11; i++) summ +=  EEPROM.read(i);
 L100SR_TFT = summ / 110.00;
 if (L100SR_TFT<0) L100SR_TFT = 0;
 if (L100SR_TFT>99) L100SR_TFT = 25;}
 
 // ниже цикл считает расход топлива за пробег, указанный в переменной kmL, здесь же запись в ячейки еепром 
  if (kmTrip-km>kmL) {km=kmTrip; 
 L100SR = ((float)(fuel_last-Fuel)*100.00)/(float)kmL; // расход/100км  - обновляется раз в 10км, меняется км в int kmL = 10;
 fuel_last = Fuel;      // сохранение параметров с последнего измерениея 
  if (L100SR<0) L100SR = 0;
  if (L100SR>99) L100SR = 99;

 //расчет расстояния до заправки
 if (L100SR>0) kmREFUELING=((float)Fuel*100.0)/(float)L100SR; //если средний расход больше нуля, то расчитывать расстояние до заправки из него
 else kmREFUELING=((float)Fuel*100.00)/(float)L100SR_TFT;    //если ноль или меньше то расчитывать расстояние до заправки с усредненного расхода

 // тут записываем  L100SR последовательно в одну из 11 ячеек еепром
 //EEPROM.write (12,n_eeprom);      // ЗДЕСЬ ВНИМАТЕЛЬНО. ЗАГРУЗИТЬ ПРОШИВКУ С ЭТОЙ СТРОКОЙ ОДИН РАЗ, ПОТОМ ЗАКОМЕНТИРОВАТЬ И ЕЩЁ РАЗ ЗАГРУЗИТЬ
 byte n_eeprom = EEPROM.read (12);    // в ячейке 12 хранится № текущей ячейки для записи расхода, чтобы где остановился при выкл питания, от туда и продолжил
 EEPROM.write(n_eeprom, L100SR*10); 
 n_eeprom++; if (n_eeprom>10) n_eeprom=0;
 EEPROM.write (12,n_eeprom); 
 
 #ifdef debugTRIP
Serial.println (" I am heer:  if (kmTrip-km>kmL) {}  "); 
Serial.print (" L100SR = "); Serial.print (L100SR) ; Serial.println (" L/100km");
Serial.print (" kmREFUELING = "); Serial.print (kmREFUELING) ; Serial.println (" km");
#endif
 
 
 }
 
 #ifdef debugTRIP
Serial.print (" FuelTrip = "); Serial.print (FuelTrip); Serial.println (" L");
Serial.print (" kmTrip = "); Serial.print (kmTrip); Serial.println (" km");
Serial.print (" L100SR_TFT = "); Serial.print (L100SR_TFT); Serial.println (" L/100km");
#endif

 }}
*/


void receiveGAUGE () {


static uint32_t prevRESETheaderGAUGE=0; // таймер сброса сообщения, если данные оборвались посередине сообщения 
static bool RESETheader_timerGAUGE;     // таймер сброса сообщения, если данные оборвались посередине сообщения  

static uint32_t prevNoconnect = 0;      // таймер периодической проверки наличия связи со щитком приборов
static byte NoconnectsGAUGE = 0 ;       // счетчик неответов от щитка приборов 
static byte message_sizeGAUGE = 0;      // размер тела сообщения
static byte jGAUGE = 3;                 // инкремент
static byte nGAUGE = 3;                 // количество старт байт
static int ChecksumGAUGE =0;            // байт контрольной суммы 
static byte InitGauge = 0;              // автомат состояния инита щитка приборов 
const byte bufsizeG = 100;              // размер буфера принятого сообщения
static byte MessageRx_GAUGE [bufsizeG] = {0};   // буфер принятого сообщения
byte PIDgauge[] = {0x02,0x11,0x00,0x13}; // запрос параметоров щитка приборов



 if (K_LINE_GAUGE.available() ){
    
 // первый старт байт
 if (headerGAUGE == 0){ MessageRx_GAUGE[0]=K_LINE_GAUGE.read();  
   if ((InitGauge ==1 && MessageRx_GAUGE[0]==0x55) || (InitGauge ==2 && MessageRx_GAUGE[0]!=0xFF && MessageRx_GAUGE[0]!=0x7F)
   || (InitGauge ==3 && MessageRx_GAUGE[0]==0x23)
      )
          {headerGAUGE = 1; RESETheader_timerGAUGE = 1; prevRESETheaderGAUGE = curmillis; 
               #ifdef debugGAUGE
                  Serial.print (F("Receive GAUGE: ")); printDebugRX(MessageRx_GAUGE[0]);
               #endif               
          }
                                    }                  

 // второй старт байт
 else if (headerGAUGE == 1){ MessageRx_GAUGE[1]=K_LINE_GAUGE.read(); 
 #ifdef debugGAUGE
      printDebugRX (MessageRx_GAUGE[1]);
 #endif
      if ( (InitGauge ==1 && MessageRx_GAUGE[1]==0x52)  ||     (InitGauge ==2 && (MessageRx_GAUGE[1]==0xA0 || MessageRx_GAUGE[1]==0xF0))  
      || (InitGauge == 3 && MessageRx_GAUGE[1]==0xA1)){ headerGAUGE = 2;} 
      else {
        #ifdef debugGAUGE 
        Serial.println(F(" GAUGE Message fail address")); 
        #endif
        headerGAUGE = 0; RESETheader_timerGAUGE = 0;}} 

 // третий старт байт
 else if (headerGAUGE == 2){ 
  
  MessageRx_GAUGE[2]=K_LINE_GAUGE.read(); 
  #ifdef debugGAUGE
  printDebugRX (MessageRx_GAUGE[2]);
  #endif
  if ((InitGauge ==2 && (MessageRx_GAUGE[2]==0x48 || MessageRx_GAUGE[2]==0x55 || MessageRx_GAUGE[2]==0xAA)) || (InitGauge == 3 && MessageRx_GAUGE[2]==0x04)){ message_sizeGAUGE = MessageRx_GAUGE[0]-2; prevRESETheaderGAUGE = curmillis;
       headerGAUGE = 4;  jGAUGE=3; nGAUGE=3;
      
       if (message_sizeGAUGE > bufsizeG) message_sizeGAUGE = bufsizeG;  ChecksumGAUGE = 0;} 
  else if (InitGauge ==1 && MessageRx_GAUGE[2]==0x80) {InitGauge = 2; K_LINE_GAUGE.write(0x7F); delay (2); K_LINE_GAUGE.read();  headerGAUGE = 0; RESETheader_timerGAUGE = 0; 
             #ifdef debugGAUGE
             Serial.println ("Gauge INIT is good!"); 
             #endif
                                                      }     
  else {headerGAUGE = 0; 
        #ifdef debugGAUGE 
        Serial.println(F("GAUGE Message fail address")); 
        #endif
        RESETheader_timerGAUGE = 0;}
  
                          }  

  // пишем тело сообщения 
 else if (headerGAUGE == 4 && jGAUGE< message_sizeGAUGE+nGAUGE+1) {
 MessageRx_GAUGE[jGAUGE] = K_LINE_GAUGE.read(); prevRESETheaderGAUGE = curmillis;
 if (jGAUGE<message_sizeGAUGE+nGAUGE-1) ChecksumGAUGE+= MessageRx_GAUGE[jGAUGE]; // подсчёт КС
 
 if (jGAUGE==message_sizeGAUGE+nGAUGE) headerGAUGE = 5; 
  
 #ifdef debugGAUGE
 printDebugRX(MessageRx_GAUGE[jGAUGE]);
 #endif  
 jGAUGE++;                                             } 
 }

 // сообщение приняли, действуем
 if (headerGAUGE == 5) {  
 #ifdef debugGAUGE
 Serial.println();
 #endif  
 
  
for(byte i = 0; i<nGAUGE; i++) ChecksumGAUGE+=MessageRx_GAUGE[i]; // прибавляем к контрольной сумме старт байты
int ChecksumG =  ( ( unsigned int )MessageRx_GAUGE[message_sizeGAUGE+nGAUGE-1] << 8 ) | MessageRx_GAUGE[message_sizeGAUGE+nGAUGE]; // парсинг контрольной суммы из 2 последних байт 
 // если контрольная сумма верна: 
if ( ChecksumGAUGE == ChecksumG) 
{  NoconnectsGAUGE = 0; // сбрасываем на 0 отсутствие связи с панелью
  #ifdef debugGAUGE
  Serial.print (F("Received message is OK! Checksum is correct!"));  Serial.print (F("  ")); Serial.println (millis()); // Если КС совпала, тут чёнибудь нужное делаем
  #endif

      if (MessageRx_GAUGE[1]== 0xA0 && MessageRx_GAUGE[2]== 0x48) {
           #ifdef debugGAUGE
           Serial.println ("ID panel receive! Send request PIDGauge"); 
           #endif
           InitGauge = 3; 
           for (byte i=0; i<sizeof(PIDgauge); i++) { K_LINE_GAUGE.write (PIDgauge[i]); delay (1); K_LINE_GAUGE.read();}
                                                                  }

       if (MessageRx_GAUGE[1]== 0xF0 && (MessageRx_GAUGE[2]== 0xAA || MessageRx_GAUGE[2]== 0x55)) {
           #ifdef debugGAUGE
           Serial.println ("receive present from Gauge. I send PID to Gauge"); 
           #endif
           InitGauge = 3; 
           for (byte i=0; i<sizeof(PIDgauge); i++) { K_LINE_GAUGE.write (PIDgauge[i]); delay (1); K_LINE_GAUGE.read();}
                                                                  }

                                                                  

      if (MessageRx_GAUGE[1]== 0xA1 && MessageRx_GAUGE[2]== 0x04) {
           #ifdef debugGAUGE
           Serial.println (" receive Datastream Gauge!");
           #endif
 Fuel2 = MessageRx_GAUGE[nGAUGE + 16]/2.0; 
 if (!flagFuelIGN) {  Fuel = MessageRx_GAUGE[nGAUGE + 16]/2.0;  kmREFUELING=((float)Fuel*100.00)/(float)L100SR_TFT;} //стартовая запись литров в баке для подсчета затраченных литро
 else Fuel = MessageRx_GAUGE[nGAUGE + 17]/2.0; //для усреднения болтания в баке закоментировать эту строку, а раскоментировать ниже
            
 //для усреднения болтания топлива в баке, раскоментировать, высчитывает среднее
 /*else { FuelZamer[ZamerNumber] = MessageRxGauge[17]/2.00;
 if (ZamerNumber==9) {
 Fuel = 0 ;
 for (int i = 0; i < 10; i++) Fuel = Fuel + FuelZamer[i];
 Fuel = (float)Fuel/10.0;}
 ZamerNumber++; if (ZamerNumber>9) ZamerNumber = 0;}
*/

  kmAge = (MessageRx_GAUGE[nGAUGE + 23]+(MessageRx_GAUGE[nGAUGE + 24]*256))/10.0; //суточный пробег с панели приборов

  //бак у меня на 59 литров, а датчик показывает максимально 53 литра. для этого эта формула
  //если у вас тоже датчик имеет лимит то подправте 53 на свой лимит. 
  //если ваш датчик показывает одинаково с полным баком то закоментировать три нижние строки. 
  if (Fuel<53){
  if (!flagkmAgeIGN) { kmAgeIGN = kmAge; flagkmAgeIGN =1;}
  if (!flagFuelIGN) { FuelIGN = Fuel; fuel_last = Fuel; flagFuelIGN = 1;}}

#ifdef debugTRIP
Serial.print (" Fuel = "); Serial.print (Fuel); Serial.println (" L");
Serial.print (" kmAge = "); Serial.print (kmAge); Serial.println (" km");
#endif

           
                                                                  }
 }   

// если контрольная сумма не совпала: 
#ifdef debugGAUGE
  else Serial.println("CRC fail!!!" );
#endif
message_sizeGAUGE = 0; headerGAUGE=0; RESETheader_timerGAUGE = 0; jGAUGE=3; ChecksumGAUGE = 0;
}

// таймер сброса целостности сообщения (если данные оборвались посередине сообщения)
if (RESETheader_timerGAUGE && curmillis - prevRESETheaderGAUGE > 300) { 
  #ifdef debugGAUGE 
  Serial.println(F("Message fail timeout")); 
  #endif 
  RESETheader_timerGAUGE = 0; headerGAUGE = 0;}   

 if (curmillis - prevNoconnect > 500) {NoconnectsGAUGE ++ ; if (NoconnectsGAUGE>=8){
 #ifdef debugGAUGE 
  Serial.println (F("       Connect GAUGE failed!!! ")) ;
 #endif
  NoconnectsGAUGE = 0 ;InitGauge = 0 ; } prevNoconnect = curmillis; }
 
 InitBusGAUGE (InitGauge);
}// end receiveGAUGE


void InitBusGAUGE (byte &InitGauge) 
{
  uint32_t prevInitbusGauge = 0;   // таймер для инита щитка приборов
  
    if (InitGauge == 0){
#ifdef debugGAUGE 
  Serial.println ("Send startsession - address Gauge");
#endif   
  K_LINE_GAUGE.end();
   pinMode(TX_gauge, OUTPUT);
   digitalWrite (TX_gauge, HIGH);                                           // BUS IDLE
   InitGauge = 5; prevInitbusGauge = curmillis;
   }  
 if (InitGauge == 5 && curmillis - prevInitbusGauge>1500)  {InitGauge = 6;} // BUS IDLE
 if (InitGauge == 6)
 {    
   byte boudrate = 1000/BAUD;
   digitalWrite (TX_gauge, LOW);   delay (boudrate); // старт бит
   for (byte i=0; i<8; i++){digitalWrite (TX_gauge, bitRead(addressGUAGE, i)); delay (boudrate);} // биты тела адреса 
   digitalWrite (TX_gauge, HIGH);  delay (boudrate); // стоп бит
   K_LINE_GAUGE.begin(9600);
   InitGauge = 1; 
 }
}




#if defined debugPCM or defined debugGAUGE
void printDebugRX (const byte &inbyte) {if (inbyte<=15) Serial.print(F("0")); Serial.print (inbyte, HEX);  Serial.print (F(" "));}
#endif

#ifdef debugPCM
void printDebugRX_CSgood(const byte &n){
if (MessageRx_PCM[n]==0xC1 && MessageRx_PCM[n+1]==0x6B && MessageRx_PCM[n+2]==0x8F) {Serial.println (F("   Initialization OK!!!!")); }
 else if (MessageRx_PCM[n]==0x58 && MessageRx_PCM[n+1]==0x00) {Serial.println (F("     NO DTC  "));}
 else if (MessageRx_PCM[n]==0x58 && MessageRx_PCM[n+1] >0x00) {Serial.println (F("     DTC is found!"));} 
 else if (MessageRx_PCM[n]==0x54 && MessageRx_PCM[n+1]==0xFF && MessageRx_PCM[n+2]==0x00){Serial.println (F("     DTC CLEARED  "));}
 else if (MessageRx_PCM[n]==0x61 && MessageRx_PCM[n+1]==0x01) {Serial.println (F("     Receive PCM DATAstream"));}}
#endif                          



void Menu () {
     TouchHOME();
    if (currentPage == '0') {
     
     TouchINF1();
     TouchINF2();
     TouchCHECK(); }
    if (currentPage == '1') { 
     
     TouchINF2();
     TouchCHECK(); }
    if (currentPage == '2') { 
     
     TouchINF1();
     TouchCHECK(); }
    if (currentPage == '3') { 
     
     TouchREAD();
     TouchERASE(); }}   
 
 
  void drawHomeScreen() {
    line() ;
    //myGLCD.print(":", 290, 5);
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setTextColor(RED, BLACK); // цвет линии и текста красный
    myGLCD.drawLine(295,35,295,248); // линия вертикальная
    myGLCD.drawLine(145,35,145,178); // линия вертикальная
    myGLCD.drawLine(80,178,80,247); // линия вертикальная
    myGLCD.print("L/H", 10, 40);
    myGLCD.print("L/A", 148, 40);
    myGLCD.print("L/V", 10, 75);
    myGLCD.print("L/M", 148, 75);
    myGLCD.print("D/K", 10, 110);
    myGLCD.print("D/L", 148, 110);
    myGLCD.print("V/K", 10, 145);
    myGLCD.print("V/L", 148, 145);
    myGLCD.print("PUMP  RPM", 82, 180);
    myGLCD.print("ENGI   RPM", 82, 215);
    myGLCD.print("D/L/A", 10, 180);
    myGLCD.print("Motor C", 300, 40);
    myGLCD.print("OIL     C", 300, 75);
    myGLCD.print("FUEL   C", 300, 110);
    myGLCD.print("FUERA  C", 300, 145);
    myGLCD.print("DENTRO  C", 300, 180);
    myGLCD.print("INTAIR  C", 300, 215);
    //myGLCD.setTextColor(RED); 
    myGLCD.drawRoundRect (15, 255, 145, 310);
    myGLCD.print("INF 1", 55, 270);
    myGLCD.drawRoundRect (175, 255, 305, 310);
    myGLCD.print("INF 2", 215, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("CHECK", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 7);
    myGLCD.print("Km/h", 410, 7);
    reNew = 1;
    Watch ();
  }
 //-------------------------------------------------
   void drawscreen_one() {
    line() ;
    //myGLCD.print(":", 290, 5);
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setTextColor(RED, BLACK); // цвет линии и текста красный
    myGLCD.print("Start of Delivery   *CA:", 10, 40);
    myGLCD.print("Desir inject Start  *CA:", 10, 75);
    myGLCD.print("Actua Inject Start  *CA:", 10, 110);
    myGLCD.print("Desir Inject Quan  mg/s:", 10, 145);
    myGLCD.print("Actu Inject Quant mg/s:", 10, 180);
    myGLCD.print("MAF  mg/s:", 10, 215);
    myGLCD.print("Humedad %:", 255, 215);
    //myGLCD.setTextColor(RED);
    myGLCD.drawRoundRect (175, 255, 305, 310);
    myGLCD.print("INF 2", 215, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("CHECK", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 7);
    myGLCD.print("Km/h", 410, 7);
    reNew = 1;
    Watch ();
    }
 //-------------------------------------------------
  void drawscreen_two() {
    line() ;
    //myGLCD.print(":", 290, 5);
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setTextColor(RED, BLACK); // цвет линии и текста красный
    myGLCD.print("Boost Press       Bar:", 10, 40);
    myGLCD.print("Boost Press Com  Bar:", 10, 75);
    myGLCD.print("EGR command     mg/s:", 10, 110);
    myGLCD.print("EGR Pulse Ratio      %:", 10, 145);
    myGLCD.print("Solenoide Pulse      %:", 10, 180);
    myGLCD.print("Solenoide Boost      %:", 10, 215);
    //myGLCD.setColor(RED);
    myGLCD.drawRoundRect (15, 255, 145, 310);
    myGLCD.print("INF 1", 55, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("CHECK", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 7);
    myGLCD.print("Km/h", 410, 7);
    reNew = 1;
    Watch ();
    }
 //----------------------------------------------------------------------------
  void drawscreen_three() {
    //myGLCD.print(":", 290, 5);
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setTextColor(RED, BLACK); // цвет линии красный
    myGLCD.drawLine(1,35,479,35); // линия горизонтальная
    myGLCD.drawLine(1,248,479,248); // линия горизонтальная
    //myGLCD.setTextColor(RED);
    myGLCD.drawRoundRect (15, 255, 145, 310);
    myGLCD.print("ERASE", 55, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("READ", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 5);
    reNew = 1;
    Watch ();
   }

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//кнопки тач . координаты и переходы
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void TouchHOME(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {if (p.x > 140 && p.x < 320 && p.y > 140 && p.y < 260 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (1, 1, 77, 37);
        currentPage = '0';     
        request = PID; RequestPeriod = 10; prevRequest = curmillis; // на PCM в этом окне посылается запрос текущих параметров
        myGLCD.clrScr();             
        drawHomeScreen();
        x = 0;
        y = 0;
        p.z = 0;}}}

void TouchINF1(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
      if (p.x > 150 && p.x < 450 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (15, 255, 145, 310);
        currentPage = '1';    
        request = PID; RequestPeriod = 10; prevRequest = curmillis; // на PCM в этом окне посылается запрос текущих параметров       
        myGLCD.clrScr();             
        drawscreen_one();
        x = 0;
        y = 0;
        p.z = 0;}}}
    
void TouchINF2(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
    if (p.x > 450 && p.x < 680 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (175, 255, 305, 310);
        currentPage = '2';     
        request = PID; RequestPeriod = 600; prevRequest = curmillis; // на PCM в этом окне посылается запрос текущих параметров      
        myGLCD.clrScr();             
        drawscreen_two();
        x = 0;
        y = 0;
        p.z = 0;}}}

void TouchCHECK(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
if (p.x > 690 && p.x < 950 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (335, 255, 465, 310);
        currentPage = '3';  
  //     request = DTCREAD; RequestPeriod = 10; prevRequest = curmillis; // на PCM в этом окне посылается запрос чтения ошибок  
        myGLCD.clrScr();             
        drawscreen_three();
        x = 0;
        y = 0;
        p.z = 0;}}}

void TouchREAD(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
if (p.x > 690 && p.x < 950 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (335, 255, 465, 310);
        request = DTCREAD; RequestPeriod = 300; prevRequest = curmillis; // на PCM при нажатии этой кнопки посылается запрос чтения ошибок  
        x = 0;
        y = 0;
        p.z = 0;}}}

void TouchERASE(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
if (p.x > 150 && p.x < 450 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      {myGLCD.drawRoundRect (15, 255, 145, 310);
       request = DTCERASE; RequestPeriod = 300;  prevRequest = curmillis; // на PCM при нажатии этой кнопки посылается запрос удаления ошибок
       myGLCD.clrScr();
       drawscreen_three();
       myGLCD.print("DTC BORRADO", 180, 145);
       
        x = 0;
        y = 0;
        p.z = 0;}}}
 ////////////////////////////////////////////////////////////////////////////////////////
 //прорисовка линий
 ///////////////////////////////////////////////////////////////////////////////////////
 void line() {
    //myGLCD.setTextColor(RED); // цвет линии красный
    myGLCD.drawLine(1,35,479,35); // линия горизонтальная
    myGLCD.drawLine(1,73,479,73); // линия горизонтальная
    myGLCD.drawLine(1,108,479,108); // линия горизонтальная
    myGLCD.drawLine(1,143,479,143); // линия горизонтальная
    myGLCD.drawLine(1,178,479,178); // линия горизонтальная
    myGLCD.drawLine(1,212,479,212); // линия горизонтальная
    myGLCD.drawLine(1,248,479,248); // линия горизонтальная
             }


void Watch (){
   DateTime now = rtc.now();
   int minut = now.minute(); 
   int hour = now.hour();
   int mon = now.month();
   int date = now.day();
   int Year = now.year();
 static  int minut_last; 
 static  int hour_last;
 static  int mon_last;
 static  int date_last;
 static  int Year_last;
 myGLCD.setTextColor(WHITE, BLACK); //белый цвет цифры

 if (date != date_last || reNew){ myGLCD.printNumI(date, 85, 7, 2, '0'); date_last = date; }

 if (mon!=mon_last || reNew){myGLCD.printNumI(mon, 130, 7, 2, '0'); mon_last = mon; }  
 
 if (Year!=Year_last || reNew) {  myGLCD.printNumI(Year, 175, 7); Year_last = Year; }
   
 if (hour!=hour_last || reNew){ myGLCD.printNumI(hour, 255, 7, 2, '0'); hour_last = hour; } 
   
 if (minut!=minut_last || reNew ){ myGLCD.printNumI(minut, 300, 7, 2, '0'); minut_last = minut; }
   } 

void Temperature () { 

     static boolean p=0; // флаг работы: запрос температуры или её чтение
p=!p;
if (p) {ds.reset();      // сброс шины
        ds.write(0xCC);  // обращение ко всем датчикам
        ds.write(0x44);  // начать преобразование (без паразитного питания)  
       }
else   {
 
        int Temper_= 20;  byte buff[9];
        ds.reset();
        ds.select(DSaddress);    
        ds.write(0xBE); // Read Scratchpad (чтение регистров)  
        for (byte j = 0; j<9; j++) buff[j]= ds.read(); //читаем все 9 байт от датчика 
        ds.reset();
        if (OneWire::crc8(buff, 8) == buff[8]){        // если контрольная сумма совпадает
        Temper_ =  buff[0] | (buff[1]<<8);             // читаем температуру из первых двух байт (остальные были нужны для проверки CRC)
        Temper_ = Temper_ / 16;
        if  (Temper_ < 150 && Temper_ > -50 && Temper_ !=85 && Temper_!=-127)  IntTemp =  Temper_;
                 
                                              }
                                                      
}
   }

здесь применил расчёт среднего расхода с измерениями на больших дистанциях в 50км для увеличения точности. А данные сохраняются в еепром ,т.к. за одну поездку не всегда получается проезжать 50 км, поэтому при старте МК измерения продолжатся с последнего момента. Т.е. проехали 30 км, в следующий раз он и считает уже с 30 км, т.е. нужно ещё 20 проехать для того, чтобы произошло измерение. 

а расчёт пробега до заправки сделан по мгновенному расходу с помощью интегрирования (среднеарифметическое между 60 измерениями, которые делаются раз в 15 сек).  Т.е. этот параметр обновляется раз в 15 минут. 

 

viki13viki
Offline
Зарегистрирован: 14.11.2016

звучит круто. значит заливаю первый, подставив данные, и потом заливаю второй и сегодня прокатить?

сделал. поставил 1744 км, 12 литров, и 6.7 расход, залил. Потом залил второй, на экране показало средний 6.7 , и расчитало бак на 164 км, актуальный расход 99.0. завтра отпишу после пробега

MaksVV
Offline
Зарегистрирован: 06.08.2015

нашёл пару ошибок, исправил 2083. 

viki13viki
Offline
Зарегистрирован: 14.11.2016

я так понимаю по 2083 до исправления ошибок нет смысла отчитыватся. Но тем не мение. Вчера пройдено около 35км. Со старта расчет километров в баке был реальным 170 км, через киллометров 15 стало 23 км в баке и так аж до дома. Средний со старта так и остался 6.7 л на 100 км. Утром выехал сново со старта было км в баке реально спустя 11-15 км сново показал занижено гдето 20 с чемто. Средний оставался 6.7 л на 100 км. Проехал 20 км заехал на заправку. заправил бак на полную. Завел и сбросил суточный на ноль, и сразу показало что я 200 км уже проехал, не стал заморачиватся глушить, поехал дальше. Км в баке показало на 805 км. Доезжая до работы пройдя километров 6 , вдруг средний расход сменился на 5.4 л на 100 км, км в баке так и остались на 805 км. На работе заглушил и включил показало средний 5.4 и км в  баке 1007 км. Может какието выводы можно из этого сделать. Сегодня залью подправленый 2083, если я сейчас его залью 10 км хватит для теста? учитываю что буду гонять по кругу большому с поворотами и маленькими спусками и подьемчиками учитывая что будет сильная болтанка в баке, это даст какойто результат для проверки? или лучше уже вечером домой сделать нормальный прогон?

MaksVV
Offline
Зарегистрирован: 06.08.2015

пробег до заправки очень коряво должен был показывать, в этом и была ошибка , я там формулу не ту написал. так что тут нечему удивляться.  При заправке не надо скидывать суточный на ноль. Этим самым ты вводишь в ступор бортовик. Через 2000 км на ноль он сам безболезненно должен перепрыгивать . Если заправился , по идее один из расчетов среднего расхода просто должен пропуститься , т.е. следующие 50 км после заправки средний расход будет без изменений. 

viki13viki
Offline
Зарегистрирован: 14.11.2016

Я понял. Но при заправки полного бака я всегда скидываю суточный, привычка, так как знаю что до загорания лампочки приезжаю где-то 770 км. Привычка.

MaksVV
Offline
Зарегистрирован: 06.08.2015

аа, ну тогда надо и на бортовике делать кнопку сброса этих значений, а то не корректно будет одно измерение, от слова совсем. Логика в новом скетче такая. 

Расчёт среднего расхода происходит раз в 50км при отсутствии заправки и сброса суточного пробега. 

Расчёт пробега до заправки делается так: в течение одной минуты раз в секунду записывается мгновенный расход. Итого имеем 60 значений. Считаем среднее арифметическое. Далее это среднее опять записывается в массив из 20 значений. По истечении записи в этот массив (двадцатое значение) считается опять среднеарифметический расход на сотню и уже здесь и считается пробег до заправки. Таким образом пробег до заправки обновляется раз в 20 минут . Соответственно если мы стоим и не едем, то расход записывается по 99 л/100км. Поэтому в пробках расстояние до заправки будет снижаться. 

Не знаю на сколько такой алгоритм будет адекватен. 

viki13viki
Offline
Зарегистрирован: 14.11.2016

Раньше я всегда так делал, но у меня было задано расход 7.6 в формуле. С другой стороны он же считает по пробегом за поездку а не от полной суточной цифры. Или ты что-то изменил?
Я думаю чтобы уже не парится, просто км в баке я подкину 6.7, меня очень устраивало, нужно только со средним расходом сделать порядок, и фиг с ним.

MaksVV
Offline
Зарегистрирован: 06.08.2015

изменил . Теперь значения пробега и количества литров от прошлого измерения сохраняются в еепром. А раньше каждое измерение происходило в пределах одного цикла зажигания. Теперь же, включая зажигание, мы как бы продолжаем измерение, пока не наступит разница в 50 км . между текущем пробегом и сохранённом в еепром  .

viki13viki
Offline
Зарегистрирован: 14.11.2016

Я понял. Но сброс для меня как подстраховка, в принципе если бы бортовиков выдавал более менее правдиво и стабильно а не с прыжкам то 500 то 320 и т.д, я бы не сбрасывал. Хз, стоит ли так усложнятся. Меня бы устроило 6.7 в формуле и просто упорядочить вывод среднего расхода, ты уже наверняка замучился с моим скетчем.

MaksVV
Offline
Зарегистрирован: 06.08.2015

если измерение среднего расхода придёт в норму , будешь просто пробег до заправки от него считать и все. 

MaksVV
Offline
Зарегистрирован: 06.08.2015

250км не ползуйся сбросом суточного посмотрим как работает

viki13viki
Offline
Зарегистрирован: 14.11.2016

Ок. Понял 250 км не сбрасывая. Не до понял другое, если прийдет средний в норму.. ( Типа допустим 6.9 пришёл в норму), будешь пробег до заправки от него считать. Что ты имеешь в виду?

MaksVV
Offline
Зарегистрирован: 06.08.2015

в строку 630 вставить kmREFUELING=Fuel*100.00/L100SR_TFT;

строки 631-647 убрать

viki13viki
Offline
Зарегистрирован: 14.11.2016

ок. понял

viki13viki
Offline
Зарегистрирован: 14.11.2016

Макс дела такие.... спустя 400 км пробега наконец то вышло на примерно правдивое показание 7.6 л на 100 , в начале теста было 5.4 потом в течении времени падало и упало до 3.4 и потом начало потихоньку расти и сегодня вышло на 7.6 а вечером на 8.4, но.... все это время происходило такое, километры в баке со старта показывают правильно спустя пару минут падает очень низко, например, сегодня включил зажигание км в баке 415 что есть верно, спустя пару минут упало до 51 км в баке, спустя 10 или 15 км прогона стало 10 км в баке и спустя 27 км пробега показало 26 км в баке. Похоже косяк происходит из за того что я тогда сбил суточный. Как убрать эту зависимость от полного цикла суточного пробега. Я так понимаю что от привязки к целому суточному циклу средний расход от этого зависит а за ним уже и км в баке пляшут.  Так как привычка сбивать при следующей полной заправке не уйдет, и будут вечно косяки может вернуть как то логику как была раньше, я все время сбивал суточный и на средний расход это никак не влияло а км в баке было в формуле подставлен мой средний расход 6.7. Вот скетч с последними под правками которые ты говорил

//------------все для связи по K-line (тут настраиваем UARTы к-лайников, адреса блоков, скорость инита и отладку) 
#include <SoftwareSerial.h>
 #define TX_PCM 13
 SoftwareSerial K_LINE_PCM   (12, TX_PCM); //RХ,TХ    //UART на котором висит K_line к PCM

#define K_LINE_GAUGE Serial2   //UART     на котором висит K_line к приборке 
#define TX_gauge 16            //TX UARTa на котором висит K_line к приборке 

#define PCM_address  0x11      // адрес PCM 
#define DIAG_address 0xF1      // адрес диагностики

const byte BAUD=200;           // init baudrate - скорость инита при подключении к приборке 
const byte addressGUAGE = 0xB8;// init GAUGE address - адрес щитка приборов при ините (установке связи)

#define debugPCM             // раскоментировать эту строку для отладки в Serial порту обмена с PCM
//#define debugGAUGE             // раскоментировать эту строку для отладки в Serial порту обмена co щитком приборов
//#define debugTRIP             // раскоментировать эту строку для отладки в Serial порту данных бортовика
 
uint32_t curmillis = 0;        // снимок текущего времени 
 
//------------------------------------------переменные для организации протокола связи с PCM

uint32_t prevRequest  = 0;     // таймер периодических запосов на PCM
uint16_t RequestPeriod = 3500; // периодичность запросов на PCM
byte header = 0;               // состояние заголовка
bool NOanswer_timer = 0;       // таймер контроля неответов от ЭБУ после подачи запросов
uint32_t prev_NOanswer=0;      // таймер контроля неответов от ЭБУ после подачи запросов
// возможные варианты запросов на ЭБУ:
enum REQUEST {INIT, PID, DTCERASE, DTCREAD, PRESENT,};

#ifdef debugPCM 
// текстовки запросов для отладки 
char* textRequest[] = {"INIT", "PID_2101", "DTC_ERASE", "DTC_READ", "PRESENT",} ;
#endif 

 // сами запросы
 byte PCM_Message_TX[][5] = {
 {1,  0x81,           0,0,0},    // запрос инициализации
 {2,  0x21,0x01,        0,0},    // запрос пид 2101
 {3,  0x14,0xFF,0x00,     0},    // запрос на стирание ошибок
 {4,  0x18,0x00,0xFF,0x00  },    // запрос на чтение ошибок
 {1,  0x3E,           0,0,0},    // запрос присутствия 
                            };
byte request = INIT;             // переменная, показывающая какой запрос будем делать
static byte headerGAUGE = 0;            // состояние заголовка сообщений щитка  приборов

const byte bufsize = 150;           // размер буфера принятого сообщения
byte MessageRx_PCM [bufsize] = {0}; // буфер принятого сообщения


//-------------------------------------------переменные бортовика

 float L100M = 0;      //расход на 100 км измеренный за поездку
 float L100 = 0;       //мгновенный расход литров на 100км
 float LHor = 0;       //мгновенный расход топлива литров в час
 float L100SR = 0;     //расход литров на 100км измеренный раз в интервал kmL  
 float L100SR_TFT = 0; // самый средний из расходов на 100км, он выводится на экран

 //int L100_Eeprom[11]= {10,10,10,10,10,10,10,10,10,10,10};
 //int FuelZamer[10]= {0};  // массив для измерения уровня (количества) топлива 
 //int ZamerNumber = 0;     // номер замера уровня (количества) топлива 
 
 
 int MAF = 0;            //26,27 байты   Sensor de flujo de aire en masa
 float BoostPres = 0;    //28,29 байты   Presión de refuerzo
 int RPM = 0;            //32,33 байты   Velocidad del motor
 int EGRmg = 0;          //34,35 байты   Comando EGR (Comando de recirculación de gases de escape)
 float BoostPresCom = 0; //38,39 байты   Comando de presión de refuerzo
 int Speed = 0;          //44,45 байты   Velocidad del vehículo
 float DesaInjQua = 0;   //50,51 байты   Cantidad de inyección deseada
 float InjQua = 0;       //52,53 байты   Cantidad de la inyección
 float StaDaliv = 0;     //54,55 байты   Inicio de la entrega
 int PumpRPM = 0;        //56,57 байты   Velocidad de la bomba
 float EGRPul = 0;       //62,63 байты   Relación de impulsos EGR (recirculación de gases de escape
 float SolenPul = 0;     //64,65 байты   Velocidad de solenoide de control de nivel de remolino Relación de impulsos
 float SolenPre = 0;     //70,71 байты   Relación de impulsos Presión Electroválvula de presión
 float DesInj = 0;       //72,73 байты   Inyección deseada Inicio
 float ActInj = 0;       //16,17 байты   Inicio de la inyección real
 int TempAir = 0;        //74,75 байты   Temperatura del aire de admisión
 int Temp = 0;           //14,15 байты   Temperatura del refrigerante
 int TempOil = 0;        //18,19 байты   Temperatura del aceite del motor
 int TempFuel = 0;       //58,59 байты   Temperatura del combustible
 int IntTemp = 0;        //Температура улицы
 
 //все что касается топлива
 float Fuel = 0;       //остаток топлива 
 float Fuel2 = 0;    float Fuel2_last = 1; //остаток мгновенного топлива байт 16 , датчика в баке
 float FuelIGN = 0;      // количество топлива в баке на момент включения зажигания
 float fuel_last = 0;    // для формул
 bool flagFuelIGN = 0; // флаг записан ли остаток топлива в момент вкл. зажигания 
 float FuelTrip = 0; float FuelTrip_last = 1;    // количество литров топлива, израсходованное за один цикл включения зажигания
 
 //все что касается километража
 float kmAge = 0;           //пробег, полученный со щитка приборов
 float kmAgeIGN = 0;          //пробег который был в момент включения зажигания 
 bool flagkmAgeIGN = 0;     //флаг записан ли пробег в момент вкл. зажигания 
 float kmTrip = 0; float kmTrip_last = 1;           //пробег за один цикл включения зажигания
 const int kmL = 50;              // интервал, через который будет происходить обновление среднего расхода на 100км
// int km = 0;                // переменная для расчетов
// const int kmeeprom = 15;         // интервал, через который будет происходить подсчет среднеарифмитического расхода  L100SR_TFT
// int kmTFT =  0;     // переменная для расчетов периодического подсчета среднеарифмитического расхода топлива L100SR_TFT
 int kmREFUELING = 0; int kmREFUELING_last = 1;     // пробег до заправки на остатке топлива 
 
 unsigned long prevWatch = 0;
 unsigned long prevDvoet = 0;
 

//----------------------------------------------для экрана 
#include <Adafruit_GFX.h>
 #include <MCUFRIEND_kbv.h>
 #include <UTFTGLUE.h>//use GLUE class and constructor
 #include "TouchScreen.h"
 #include <stdint.h>
 #include <SPI.h>
 #include <EEPROM.h>
 //#include "Fonts/Chosence_Bold16pt7b.h";

#define MINPRESSURE 200
#define MAXPRESSURE 1000

//pin 20 SCL , 21 SDA датчик реального времени
 #include <Wire.h>
 #include "RTClib.h"
 RTC_DS3231 rtc;       

UTFTGLUE myGLCD(0x1581,A2,A1,A3,A4,A0); //all dummy args
 
 const int XP = 6, XM = A2, YP = A1, YM = 7; 
 const int TS_LEFT = 136, TS_RT = 907, TS_TOP = 139, TS_BOT = 942;
 TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
 uint16_t ID;
 int x, y;
 char currentPage;
 float h; int h_last = 1; 
 float t; int t_last = 1; 
 bool Dvoet = 0;
 bool reNew = 0;
 #define BLACK 0x0000
 #define WHITE 0xFFFF
 #define RED   0xF800
 #define GREEN 0x07E0

 //--------------------------------------датчики t

byte DSaddress[] = {0x28, 0xFF, 0xA6, 0x19, 0xA8, 0x15, 0x01, 0xD2};
//датчик внутринней температуры и влаги
 #include "DHT.h"
 #define DHTPIN 26   
 #define DHTTYPE DHT22 
 DHT dht(DHTPIN, DHTTYPE);
#include <OneWire.h>
 #define ONE_WIRE_BUS 22   
 OneWire ds(ONE_WIRE_BUS);



 
void setup() {
   uint16_t ID = myGLCD.readID();
   if (ID == 0xD3D3) ID = 0x1581; // write-only shield
   myGLCD.begin(ID);  
   myGLCD.InitLCD(3);
   myGLCD.clrScr();
   myGLCD.setTextSize(2);
   //myGLCD.setFont(&Chosence_Bold16pt7b);
   Wire.begin();
   rtc.begin();
   dht.begin();
   //загрузка стартовой страницы
   currentPage = '0';       
   drawHomeScreen();  

   //подсчет среднеарифметического усредненного расхода
 float summar = 0;
 for (int i = 0; i < 20; i+=4) {float summar_;   EEPROM.get (i, summar_);   summar +=summar_;} 
 L100SR_TFT = summar/5.00;    
 L100SR = L100SR_TFT;
   
   /*
   
   int summ=0;
 for (int i = 0; i < 11; i++) summ +=  EEPROM.read(i);
 L100SR_TFT = summ / 110.00;
   if (L100SR_TFT<0) L100SR_TFT = 0;
   if (L100SR_TFT>99) L100SR_TFT = 99;
  */
   // строка ниже используется для настройки даты и времени часов 
   // раскоментировать, выставить времая и дату, залить в ардуино. в скетче закоментировать
   // обратно и залить еще раз, иначе каждый раз будет по новой выствлятся это же время и дата
   // (год, месяц, день, часы, минуты, секунды)
   //rtc.adjust(DateTime(2019, 7, 2, 10, 48, 0));
  
 #if defined debugPCM or defined debugGAUGE or defined debugTRIP
   Serial.begin(115200);
 #endif
   K_LINE_PCM.begin(10400);
   pinMode(TX_PCM, OUTPUT);
  
             }


    void loop() 

                
                {
                  
curmillis = millis();              // снимок текущего времени

if (curmillis - prevRequest > RequestPeriod && header == 0 ) 
    {
  if (request == INIT) fastinit();                                          // при необходимости делаем переподключение к PCM
  else {sendMessagePCM(request);                                            // отправляем на PCM текущий запрос
         if (request == PID) RequestPeriod = 600; 
         if (request == DTCERASE || request == DTCREAD) RequestPeriod = 2500;} 
  prevRequest = curmillis;
    }

receivePCM ();   // приём сообщений от PCM
receiveGAUGE (); // приём сообщений от щитка приборов
if (header == 0 && headerGAUGE == 0) {Menu ();}
if (curmillis - prevWatch > 4000)  { Watch (); prevWatch = curmillis;  h = dht.readHumidity(); t = dht.readTemperature();Temperature ();}
//if (curmillis - prevDvoet > 500)  { if (!Dvoet) {myGLCD.setTextColor(WHITE); } else {myGLCD.setTextColor(BLACK); }  myGLCD.print(":", 290, 5); prevDvoet = curmillis; Dvoet=!Dvoet;}                
if (curmillis - prevDvoet > 500)  { if (!Dvoet) {myGLCD.print(":", 285, 5);} else {myGLCD.print(" ", 285, 5);} prevDvoet = curmillis; Dvoet=!Dvoet;}
Trip ();
                }// end loop

 void fastinit() {
   digitalWrite (TX_PCM, HIGH);  // bus idle
   delay(1500);              
   digitalWrite (TX_PCM, LOW);  // first part fastinit  (25 ms LOW)
   delay(25);
   digitalWrite (TX_PCM, HIGH); // second part fastinit (25 ms HIGH)
   delay(25);               
   K_LINE_PCM.begin(10400);
   sendMessagePCM(INIT);        // send start communication message 
      }  
 
  
  void receivePCM () {

static uint32_t prevRESETheader=0;    // таймер сброса сообщения, если данные оборвались посередине сообщения 
static bool RESETheader_timer;        // таймер сброса сообщения, если данные оборвались посередине сообщения 
static byte noanswers = 0;            // количество подряд неответов от ЭБУ 
static byte message_size = 0;         // размер тела сообщения
static byte j = 3;                    // инкремент
static byte n = 3;                    // количество старт байт
static byte crc =0;                   // байт контрольной суммы 



 if (K_LINE_PCM.available() ){
    
 // первый старт байт
 if (header == 0){ MessageRx_PCM[0]=K_LINE_PCM.read();  
         if (MessageRx_PCM[0]!=0xFF && bitRead (MessageRx_PCM[0],7)){header = 1; RESETheader_timer = 1; prevRESETheader = curmillis; 
               #ifdef debugPCM
                  Serial.print (F("Receive PCM: ")); printDebugRX(MessageRx_PCM[0]);
               #endif               
                                                }
                          }                  

 // второй старт байт
 else if (header == 1){ MessageRx_PCM[1]=K_LINE_PCM.read(); 
 #ifdef debugPCM
      printDebugRX (MessageRx_PCM[1]);
 #endif
      if (MessageRx_PCM[1]==DIAG_address){ header = 2;} 
      else {
        #ifdef debugPCM 
        Serial.println(F(" PCM Message fail address")); 
        #endif
        header = 0; RESETheader_timer = 0;}} 

 // третий старт байт
 else if (header == 2){ 
  MessageRx_PCM[2]=K_LINE_PCM.read(); 
  #ifdef debugPCM
  printDebugRX (MessageRx_PCM[2]);
  #endif
  if (MessageRx_PCM[2]==PCM_address){ message_size = MessageRx_PCM[0]; prevRESETheader = curmillis;
       if (MessageRx_PCM[0] !=0x80) {header = 4;  bitWrite (message_size, 7 , 0);j=3;n=3;}
       else {header = 3; j=4;n=4;}
       if (message_size > bufsize) message_size = bufsize;  crc = 0;} 
  else {header = 0; 
        #ifdef debugPCM 
        Serial.println(F("PCM Message fail address")); 
        #endif
        RESETheader_timer = 0;}
  
                          }  
// если размер сообщения указан в дополнительном байте (нулевой байт 0x80) читаем этот дополнительный байт:
else if (header == 3){
   prevRESETheader = curmillis;
  MessageRx_PCM[3]=K_LINE_PCM.read(); 
  #ifdef debugPCM
  printDebugRX(MessageRx_PCM[3]);
  #endif
  message_size = MessageRx_PCM[3]; 
  if (message_size > bufsize) message_size = bufsize;  
  crc = 0; header = 4;  
                         }

  // пишем тело сообщения 
 else if (header == 4 && j< message_size+n+1) {
 MessageRx_PCM[j] = K_LINE_PCM.read(); prevRESETheader = curmillis;
 if (j<message_size+n) crc+= MessageRx_PCM[j]; // подсчёт КС
 
 if (j==message_size+n) header = 5; 
 #ifdef debugPCM
 printDebugRX(MessageRx_PCM[j]);
 #endif  
 j++;                                             } 
 }

 // сообщение приняли, действуем
 if (header == 5) {
 #ifdef debugPCM
 Serial.println();
 #endif  
 NOanswer_timer = 0; noanswers = 0;              // сбрасываем таймер контроля неответов 
  
for(byte i = 0; i<n; i++) crc+=MessageRx_PCM[i]; // прибавляем к контрольной сумме старт байты

 // если контрольная сумма верна: 
if ( crc == MessageRx_PCM[message_size+n]) 
{  
  #ifdef debugPCM
  Serial.print (F("Received message is OK! Checksum is correct!"));  Serial.print (F("  ")); Serial.println (millis()); // Если КС совпала, тут чёнибудь нужное делаем
  printDebugRX_CSgood(n); 
  #endif
      if (MessageRx_PCM[n]==0xC1 && MessageRx_PCM[n+1]==0x6B && MessageRx_PCM[n+2]==0x8F) {
              if (currentPage!=3) {request = PID; RequestPeriod = 70;} else request = PRESENT, RequestPeriod = 4000; prevRequest = curmillis; // receive good INIT
                                                                                          }
 else if (MessageRx_PCM[n]==0x58) Troublecodes (n); // DTC
 else if (MessageRx_PCM[n]==0x54 && MessageRx_PCM[n+1]==0xFF && MessageRx_PCM[n+2]==0x00){ request = PRESENT; RequestPeriod = 4000; prevRequest = curmillis;} // DTC are cleared
 else if (MessageRx_PCM[n]==0x61 && MessageRx_PCM[n+1]==0x01) {dataVars(n) ; RequestPeriod = 70; prevRequest = curmillis; }           // receive DataStream
 
 
 }   

// если контрольная сумма не совпала: 
#ifdef debugPCM
  else Serial.println("CRC fail!!!" );
#endif
message_size = 0; header=0; RESETheader_timer = 0; j=3; crc = 0;
}

// таймер сброса целостности сообщения (если данные оборвались посередине сообщения)
if (RESETheader_timer && curmillis - prevRESETheader > 200) { 
  #ifdef debugPCM 
  Serial.println(F("Message fail timeout")); 
  #endif 
  RESETheader_timer = 0; header = 0;}   

 
// если нет ответа после запроса: +1 к счетчику неответов. Если накопилось 6 и более: делаем реинит.  
if (request!=INIT && NOanswer_timer && curmillis - prev_NOanswer > RequestPeriod - RequestPeriod/10) 
         {
     NOanswer_timer = 0; noanswers++; 
     if (noanswers>=6) { noanswers = 0; request = INIT; RequestPeriod = 3500;}
         }
}// end receivePCM


void Troublecodes (const byte &n) 
{
  if (MessageRx_PCM[n]==0x58 && MessageRx_PCM[n+1]==0x00){
    myGLCD.clrScr();             
    drawscreen_three();      
    myGLCD.print("NO DTC", 180, 145);
    
                         }
 
  // при получении сообщения о наличии ошибок DTC разберем сообщение выведем на экран ошибки
  if (MessageRx_PCM[n]==0x58 && MessageRx_PCM[n+1]>0){
     
     myGLCD.clrScr();             
     drawscreen_three();       

  for (int i=0; i<MessageRx_PCM[n+8-7]; i++ ) {
     int y = i*35;
     bool nolA=0; bool nolB =0;
  if (!bitRead(MessageRx_PCM[n+11-7+(i*3)],6) && bitRead(MessageRx_PCM[n+11-7+(i*3)],7)){ myGLCD.setTextColor(GREEN, BLACK); 
     myGLCD.print(" -Passive-", 300, (75+y));} // если DTC пасивныый делаем цвет зеленый 
  if (bitRead(MessageRx_PCM[n+11-7+(i*3)],7) && bitRead(MessageRx_PCM[n+11-7+(i*3)],6)) { myGLCD.setTextColor(RED, BLACK);  
     myGLCD.print(" -Active-", 300, (75+y));} // если DTC активный, делаем цвет красный 
     myGLCD.print("ERROR ", 50, (75+y));
     myGLCD.printNumI((i+1), 150, (75+y));
     
  if (!bitRead(MessageRx_PCM[n+9-7+(i*3)],6) && !bitRead(MessageRx_PCM[n+9-7+(i*3)],7)) myGLCD.print(": P", 170, (75+y));
  if (bitRead(MessageRx_PCM[n+9-7+(i*3)],6) && !bitRead(MessageRx_PCM[n+9-7+(i*3)],7)) myGLCD.print(": C", 170, (75+y));
  if (!bitRead(MessageRx_PCM[n+9-7+(i*3)],6) && bitRead(MessageRx_PCM[n+9-7+(i*3)],7)) myGLCD.print(": B", 170, (75+y));
  if (bitRead(MessageRx_PCM[n+9-7+(i*3)],6) && bitRead(MessageRx_PCM[n+9-7+(i*3)],7)) myGLCD.print(": U", 170, (75+y));

  if (MessageRx_PCM[n+9-7+(i*3)]==0x00) {myGLCD.print("00", 230, (75+y)); nolA = 1;}
  if (MessageRx_PCM[n+9-7+(i*3)]<=0x0F&&MessageRx_PCM[n+9-7+(i*3)]!=0) {myGLCD.print("0", 230, (75+y)); nolA = 1;} 
  if (nolA)myGLCD.print(String (MessageRx_PCM[n+9-7+(i*3)],HEX), 246, (75+y)); 
  else myGLCD.print(String (MessageRx_PCM[n+9-7+(i*3)],HEX), 230, (75+y));

  if (MessageRx_PCM[n+10-7+(i*3)]==0x00) {myGLCD.print("00", 262, (75+y)); nolB = 1;}
  if (MessageRx_PCM[n+10-7+(i*3)]<=0x0F&&MessageRx_PCM[n+10-7+(i*3)]!=0) {myGLCD.print("0", 262, (75+y)); nolB = 1;}
  if (nolB)myGLCD.print(String (MessageRx_PCM[n+10-7+(i*3)]),HEX, 278, (75+y)); 
  else myGLCD.print(String (MessageRx_PCM[n+10-7+(i*3)],HEX), 262, (75+y));}} 

request = PRESENT; RequestPeriod = 4000;  prevRequest = curmillis;

}



void dataVars(const byte &n) 
{

static float L100M_last = 1;              //расход на 100 км измеренный за поездку
static float L100_last = 1;               //мгновенный расход литров на 100км
static float LHor_last = 1;               //мгновенный расход топлива литров в час
static float L100SR_TFT_last = 1;         // самый средний из расходов на 100км, он выводится на экран

static int MAF_last = 1;           //26,27 байты   Sensor de flujo de aire en masa
static float BoostPres_last = 1;   //28,29 байты   Presión de refuerzo
static int RPM_last = 1;           //32,33 байты   Velocidad del motor
static int EGRmg_last = 1;         //34,35 байты   Comando EGR (Comando de recirculación de gases de escape)
static float BoostPresCom_last = 1;//38,39 байты   Comando de presión de refuerzo
static int Speed_last = 1;         //44,45 байты   Velocidad del vehículo
static float DesaInjQua_last = 1;  //50,51 байты   Cantidad de inyección deseada
static float InjQua_last = 1;      //52,53 байты   Cantidad de la inyección
static float StaDaliv_last = 1;    //54,55 байты   Inicio de la entrega
static int PumpRPM_last = 1;       //56,57 байты   Velocidad de la bomba
static float EGRPul_last = 1;      //62,63 байты   Relación de impulsos EGR (recirculación de gases de escape
static float SolenPul_last = 1;    //64,65 байты   Velocidad de solenoide de control de nivel de remolino Relación de impulsos
static float SolenPre_last = 1;    //70,71 байты   Relación de impulsos Presión Electroválvula de presión
static float DesInj_last = 1;      //72,73 байты   Inyección deseada Inicio
static float ActInj_last = 1;      //16,17 байты   Inicio de la inyección real
static int TempAir_last = 1;       //74,75 байты   Temperatura del aire de admisión
static int Temp_last = 1;          //14,15 байты   Temperatura del refrigerante
static int TempOil_last = 1;       //18,19 байты   Temperatura del aceite del motor
static int TempFuel_last = 1;      //58,59 байты   Temperatura del combustible
static int IntTemp_last =  1;      //Температура улицы
static float Fuel_last =  1;         //уровень топлива в баке 



  
  //Barom = MessageRx_PCM[39];
   
   MAF =  ((MessageRx_PCM[n+22]*256)+MessageRx_PCM[n+23])/10;
   BoostPres =  ((MessageRx_PCM[n+24]*256)+MessageRx_PCM[n+25])/1000.0;
   RPM =  (MessageRx_PCM[n+35-7]*256)+MessageRx_PCM[n+36-7];
   EGRmg =  ((MessageRx_PCM[n+37-7]*256)+MessageRx_PCM[n+38-7])/10.0;
   BoostPresCom =  ((MessageRx_PCM[n+41-7]*256)+MessageRx_PCM[n+42-7])/1000.0;
   Speed =  ((MessageRx_PCM[n+47-7]*256)+MessageRx_PCM[n+48-7])/100;
   DesaInjQua =  ((MessageRx_PCM[n+53-7]*256)+MessageRx_PCM[n+54-7])/100.0;
   InjQua =  ((MessageRx_PCM[n+55-7]*256)+MessageRx_PCM[n+56-7])/100.0;
   StaDaliv =  ((MessageRx_PCM[n+57-7]*256)+MessageRx_PCM[n+58-7])/100.0;
   PumpRPM =  (MessageRx_PCM[n+59-7]*256)+MessageRx_PCM[n+60-7];
   EGRPul =  ((MessageRx_PCM[n+65-7]*256)+MessageRx_PCM[n+66-7])/100.0;
   SolenPul =  ((MessageRx_PCM[n+67-7]*256)+MessageRx_PCM[n+68-7])/100.0;
   SolenPre =  ((MessageRx_PCM[n+73-7]*256)+MessageRx_PCM[n+74-7])/100.0;
   DesInj =  ((MessageRx_PCM[n+75-7]*3)+(MessageRx_PCM[n+76-7])/100.0)+0.3;
   ActInj =  ((MessageRx_PCM[n+19-7]*3)+(MessageRx_PCM[n+20-7])/100.0)+0.3;
   //TempAir =  ((MessageRx_PCM[n+77-7]*26)-278)+MessageRx_PCM[n+78-7]/10.0;
   //Temp =  ((MessageRx_PCM[n+17-7]*26)-278)+MessageRx_PCM[n+18-7]/10.0;
   //TempOil =  ((MessageRx_PCM[n+21-7]*26)-278)+MessageRx_PCM[n+22-7]/10.0;
   //TempFuel =  ((MessageRx_PCM[n+61-7]*26)-278)+MessageRx_PCM[n+62-7]/10.0;
   //ниже идут расчетные формулы более точные чем те что закоментированы выше
   LHor = (float)RPM* (float)InjQua*2.00/1000.0*60.00/1000.0/0.85;
   if (Speed!=0) L100 = (float)LHor*100.0/(float)Speed;
   else L100 = 99;
      
   int A = 0;
   if  (MessageRx_PCM[n+77-7]<=0x0A) A = 277;
   if  (MessageRx_PCM[n+77-7]==0x0B || MessageRx_PCM[n+77-7]==0x0C) A = 278;
   if  (MessageRx_PCM[n+77-7]>=0x0D) A = 279;
   double B = MessageRx_PCM[n+78-7]/10.0;
   double cel , drob ;
   drob = modf(B, &cel);
   if (drob>0.6) cel++;
     TempAir =  ((MessageRx_PCM[n+77-7]*26)-A)+cel;
   
   if  (MessageRx_PCM[n+17-7]<=0x0A) A = 277;
   if  (MessageRx_PCM[n+17-7]==0x0B || MessageRx_PCM[n+17-7]==0x0C) A = 278;
   if  (MessageRx_PCM[n+17-7]>=0x0D) A = 279;
   B = MessageRx_PCM[n+18-7]/10.0;
   drob = modf(B, &cel);
   if (drob>0.6) cel++;
     Temp =  ((MessageRx_PCM[n+17-7]*26)-A)+cel;


   if  (MessageRx_PCM[n+21-7]<=0x0A) A = 277;
   if  (MessageRx_PCM[n+21-7]==0x0B || MessageRx_PCM[n+21-7]==0x0C) A = 278;
   if  (MessageRx_PCM[n+21-7]>=0x0D) A = 279;
   B = MessageRx_PCM[n+22-7]/10.0;
   drob = modf(B, &cel);
   if (drob>0.6) cel++;
     TempOil =  ((MessageRx_PCM[n+21-7]*26)-A)+cel;


   if  (MessageRx_PCM[n+61-7]<=0x0A) A = 277;
   if  (MessageRx_PCM[n+61-7]==0x0B || MessageRx_PCM[n+61-7]==0x0C) A = 278;
   if  (MessageRx_PCM[n+61-7]>=0x0D) A = 279;
   B = MessageRx_PCM[n+62-7]/10.0;
   drob = modf(B, &cel);
   if (drob>0.6) cel++;
     TempFuel =  ((MessageRx_PCM[n+61-7]*26)-A)+cel;   
     
  //----------------------------------------------------------
  //страниц HOME
  //----------------------------------------------------------
     
     //myGLCD.setBackColor(RED);
     myGLCD.setTextColor(WHITE, BLACK);
     //myGLCD.setBackColor(RED);
     if ((Speed != Speed_last) || reNew) {myGLCD.printNumI(Speed, 360, 7, 3); Speed_last=Speed;}
  if (currentPage == '0') {
     if ((LHor != LHor_last) || reNew) {myGLCD.printNumF(LHor, 1, 75, 40, '.',4); LHor_last=LHor;}
     if ((L100 != L100_last) || reNew) {myGLCD.printNumF(L100, 1, 225, 40,'.',4 ); L100_last=L100;}
     if ((L100M != L100M_last) || reNew) {myGLCD.printNumF(L100M, 1, 75, 75,'.',4 ); L100M_last=L100M;}
     if ((L100SR_TFT != L100SR_TFT_last) || reNew) {myGLCD.printNumF(L100SR_TFT, 1, 225, 75,'.',4 ); L100SR_TFT_last=L100SR_TFT;}
     if ((kmREFUELING != kmREFUELING_last) || reNew) {myGLCD.printNumI(kmREFUELING, 90, 110,3 ); kmREFUELING_last=kmREFUELING;} 
     //if (Fuel<53) 
     if ((Fuel != Fuel_last) || reNew) {myGLCD.printNumF(Fuel, 1, 225, 110,'.',4); Fuel_last=Fuel;}
     //else myGLCD.print("MAX", 210, 110); 
     if ((kmTrip != kmTrip_last) || reNew) {myGLCD.printNumF(kmTrip, 1, 60, 145,'.',5); kmTrip_last=kmTrip;}
     if ((FuelTrip != FuelTrip_last) || reNew) {myGLCD.printNumF(FuelTrip, 1, 210, 145,'.',5); FuelTrip_last=FuelTrip;}
     if ((PumpRPM != PumpRPM_last) || reNew) {myGLCD.printNumI(PumpRPM, 230, 180,4); PumpRPM_last=PumpRPM;}
     if ((RPM != RPM_last) || reNew) {myGLCD.printNumI(RPM, 230, 215,4); RPM_last=RPM;}
     if ((Fuel2 != Fuel2_last) || reNew) {myGLCD.printNumF(Fuel2, 1, 10, 215,'.',4); Fuel2_last=Fuel2;}      
     if ((Temp != Temp_last) || reNew) {myGLCD.printNumI(Temp, 415, 40, 3); Temp_last=Temp;}
     if ((TempOil != TempOil_last) || reNew) {myGLCD.printNumI(TempOil, 415, 75, 3); TempOil_last=TempOil;}
     if ((TempFuel != TempFuel_last) || reNew) {myGLCD.printNumI(TempFuel, 415, 110,3); TempFuel_last=TempFuel;} 
     if ((IntTemp != IntTemp_last) || reNew)   {myGLCD.printNumI(IntTemp, 415, 145 , 3); IntTemp_last=IntTemp;} 
     if ((t != t_last) || reNew) {myGLCD.printNumI(t, 415, 180, 3); t_last=t;}
     if ((TempAir != TempAir_last) || reNew) {myGLCD.printNumI(TempAir, 415, 215, 3); TempAir_last=TempAir;}
     reNew = 0; 
     }
   //----------------------------------------------------------
   //страниц INF1
   //----------------------------------------------------------
   if (currentPage == '1') {
     if ((StaDaliv != StaDaliv_last) || reNew) {myGLCD.printNumF(StaDaliv,1, 385, 40,'.', 4); StaDaliv_last=StaDaliv;}
     if ((DesInj != DesInj_last) || reNew) {myGLCD.printNumF(DesInj,1, 385, 75, '.', 4); DesInj_last=DesInj;}
     if ((ActInj != ActInj_last) || reNew) {myGLCD.printNumF(ActInj,1, 385, 110,'.', 4); ActInj_last=ActInj;} 
     if ((DesaInjQua != DesaInjQua_last) || reNew) {myGLCD.printNumF(DesaInjQua,1, 385, 145,'.', 4);DesaInjQua_last=DesaInjQua;}  
     if ((InjQua != InjQua_last) || reNew) {myGLCD.printNumF(InjQua,1, 385, 180,'.', 4); InjQua_last=InjQua;} 
     if ((MAF != MAF_last) || reNew) {myGLCD.printNumI(MAF, 170, 215, 4); MAF_last=MAF;}
     if ((h != h_last) || reNew) {myGLCD.printNumF(h, 1, 430, 215, 3); h_last=h;}
     reNew = 0; 
     }
   //----------------------------------------------------------
   //страниц INF2
   //----------------------------------------------------------
   if (currentPage == '2') {    
     if ((BoostPres != BoostPres_last) || reNew) {myGLCD.printNumF(BoostPres,1, 400, 40,'.', 4); BoostPres_last=BoostPres;}  
     if ((BoostPresCom != BoostPresCom_last) || reNew) {myGLCD.printNumF(BoostPresCom,1, 400, 75,'.', 4); BoostPresCom_last=BoostPresCom;} 
     if ((EGRmg != EGRmg_last) || reNew) {myGLCD.printNumI(EGRmg, 400, 110, 4); EGRmg_last=EGRmg;}  
     if ((EGRPul != EGRPul_last) || reNew) {myGLCD.printNumF(EGRPul,1, 400, 145,'.', 4); EGRPul_last=EGRPul;}
     if ((SolenPul != SolenPul_last) || reNew) {myGLCD.printNumF(SolenPul, 1, 400, 180,'.', 4); SolenPul_last=SolenPul;} 
     if ((SolenPre != SolenPre_last) || reNew) {myGLCD.printNumF(SolenPre, 0, 400, 215,'.', 4); SolenPre_last=SolenPre;}
     reNew = 0; 
     }
 //reNew = 0;
}



 void sendMessagePCM(const byte &command)
{
 #ifdef debugPCM                         
Serial.print (F("Send request "));  Serial.print (textRequest[command]); Serial.print (F(" to PCM  ")); Serial.println (millis());
 #endif
if (command != INIT) {NOanswer_timer = 1; prev_NOanswer = curmillis;}  //т.к. сейчас будем делать запрос, то запускаем таймер контроля неответов 
  byte size =  PCM_Message_TX[command][0];
  const byte siZe = size+4;
  byte Mes[siZe];
  byte Checksum = 0;
  for(byte i=0; i<siZe; i++) {
    if (i==0) {Mes[i]=size; bitWrite(Mes[i], 7 , 1);}
    if (i==1) Mes[i] = PCM_address;
    if (i==2) Mes[i] = DIAG_address;    
    if (i==3) {for (byte t=1; t<size+1; t++ ) {
           Mes[i]=PCM_Message_TX [command][t]; 
           Checksum+=Mes[i] ; 
           K_LINE_PCM.write (Mes[i]); 
           if (command == INIT) delay (5); else delay (1);  
           K_LINE_PCM.read(); 
           i++;}}
    if (i!=siZe-1) Checksum+=Mes[i];
    else Mes[i] = Checksum;    
    K_LINE_PCM.write (Mes[i]);
   if (command == INIT) delay (5); else delay (1);
    K_LINE_PCM.read();
                             }
}// end sendMessagePCM


void Trip ()
{
static uint32_t prevRefueling = 0; 
if (curmillis - prevRefueling>1000)
  {   static float rashod [60]={0};
      static byte yacheyka_numer = 0;
  rashod[yacheyka_numer] = L100;
  

  if (yacheyka_numer == 59) 
    {
//-----------------расчет среднего расхода 
float km_prev = 0;
  EEPROM.get (130, km_prev);    // считываем из еепром пробег  прошлого измерения каждую минуту
   
 float kmTrip_refuel = 0;
 if (kmAge>km_prev) kmTrip_refuel = kmAge - km_prev;
 if (kmAge<km_prev)  kmTrip_refuel = 2000 - (km_prev - kmAge);
 if (kmAge==km_prev) kmTrip_refuel = 0; 
 
if (kmTrip_refuel >=kmL) {
  float l_prev = 0;
  EEPROM.get (140, l_prev);   // считываем из еепром уровень топлива прошлого измерения
  if (l_prev-Fuel > 0) L100SR = ((float)(l_prev-Fuel)*100.00)/(float)kmL;
  EEPROM.put (140, Fuel);    // записываем в еепром уровень топлива текущего измерения
  EEPROM.put (130, kmAge);   // записываем в еепром пробег текущего измерения

 byte n_eeprom = EEPROM.read (150);    // в ячейке 150 хранится № текущей ячейки для записи расхода, чтобы где остановился при выкл питания, от туда и продолжил
 EEPROM.put(n_eeprom, L100SR); 
 n_eeprom+=4; if (n_eeprom>16) n_eeprom=0;
 EEPROM.write (150,n_eeprom); 
 float summar = 0.0;
 for (int i = 0; i < 20; i+=4) {float summar_=0.0;   EEPROM.get (i, summar_);   summar +=summar_;} 
 L100SR_TFT = summar/5.00;
 kmREFUELING=Fuel*100.00/L100SR_TFT;  //расчет остатка км в баке                
  }
 }  // end of 1 minuts

//---------------расчёт пробега и расхода за поездку 

if (yacheyka_numer == 5) {
if (flagkmAgeIGN){

 FuelTrip = FuelIGN - Fuel;                          
  if (kmAge>kmAgeIGN) kmTrip = kmAge - kmAgeIGN;
  if (kmAge<kmAgeIGN) kmTrip = 2000 - (kmAgeIGN - kmAge);  // 2000 это через сколько км у тебя суточный пробег сбрасывается на ноль, поменяй если другое число
  if (kmAge==kmAgeIGN) kmTrip = 0;


 //подсчет расхода на 100км за поездку
 L100M = ((float)FuelTrip*100.00)/(float)kmTrip;
  if (L100M<0) L100M = 0;
  if (L100M>99) L100M = 99;
                 }}
  
  yacheyka_numer++; if (yacheyka_numer>59) yacheyka_numer = 0;
      prevRefueling = curmillis;
  }
}


/*
void Trip () {

 
 
 if (flagkmAgeIGN){

 FuelTrip = FuelIGN - Fuel;                          
  if (kmAge>kmAgeIGN) kmTrip = kmAge - kmAgeIGN;
  if (kmAge<kmAgeIGN) kmTrip = 2000 - (kmAgeIGN - kmAge);  // 2000 это через сколько км у тебя суточный пробег сбрасывается на ноль, поменяй если другое число
  if (kmAge==kmAgeIGN) kmTrip = 0;


 //подсчет расхода на 100км за поездку
 L100M = ((float)FuelTrip*100.00)/(float)kmTrip;
  if (L100M<0) L100M = 0;
  if (L100M>99) L100M = 99;

 // ниже цикл считает среднеарифметический расход из еепром раз в пробег, указанный в переменной kmeeprom
  if (kmTrip-kmTFT>kmeeprom) {kmTFT = kmTrip; 

 // тут считаем среднеарифметический усредненного расхода из ячеек еепром 
int summ = 0;
 for (int i = 0; i < 11; i++) summ +=  EEPROM.read(i);
 L100SR_TFT = summ / 110.00;
 if (L100SR_TFT<0) L100SR_TFT = 0;
 if (L100SR_TFT>99) L100SR_TFT = 25;}
 
 // ниже цикл считает расход топлива за пробег, указанный в переменной kmL, здесь же запись в ячейки еепром 
  if (kmTrip-km>kmL) {km=kmTrip; 
 L100SR = ((float)(fuel_last-Fuel)*100.00)/(float)kmL; // расход/100км  - обновляется раз в 10км, меняется км в int kmL = 10;
 fuel_last = Fuel;      // сохранение параметров с последнего измерениея 
  if (L100SR<0) L100SR = 0;
  if (L100SR>99) L100SR = 99;

 //расчет расстояния до заправки
 if (L100SR>0) kmREFUELING=((float)Fuel*100.0)/(float)L100SR; //если средний расход больше нуля, то расчитывать расстояние до заправки из него
 else kmREFUELING=((float)Fuel*100.00)/(float)L100SR_TFT;    //если ноль или меньше то расчитывать расстояние до заправки с усредненного расхода

 // тут записываем  L100SR последовательно в одну из 11 ячеек еепром
 //EEPROM.write (12,n_eeprom);      // ЗДЕСЬ ВНИМАТЕЛЬНО. ЗАГРУЗИТЬ ПРОШИВКУ С ЭТОЙ СТРОКОЙ ОДИН РАЗ, ПОТОМ ЗАКОМЕНТИРОВАТЬ И ЕЩЁ РАЗ ЗАГРУЗИТЬ
 byte n_eeprom = EEPROM.read (12);    // в ячейке 12 хранится № текущей ячейки для записи расхода, чтобы где остановился при выкл питания, от туда и продолжил
 EEPROM.write(n_eeprom, L100SR*10); 
 n_eeprom++; if (n_eeprom>10) n_eeprom=0;
 EEPROM.write (12,n_eeprom); 
 
 #ifdef debugTRIP
Serial.println (" I am heer:  if (kmTrip-km>kmL) {}  "); 
Serial.print (" L100SR = "); Serial.print (L100SR) ; Serial.println (" L/100km");
Serial.print (" kmREFUELING = "); Serial.print (kmREFUELING) ; Serial.println (" km");
#endif
 
 
 }
 
 #ifdef debugTRIP
Serial.print (" FuelTrip = "); Serial.print (FuelTrip); Serial.println (" L");
Serial.print (" kmTrip = "); Serial.print (kmTrip); Serial.println (" km");
Serial.print (" L100SR_TFT = "); Serial.print (L100SR_TFT); Serial.println (" L/100km");
#endif

 }}
*/


void receiveGAUGE () {


static uint32_t prevRESETheaderGAUGE=0; // таймер сброса сообщения, если данные оборвались посередине сообщения 
static bool RESETheader_timerGAUGE;     // таймер сброса сообщения, если данные оборвались посередине сообщения  

static uint32_t prevNoconnect = 0;      // таймер периодической проверки наличия связи со щитком приборов
static byte NoconnectsGAUGE = 0 ;       // счетчик неответов от щитка приборов 
static byte message_sizeGAUGE = 0;      // размер тела сообщения
static byte jGAUGE = 3;                 // инкремент
static byte nGAUGE = 3;                 // количество старт байт
static int ChecksumGAUGE =0;            // байт контрольной суммы 
static byte InitGauge = 0;              // автомат состояния инита щитка приборов 
const byte bufsizeG = 100;              // размер буфера принятого сообщения
static byte MessageRx_GAUGE [bufsizeG] = {0};   // буфер принятого сообщения
byte PIDgauge[] = {0x02,0x11,0x00,0x13}; // запрос параметоров щитка приборов



 if (K_LINE_GAUGE.available() ){
    
 // первый старт байт
 if (headerGAUGE == 0){ MessageRx_GAUGE[0]=K_LINE_GAUGE.read();  
   if ((InitGauge ==1 && MessageRx_GAUGE[0]==0x55) || (InitGauge ==2 && MessageRx_GAUGE[0]!=0xFF && MessageRx_GAUGE[0]!=0x7F)
   || (InitGauge ==3 && MessageRx_GAUGE[0]==0x23)
      )
          {headerGAUGE = 1; RESETheader_timerGAUGE = 1; prevRESETheaderGAUGE = curmillis; 
               #ifdef debugGAUGE
                  Serial.print (F("Receive GAUGE: ")); printDebugRX(MessageRx_GAUGE[0]);
               #endif               
          }
                                    }                  

 // второй старт байт
 else if (headerGAUGE == 1){ MessageRx_GAUGE[1]=K_LINE_GAUGE.read(); 
 #ifdef debugGAUGE
      printDebugRX (MessageRx_GAUGE[1]);
 #endif
      if ( (InitGauge ==1 && MessageRx_GAUGE[1]==0x52)  ||     (InitGauge ==2 && (MessageRx_GAUGE[1]==0xA0 || MessageRx_GAUGE[1]==0xF0))  
      || (InitGauge == 3 && MessageRx_GAUGE[1]==0xA1)){ headerGAUGE = 2;} 
      else {
        #ifdef debugGAUGE 
        Serial.println(F(" GAUGE Message fail address")); 
        #endif
        headerGAUGE = 0; RESETheader_timerGAUGE = 0;}} 

 // третий старт байт
 else if (headerGAUGE == 2){ 
  
  MessageRx_GAUGE[2]=K_LINE_GAUGE.read(); 
  #ifdef debugGAUGE
  printDebugRX (MessageRx_GAUGE[2]);
  #endif
  if ((InitGauge ==2 && (MessageRx_GAUGE[2]==0x48 || MessageRx_GAUGE[2]==0x55 || MessageRx_GAUGE[2]==0xAA)) || (InitGauge == 3 && MessageRx_GAUGE[2]==0x04)){ message_sizeGAUGE = MessageRx_GAUGE[0]-2; prevRESETheaderGAUGE = curmillis;
       headerGAUGE = 4;  jGAUGE=3; nGAUGE=3;
      
       if (message_sizeGAUGE > bufsizeG) message_sizeGAUGE = bufsizeG;  ChecksumGAUGE = 0;} 
  else if (InitGauge ==1 && MessageRx_GAUGE[2]==0x80) {InitGauge = 2; K_LINE_GAUGE.write(0x7F); delay (2); K_LINE_GAUGE.read();  headerGAUGE = 0; RESETheader_timerGAUGE = 0; 
             #ifdef debugGAUGE
             Serial.println ("Gauge INIT is good!"); 
             #endif
                                                      }     
  else {headerGAUGE = 0; 
        #ifdef debugGAUGE 
        Serial.println(F("GAUGE Message fail address")); 
        #endif
        RESETheader_timerGAUGE = 0;}
  
                          }  

  // пишем тело сообщения 
 else if (headerGAUGE == 4 && jGAUGE< message_sizeGAUGE+nGAUGE+1) {
 MessageRx_GAUGE[jGAUGE] = K_LINE_GAUGE.read(); prevRESETheaderGAUGE = curmillis;
 if (jGAUGE<message_sizeGAUGE+nGAUGE-1) ChecksumGAUGE+= MessageRx_GAUGE[jGAUGE]; // подсчёт КС
 
 if (jGAUGE==message_sizeGAUGE+nGAUGE) headerGAUGE = 5; 
  
 #ifdef debugGAUGE
 printDebugRX(MessageRx_GAUGE[jGAUGE]);
 #endif  
 jGAUGE++;                                             } 
 }

 // сообщение приняли, действуем
 if (headerGAUGE == 5) {  
 #ifdef debugGAUGE
 Serial.println();
 #endif  
 
  
for(byte i = 0; i<nGAUGE; i++) ChecksumGAUGE+=MessageRx_GAUGE[i]; // прибавляем к контрольной сумме старт байты
int ChecksumG =  ( ( unsigned int )MessageRx_GAUGE[message_sizeGAUGE+nGAUGE-1] << 8 ) | MessageRx_GAUGE[message_sizeGAUGE+nGAUGE]; // парсинг контрольной суммы из 2 последних байт 
 // если контрольная сумма верна: 
if ( ChecksumGAUGE == ChecksumG) 
{  NoconnectsGAUGE = 0; // сбрасываем на 0 отсутствие связи с панелью
  #ifdef debugGAUGE
  Serial.print (F("Received message is OK! Checksum is correct!"));  Serial.print (F("  ")); Serial.println (millis()); // Если КС совпала, тут чёнибудь нужное делаем
  #endif

      if (MessageRx_GAUGE[1]== 0xA0 && MessageRx_GAUGE[2]== 0x48) {
           #ifdef debugGAUGE
           Serial.println ("ID panel receive! Send request PIDGauge"); 
           #endif
           InitGauge = 3; 
           for (byte i=0; i<sizeof(PIDgauge); i++) { K_LINE_GAUGE.write (PIDgauge[i]); delay (1); K_LINE_GAUGE.read();}
                                                                  }

       if (MessageRx_GAUGE[1]== 0xF0 && (MessageRx_GAUGE[2]== 0xAA || MessageRx_GAUGE[2]== 0x55)) {
           #ifdef debugGAUGE
           Serial.println ("receive present from Gauge. I send PID to Gauge"); 
           #endif
           InitGauge = 3; 
           for (byte i=0; i<sizeof(PIDgauge); i++) { K_LINE_GAUGE.write (PIDgauge[i]); delay (1); K_LINE_GAUGE.read();}
                                                                  }

                                                                  

      if (MessageRx_GAUGE[1]== 0xA1 && MessageRx_GAUGE[2]== 0x04) {
           #ifdef debugGAUGE
           Serial.println (" receive Datastream Gauge!");
           #endif
 Fuel2 = MessageRx_GAUGE[nGAUGE + 16]/2.0; 
 if (!flagFuelIGN) {  Fuel = MessageRx_GAUGE[nGAUGE + 16]/2.0;  kmREFUELING=((float)Fuel*100.00)/(float)L100SR_TFT;} //стартовая запись литров в баке для подсчета затраченных литро
 else Fuel = MessageRx_GAUGE[nGAUGE + 17]/2.0; //для усреднения болтания в баке закоментировать эту строку, а раскоментировать ниже
            
 //для усреднения болтания топлива в баке, раскоментировать, высчитывает среднее
 /*else { FuelZamer[ZamerNumber] = MessageRxGauge[17]/2.00;
 if (ZamerNumber==9) {
 Fuel = 0 ;
 for (int i = 0; i < 10; i++) Fuel = Fuel + FuelZamer[i];
 Fuel = (float)Fuel/10.0;}
 ZamerNumber++; if (ZamerNumber>9) ZamerNumber = 0;}
*/

  kmAge = (MessageRx_GAUGE[nGAUGE + 23]+(MessageRx_GAUGE[nGAUGE + 24]*256))/10.0; //суточный пробег с панели приборов

  //бак у меня на 59 литров, а датчик показывает максимально 53 литра. для этого эта формула
  //если у вас тоже датчик имеет лимит то подправте 53 на свой лимит. 
  //если ваш датчик показывает одинаково с полным баком то закоментировать три нижние строки. 
  if (Fuel<53){
  if (!flagkmAgeIGN) { kmAgeIGN = kmAge; flagkmAgeIGN =1;}
  if (!flagFuelIGN) { FuelIGN = Fuel; fuel_last = Fuel; flagFuelIGN = 1;}}

#ifdef debugTRIP
Serial.print (" Fuel = "); Serial.print (Fuel); Serial.println (" L");
Serial.print (" kmAge = "); Serial.print (kmAge); Serial.println (" km");
#endif

           
                                                                  }
 }   

// если контрольная сумма не совпала: 
#ifdef debugGAUGE
  else Serial.println("CRC fail!!!" );
#endif
message_sizeGAUGE = 0; headerGAUGE=0; RESETheader_timerGAUGE = 0; jGAUGE=3; ChecksumGAUGE = 0;
}

// таймер сброса целостности сообщения (если данные оборвались посередине сообщения)
if (RESETheader_timerGAUGE && curmillis - prevRESETheaderGAUGE > 300) { 
  #ifdef debugGAUGE 
  Serial.println(F("Message fail timeout")); 
  #endif 
  RESETheader_timerGAUGE = 0; headerGAUGE = 0;}   

 if (curmillis - prevNoconnect > 500) {NoconnectsGAUGE ++ ; if (NoconnectsGAUGE>=8){
 #ifdef debugGAUGE 
  Serial.println (F("       Connect GAUGE failed!!! ")) ;
 #endif
  NoconnectsGAUGE = 0 ;InitGauge = 0 ; } prevNoconnect = curmillis; }
 
 InitBusGAUGE (InitGauge);
}// end receiveGAUGE


void InitBusGAUGE (byte &InitGauge) 
{
  uint32_t prevInitbusGauge = 0;   // таймер для инита щитка приборов
  
    if (InitGauge == 0){
#ifdef debugGAUGE 
  Serial.println ("Send startsession - address Gauge");
#endif   
  K_LINE_GAUGE.end();
   pinMode(TX_gauge, OUTPUT);
   digitalWrite (TX_gauge, HIGH);                                           // BUS IDLE
   InitGauge = 5; prevInitbusGauge = curmillis;
   }  
 if (InitGauge == 5 && curmillis - prevInitbusGauge>1500)  {InitGauge = 6;} // BUS IDLE
 if (InitGauge == 6)
 {    
   byte boudrate = 1000/BAUD;
   digitalWrite (TX_gauge, LOW);   delay (boudrate); // старт бит
   for (byte i=0; i<8; i++){digitalWrite (TX_gauge, bitRead(addressGUAGE, i)); delay (boudrate);} // биты тела адреса 
   digitalWrite (TX_gauge, HIGH);  delay (boudrate); // стоп бит
   K_LINE_GAUGE.begin(9600);
   InitGauge = 1; 
 }
}




#if defined debugPCM or defined debugGAUGE
void printDebugRX (const byte &inbyte) {if (inbyte<=15) Serial.print(F("0")); Serial.print (inbyte, HEX);  Serial.print (F(" "));}
#endif

#ifdef debugPCM
void printDebugRX_CSgood(const byte &n){
if (MessageRx_PCM[n]==0xC1 && MessageRx_PCM[n+1]==0x6B && MessageRx_PCM[n+2]==0x8F) {Serial.println (F("   Initialization OK!!!!")); }
 else if (MessageRx_PCM[n]==0x58 && MessageRx_PCM[n+1]==0x00) {Serial.println (F("     NO DTC  "));}
 else if (MessageRx_PCM[n]==0x58 && MessageRx_PCM[n+1] >0x00) {Serial.println (F("     DTC is found!"));} 
 else if (MessageRx_PCM[n]==0x54 && MessageRx_PCM[n+1]==0xFF && MessageRx_PCM[n+2]==0x00){Serial.println (F("     DTC CLEARED  "));}
 else if (MessageRx_PCM[n]==0x61 && MessageRx_PCM[n+1]==0x01) {Serial.println (F("     Receive PCM DATAstream"));}}
#endif                          



void Menu () {
     TouchHOME();
    if (currentPage == '0') {
     
     TouchINF1();
     TouchINF2();
     TouchCHECK(); }
    if (currentPage == '1') { 
     
     TouchINF2();
     TouchCHECK(); }
    if (currentPage == '2') { 
     
     TouchINF1();
     TouchCHECK(); }
    if (currentPage == '3') { 
     
     TouchREAD();
     TouchERASE(); }}   
 
 
  void drawHomeScreen() {
    line() ;
    //myGLCD.print(":", 290, 5);
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setTextColor(RED, BLACK); // цвет линии и текста красный
    myGLCD.drawLine(295,35,295,248); // линия вертикальная
    myGLCD.drawLine(145,35,145,178); // линия вертикальная
    myGLCD.drawLine(80,178,80,247); // линия вертикальная
    myGLCD.print("L/H", 10, 40);
    myGLCD.print("L/A", 148, 40);
    myGLCD.print("L/V", 10, 75);
    myGLCD.print("L/M", 148, 75);
    myGLCD.print("D/K", 10, 110);
    myGLCD.print("D/L", 148, 110);
    myGLCD.print("V/K", 10, 145);
    myGLCD.print("V/L", 148, 145);
    myGLCD.print("PUMP  RPM", 82, 180);
    myGLCD.print("ENGI   RPM", 82, 215);
    myGLCD.print("D/L/A", 10, 180);
    myGLCD.print("Motor C", 300, 40);
    myGLCD.print("OIL     C", 300, 75);
    myGLCD.print("FUEL   C", 300, 110);
    myGLCD.print("FUERA  C", 300, 145);
    myGLCD.print("DENTRO  C", 300, 180);
    myGLCD.print("INTAIR  C", 300, 215);
    //myGLCD.setTextColor(RED); 
    myGLCD.drawRoundRect (15, 255, 145, 310);
    myGLCD.print("INF 1", 55, 270);
    myGLCD.drawRoundRect (175, 255, 305, 310);
    myGLCD.print("INF 2", 215, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("CHECK", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 7);
    myGLCD.print("Km/h", 410, 7);
    reNew = 1;
    Watch ();
  }
 //-------------------------------------------------
   void drawscreen_one() {
    line() ;
    //myGLCD.print(":", 290, 5);
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setTextColor(RED, BLACK); // цвет линии и текста красный
    myGLCD.print("Start of Delivery   *CA:", 10, 40);
    myGLCD.print("Desir inject Start  *CA:", 10, 75);
    myGLCD.print("Actua Inject Start  *CA:", 10, 110);
    myGLCD.print("Desir Inject Quan  mg/s:", 10, 145);
    myGLCD.print("Actu Inject Quant mg/s:", 10, 180);
    myGLCD.print("MAF  mg/s:", 10, 215);
    myGLCD.print("Humedad %:", 255, 215);
    //myGLCD.setTextColor(RED);
    myGLCD.drawRoundRect (175, 255, 305, 310);
    myGLCD.print("INF 2", 215, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("CHECK", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 7);
    myGLCD.print("Km/h", 410, 7);
    reNew = 1;
    Watch ();
    }
 //-------------------------------------------------
  void drawscreen_two() {
    line() ;
    //myGLCD.print(":", 290, 5);
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setTextColor(RED, BLACK); // цвет линии и текста красный
    myGLCD.print("Boost Press       Bar:", 10, 40);
    myGLCD.print("Boost Press Com  Bar:", 10, 75);
    myGLCD.print("EGR command     mg/s:", 10, 110);
    myGLCD.print("EGR Pulse Ratio      %:", 10, 145);
    myGLCD.print("Solenoide Pulse      %:", 10, 180);
    myGLCD.print("Solenoide Boost      %:", 10, 215);
    //myGLCD.setColor(RED);
    myGLCD.drawRoundRect (15, 255, 145, 310);
    myGLCD.print("INF 1", 55, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("CHECK", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 7);
    myGLCD.print("Km/h", 410, 7);
    reNew = 1;
    Watch ();
    }
 //----------------------------------------------------------------------------
  void drawscreen_three() {
    //myGLCD.print(":", 290, 5);
    myGLCD.print("/", 115, 7);
    myGLCD.print("/", 160, 7);
    myGLCD.setTextColor(RED, BLACK); // цвет линии красный
    myGLCD.drawLine(1,35,479,35); // линия горизонтальная
    myGLCD.drawLine(1,248,479,248); // линия горизонтальная
    //myGLCD.setTextColor(RED);
    myGLCD.drawRoundRect (15, 255, 145, 310);
    myGLCD.print("ERASE", 55, 270);
    myGLCD.drawRoundRect (335, 255, 465, 310);
    myGLCD.print("READ", 365, 270);
    myGLCD.drawRoundRect (1, 1, 77, 37);
    myGLCD.print("HOME", 10, 5);
    reNew = 1;
    Watch ();
   }

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//кнопки тач . координаты и переходы
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void TouchHOME(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {if (p.x > 140 && p.x < 320 && p.y > 140 && p.y < 260 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (1, 1, 77, 37);
        currentPage = '0';     
        request = PID; RequestPeriod = 10; prevRequest = curmillis; // на PCM в этом окне посылается запрос текущих параметров
        myGLCD.clrScr();             
        drawHomeScreen();
        x = 0;
        y = 0;
        p.z = 0;}}}

void TouchINF1(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
      if (p.x > 150 && p.x < 450 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (15, 255, 145, 310);
        currentPage = '1';    
        request = PID; RequestPeriod = 10; prevRequest = curmillis; // на PCM в этом окне посылается запрос текущих параметров       
        myGLCD.clrScr();             
        drawscreen_one();
        x = 0;
        y = 0;
        p.z = 0;}}}
    
void TouchINF2(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
    if (p.x > 450 && p.x < 680 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (175, 255, 305, 310);
        currentPage = '2';     
        request = PID; RequestPeriod = 600; prevRequest = curmillis; // на PCM в этом окне посылается запрос текущих параметров      
        myGLCD.clrScr();             
        drawscreen_two();
        x = 0;
        y = 0;
        p.z = 0;}}}

void TouchCHECK(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
if (p.x > 690 && p.x < 950 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (335, 255, 465, 310);
        currentPage = '3';  
  //     request = DTCREAD; RequestPeriod = 10; prevRequest = curmillis; // на PCM в этом окне посылается запрос чтения ошибок  
        myGLCD.clrScr();             
        drawscreen_three();
        x = 0;
        y = 0;
        p.z = 0;}}}

void TouchREAD(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
if (p.x > 690 && p.x < 950 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      { myGLCD.drawRoundRect (335, 255, 465, 310);
        request = DTCREAD; RequestPeriod = 300; prevRequest = curmillis; // на PCM при нажатии этой кнопки посылается запрос чтения ошибок  
        x = 0;
        y = 0;
        p.z = 0;}}}

void TouchERASE(){
TSPoint p = ts.getPoint();
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
if (p.z > 10 && p.z < 1000)
    {
if (p.x > 150 && p.x < 450 && p.y > 770 && p.y < 890 && p.z > MINPRESSURE && p.z < MAXPRESSURE)
      {myGLCD.drawRoundRect (15, 255, 145, 310);
       request = DTCERASE; RequestPeriod = 300;  prevRequest = curmillis; // на PCM при нажатии этой кнопки посылается запрос удаления ошибок
       myGLCD.clrScr();
       drawscreen_three();
       myGLCD.print("DTC BORRADO", 180, 145);
       
        x = 0;
        y = 0;
        p.z = 0;}}}
 ////////////////////////////////////////////////////////////////////////////////////////
 //прорисовка линий
 ///////////////////////////////////////////////////////////////////////////////////////
 void line() {
    //myGLCD.setTextColor(RED); // цвет линии красный
    myGLCD.drawLine(1,35,479,35); // линия горизонтальная
    myGLCD.drawLine(1,73,479,73); // линия горизонтальная
    myGLCD.drawLine(1,108,479,108); // линия горизонтальная
    myGLCD.drawLine(1,143,479,143); // линия горизонтальная
    myGLCD.drawLine(1,178,479,178); // линия горизонтальная
    myGLCD.drawLine(1,212,479,212); // линия горизонтальная
    myGLCD.drawLine(1,248,479,248); // линия горизонтальная
             }


void Watch (){
   DateTime now = rtc.now();
   int minut = now.minute(); 
   int hour = now.hour();
   int mon = now.month();
   int date = now.day();
   int Year = now.year();
 static  int minut_last; 
 static  int hour_last;
 static  int mon_last;
 static  int date_last;
 static  int Year_last;
 myGLCD.setTextColor(WHITE, BLACK); //белый цвет цифры

 if (date != date_last || reNew){ myGLCD.printNumI(date, 85, 7, 2, '0'); date_last = date; }

 if (mon!=mon_last || reNew){myGLCD.printNumI(mon, 130, 7, 2, '0'); mon_last = mon; }  
 
 if (Year!=Year_last || reNew) {  myGLCD.printNumI(Year, 175, 7); Year_last = Year; }
   
 if (hour!=hour_last || reNew){ myGLCD.printNumI(hour, 255, 7, 2, '0'); hour_last = hour; } 
   
 if (minut!=minut_last || reNew ){ myGLCD.printNumI(minut, 300, 7, 2, '0'); minut_last = minut; }
   } 

void Temperature () { 

     static boolean p=0; // флаг работы: запрос температуры или её чтение
p=!p;
if (p) {ds.reset();      // сброс шины
        ds.write(0xCC);  // обращение ко всем датчикам
        ds.write(0x44);  // начать преобразование (без паразитного питания)  
       }
else   {
 
        int Temper_= 20;  byte buff[9];
        ds.reset();
        ds.select(DSaddress);    
        ds.write(0xBE); // Read Scratchpad (чтение регистров)  
        for (byte j = 0; j<9; j++) buff[j]= ds.read(); //читаем все 9 байт от датчика 
        ds.reset();
        if (OneWire::crc8(buff, 8) == buff[8]){        // если контрольная сумма совпадает
        Temper_ =  buff[0] | (buff[1]<<8);             // читаем температуру из первых двух байт (остальные были нужны для проверки CRC)
        Temper_ = Temper_ / 16;
        if  (Temper_ < 150 && Temper_ > -50 && Temper_ !=85 && Temper_!=-127)  IntTemp =  Temper_;
                 
                                              }
                                                      
}
   }

Макс эти строки делают зависимость от полного суточного пробега 2000?

if (kmAge>km_prev) kmTrip_refuel = kmAge - km_prev;
 if (kmAge<km_prev)  kmTrip_refuel = 2000 - (km_prev - kmAge);
 if (kmAge==km_prev) kmTrip_refuel = 0;
Sergei H.
Offline
Зарегистрирован: 17.11.2018

Komandir .Помогите ещё раз. В строке 961 я поставил 4195 ,т.е стоимость 41,95 р. за литр. в строке 4073 поставил 2:1. Поставил на автомобиль свой БК. Всё нормально ,всё что нужно показывает,только стоимость поездки делит на 10. Литр потратил должен показывать 41,95, а он выдаёт Р4,19 .Где в коде изменить ,чтобы показывало правильно. Или просто в строке 961 поставить 41950?

viki13viki
Offline
Зарегистрирован: 14.11.2016

Сергей попробуй записать  41950 или попробуй 4195*10 или 41,95*1000