Телеметрия для гонок. Опрос ЭБУ Январь 5.1. Передача данных на Racechrono

Всем привет. Может быть кому-то будет интересна эта тема.
Сделал вот такой проект. Arduino Mega опрашивает блок управления двигателем, получает данные с датчиков и передает эти данные на приборную панель, а также на телефон, где установлена программа Racechrono.

За библиотеку по работе с энкодерами спасибо Alexgyver.



#include <GyverEncoder.h> //Подключение библиотки для обработки сигналов энкодера
#include <ModbusRtu.h> //Подключение библиотки Modbus
uint16_t audata_Panel[50]; //Массив данных для обмена по Modbus. Панель - Master, Arduino - Slave
Modbus slave(1,Serial3,0); 
Encoder enc1(2, 3);
unsigned long last_time1; //переменная для таймера
unsigned long last_time2; //переменная для таймера
unsigned long last_time3; //переменная для таймера
unsigned long last_time4; //переменная для таймера
unsigned long last_time5; //переменная для таймера
unsigned long last_time6; //переменная для таймера
unsigned long last_time7; //переменная для таймера
boolean xInit1;           //Переменная для триггера таймера
boolean xInit2;           //Переменная для триггера таймера
boolean xInit3;           //Переменная для триггера таймера
boolean xInit4;           //Переменная для триггера таймера
boolean xTrig1;           //Триггер открытия порта на скорости 10400
boolean xTrig2;           //Триггер открытия порта на скорости 38400
int iCount1;               //Переменная для счетчика тайммаутов
boolean xBuffer_Empty;    //Флаг пустого буббера com-порта
boolean xTON_timeout; //Переменная срабатывания таймера для формирования ошибки связи с ЭБУ
boolean xTON_read_Error; //Переменная срабатывания таймера для считывания ошибок с ЭБУ
boolean xTON_racechrono; //Переменная срабатывания таймера для отаравки сообщения Racechrono  
boolean xFlag_Communication; //Флаг Сессия обмена данными с ЭБУ начата
boolean xFlag_38400; //Флаг изменение скорости на 38400 произведено
boolean xFlag_Read_Done; //Флаг Данные считаны
boolean xFlag_Read_Error; //Флаг Ошибка получения данных
boolean xFlag_Write_Done; //Флаг Данные отправлены
boolean xSB_Sbros_Error;  //Кнопка Сброса аварий
boolean xSB_Read_Error; //Кнопка чтения аварий
boolean xSB_Sbros_Angle; //Кнопка обнуления угла поворота руля
boolean xMode_Read_AI; //Режим чтения аналоговых входов
boolean xMode_Parameters; //Режим чтения всех параметров ЭБУ
boolean xAnalog_Read; //Просмотр значений аналоговых входов ЭБУ
int iState; //Шаг действий
int iType_parsing; //Тип парсинга
int iN_bytes; //Количество считанный байт из буффера COM-порта
int iN_w_bytes; //Количество отправленых байт в ЭБУ
int iN_r_bytes; //Количество ожидаемых байт в ответе от ЭБУ
byte bCS_read;   //Контрольная сумма данных от ЭБУ
byte abStart [5] = {0x81,0x10,0xF1,0x81,0x3}; //Команда для отправки Установить связь
byte ab38400 [7] = {0x83,0x10,0xF1,0x10,0x81,0x26,0x3B}; //Команда для отправки изменить скорость на 38400
byte abRead_Data [6] = {0x82,0x10,0xF1,0x21,0x1,0xA5}; //Команда для отправки Запрос текущих данных
byte abRead_Error [8] = {0x84,0x10,0xF1,0x18,0x0,0x0,0x0,0x9D}; //Команда для отправки Запрос ошибок
byte abSbros_Error [7] = {0x83,0x10,0xF1,0x14,0x0,0x0,0x98}; //Команда на сброс ошибок
byte ab_Analog [6] = {0x82,0x10,0xF1,0x21,0x3,0xA7}; //Команда на запрос значений АЦП
byte abRead_Buffer_Eho [50]; //Буффер для копирования данных с буффера COM-порта вместе с эхом
byte abRead_Buffer [50]; //Буффер для копирования данных с буффера COM-порта
byte abRead_E_Eprom [25]; //Буффер для копирования ошибок из памяти ЭБУ
int iSaiz_Buffer;
uint16_t count=0;    //Счетчик сообщений для RaceChrono
float rVoltage;
int iPE_Break;
float rPE_Oil;
float rPE_Fuel;
float rAlf;
int iCount_Encoder;
int iAngle;
int iAI0;
int iAI1;
int iAI2;
int iAI3;
unsigned long Time_Alarm_TE; //Переменная для таймера задержки авариии по температуре
boolean xInit_Alarm_TE;      //Переменная инициализации переменной для таймера 
unsigned long Time_Alarm_Oil; //Переменная для таймера задержки авариии по давлению масла
boolean xInit_Alarm_Oil;      //Переменная инициализации переменной для таймера 
unsigned long Time_Alarm_Fuel; //Переменная для таймера задержки авариии по давлению топлива
boolean xInit_Alarm_Fuel;      //Переменная инициализации переменной для таймера 
unsigned long Time_Alarm_Voltage; //Переменная для таймера задержки авариии по напряжению
boolean xInit_Alarm_Voltage;      //Переменная инициализации переменной для таймера 
unsigned long Time_Alarm_Alf; //Переменная для таймера задержки авариии по соотношению
boolean xInit_Alarm_Alf;      //Переменная инициализации переменной для таймера 

void setup() {
  Serial.begin(19200);   //Витруальный порт
  Serial2.begin(9600);  //Порт2. Блютуз модуль для racechrono
  Serial3.begin(57600);  //Порт3. Панель оператора
  slave.start();         //Включение Modbus Slave
  attachInterrupt(1, isrCLK, CHANGE);    // прерывание на 2 пине! CLK у энка
  attachInterrupt(0, isrDT, CHANGE);    // прерывание на 3 пине! DT у энка
}

void isrCLK() {
  enc1.tick();  // отработка в прерывании
  if (enc1.isRight()) iCount_Encoder--;       // если был поворот направо, увеличиваем на 1
  if (enc1.isLeft()) iCount_Encoder++;        // если был поворот налево, уменьшаем на 1
}
void isrDT() {
  enc1.tick();  // отработка в прерывании
  if (enc1.isRight()) iCount_Encoder--;       // если был поворот направо, увеличиваем на 1
  if (enc1.isLeft()) iCount_Encoder++;        // если был поворот налево, уменьшаем на 1
}

//Функция подсчета контрольной суммы для всех байт переменной STRING. Возвращает значение в string hex
String checksum(String s) 
{
  uint8_t cs = 0x00;
  for (unsigned int i = 1; i < s.length() - 1; i++) cs = cs ^ s.charAt(i); //lenght - возвращает длину строки, charAt - возвращает символ по указанному адресу, ^ - оператор побитового сложения XOR
  String hex = String(cs, HEX);                                            //Преобразует конрольную сумму в string hex
  hex.toUpperCase();                                                       //Делает символы заглавные
  return String((cs < 0x10 ? "0" : "") + hex);                             //Условие if. Если cs<0x10, то вывести 0, если нет, то вывести пробел
}


void loop() {

//Обработка комманд от панели оператора
xMode_Read_AI = bitRead(audata_Panel[40], 0);    //Режим чтения АЦП
xMode_Parameters = bitRead(audata_Panel[40], 1); //Режим чтения всех параметров ЭБУ
xSB_Sbros_Angle = bitRead(audata_Panel[40], 2);  //Кнопка обнуления угла поворота руля
boolean xInitSB1;
boolean xInitSB2;
if (bitRead(audata_Panel[40], 3) && !xInitSB1) { //Кнопка чтения ошибок. Обработка переднего фронта
  xSB_Read_Error=1; xInitSB1=1;
} 
if (!bitRead(audata_Panel[40], 3)) xInitSB1=0;

if (bitRead(audata_Panel[40], 4) && !xInitSB2) { //Кнопка сброса ошибок. Обработка переднего фронта
  xSB_Sbros_Error=1; xInitSB2=1;
} else {
  xSB_Sbros_Error=0;
}
if (!bitRead(audata_Panel[40], 4)) xInitSB2=0;


//Таймер тайммаута связи с ЭБУ. Когда таймер сработает, произойдет повторная отправка комманды на установление связи с ЭБУ
if (!xFlag_Communication || xFlag_38400){                                                  
  if (!xInit1) {
     last_time1 = millis();
     xInit1=1;
  } 
  if (millis() - last_time1>3000) {
      last_time1 = millis();
      iState=0;
      xFlag_Communication=0;
      xTrig1=0;
      xTrig2=0;
      xFlag_38400=0;
      xFlag_Read_Done=0;
      xFlag_Read_Error=0;
      Serial.println("Timeout");
      iCount1 = iCount1 +1;
  }   
} else {
  xInit1=0;
  }                                                                              

//Счетчик неудачных подключений.
//Возможно ЭБУ уже находится в режиме опроса и поэтому не отвечает на комманду установления связи.
//При срабатывании счетчика произойдет попытка сразу перейти к опросу. Если не получится, снова произойдет возвратат к установлению связи.
if (iCount1 == 2) {
  iCount1=0;                      
  xFlag_Communication=1;
  iState=3;
  xTrig1=0;
  xTrig2=0;
  xFlag_38400=1;
  xFlag_Read_Done=0;
  xFlag_Read_Error=0;
  Serial.println("Timeout2");
}

//Таймер таймаута ответа от ЭБУ. Если ЭБУ не отвечает, возможно ему требуется отправка комманды на установление связи.
if (xFlag_Communication && !xFlag_Read_Done){                                
  if (!xInit2) {
     last_time1 = millis();
     xInit2=1;
   } 
  if (millis() - last_time1>3000) {
      last_time2 = millis();
      iState=0;
      xFlag_Communication=0;
      Serial.println("Timeout");
      xTrig1=0;
      xTrig2=0;
      xFlag_38400=0;
      xFlag_Read_Done=0;
      xFlag_Read_Error=0;
  }   
} else {
  xInit2=0;
  }                  

//Таймер таймаута ответа от ЭБУ. Если ЭБУ не отвечает, возможно ему требуется отправка комманды на установление связи.
if (xFlag_Communication && !xFlag_Read_Done && xFlag_38400){                                
  if (!xInit3) {
     last_time3 = millis();
     xInit3=1;
   } 
  if (millis() - last_time3>1000) {
      last_time3 = millis();
      iState=3;
      xTrig1=0;
      xTrig2=0;
      xFlag_38400=1;
      Serial.println("TimeoutRead");
  } 
} else {
xInit3=0;
}        


if (!xFlag_38400 && !xTrig1) {
Serial1.begin(10400);              //Порт1. ЭБУ двигателя. Установка скорости 10400 
xTrig1=1;
Serial.println("Port1_10400");
}
if (xFlag_38400 && !xTrig2) {
Serial1.begin(38400);              //Порт1. ЭБУ двигателя. Установка скорости 38400   
xTrig2=1;
Serial.println("Port1_38400");
}



if ((!xFlag_Communication) && (iState!=2)) {                                                   //Условие для включения шага 1. Отправка комманды на установление связи с ЭБУ.
  iState=1;
}
if (xFlag_Communication && !xFlag_38400 && xFlag_Read_Done) {                                  //Условие для включения шага 7. Отправка комманды на изменение скорости на 38400
  iState=7;  
}
if (xFlag_Communication && (xFlag_Read_Done || xFlag_Read_Error) && xFlag_38400) {             //Условие для включения шага 3. Отправка комманды на запрос текущих данных
  iState=3;
}
if (xFlag_Communication && xFlag_Read_Done && xSB_Read_Error && xFlag_38400) {                 //Условие для включения шага 4. Отправка комманды на запрос ошибок ЭБУ
  iState=4;
}
if (xFlag_Communication && xFlag_Read_Done && xSB_Sbros_Error && xFlag_38400) {                //Условие для включения шага 5. Сброс ошибок
  iState=5;
}
if (xFlag_Communication && xFlag_Read_Done && xMode_Read_AI && xFlag_38400) {                  //Условие для включения шага 6. Просмотр значений АЦП ЭБУ
  iState=6;
}


//Serial.print("iState "); Serial.println(iState);

switch (iState) {


case 1: Serial1.write(abStart,5);                                         //Шаг 1. Отправка комманды. Установление связи с ЭБУ.
        iState=2;
        iType_parsing=1;
        iN_w_bytes=5;                                                     //Количество отправленных байт           
        iN_r_bytes=7;                                                     //Ожидаемое количество байт в ответе
        iN_bytes=0;
        xFlag_Read_Done=0;
        xFlag_Read_Error=0;
        Serial.println("ZaprosCommunication");
break;


case 2: if (Serial1.available()>0) {                                      //Шаг 2. Чтение данных.
           xBuffer_Empty=0;
           for (int i=0; i<Serial1.available(); i++) {
             int iN = iN_bytes;
             abRead_Buffer_Eho[iN] = Serial1.read();
             iN_bytes = iN_bytes + 1;
             //Serial.println(abRead_Buffer_Eho[iN], HEX);
           }
         } else {
           xBuffer_Empty=1;
         }
         
         if ((iType_parsing==4) && (iN_bytes>=iN_w_bytes)) {             //Формирование количества байт данных для режима чтения ошибок. Переменное значение 
           boolean xVar0=bit_is_set(abRead_Buffer_Eho[iN_w_bytes],0);    //Определяется первыми шести битами первого байта. +3 байта заголовка, +1 байт контрольной суммы
           boolean xVar1=bit_is_set(abRead_Buffer_Eho[iN_w_bytes],1);
           boolean xVar2=bit_is_set(abRead_Buffer_Eho[iN_w_bytes],2);
           boolean xVar3=bit_is_set(abRead_Buffer_Eho[iN_w_bytes],3);
           boolean xVar4=bit_is_set(abRead_Buffer_Eho[iN_w_bytes],4);
           boolean xVar5=bit_is_set(abRead_Buffer_Eho[iN_w_bytes],5); 
           bitWrite(iN_r_bytes,0,xVar0);
           bitWrite(iN_r_bytes,1,xVar1);
           bitWrite(iN_r_bytes,2,xVar2);
           bitWrite(iN_r_bytes,3,xVar3);
           bitWrite(iN_r_bytes,4,xVar4);
           bitWrite(iN_r_bytes,5,xVar5);
           iN_r_bytes = iN_r_bytes+4; 
         } 
break;        

case 3: Serial1.write(abRead_Data,6);                     //Шаг 3. Отправка комманды. Запрос текущих данных.
        iState=2;
        iType_parsing=3;
        iN_w_bytes=6;                                     //Количество отправленных байт           
        iN_r_bytes=41;                                    //Ожидаемое количество байт в ответе
        iN_bytes=0;
        xFlag_Read_Done=0;
        xFlag_Read_Error=0;
        //Serial.println("ZaprosData");
break;

case 4: Serial1.write(abRead_Error,8);                    //Шаг 4. Отправка комманды. Запрос ошибок.
        iState=2;
        iType_parsing=4;
        iN_w_bytes=8;                                     //Количество отправленных байт           
        iN_r_bytes=0;                                     //Ожидаемое количество байт в ответе
        xFlag_Read_Done=0;
        xFlag_Read_Error=0;
        xSB_Read_Error;
        Serial.println("ZaprosError");
break;

case 5: Serial1.write(abSbros_Error,7);                   //Шаг 5. Отправка комманды. Сброс ошибок.
        iState=2;
        iType_parsing=5;
        iN_w_bytes=7;                                     //Количество отправленных байт           
        iN_r_bytes=7;                                     //Ожидаемое количество байт в ответе
        xFlag_Read_Done=0;
        xFlag_Read_Error=0;
        xSB_Sbros_Error=0;
        Serial.println("SbrosError");
break;

case 6: Serial1.write(ab_Analog,6);                        //Шаг 6. Отправка комманды. Запрос значений АЦП
        iState=2;
        iType_parsing=6;
        iN_w_bytes=6;
        iN_r_bytes=17;                                     //Количество отправленных байт           
        xFlag_Read_Done=0;
        xFlag_Read_Error=0;
break;

case 7: Serial1.write(ab38400,7);                          //Шаг 7. Отправка комманды. Изменить скорость на 38400
        iState=2;
        iType_parsing=7;
        iN_w_bytes=7;
        iN_r_bytes=6;                                      //Количество отправленных байт           
        xFlag_Read_Done=0;
        xFlag_Read_Error=0;
        xFlag_Read_Done=0;
        xFlag_Read_Error=0;
        xTrig2=0;
        Serial.println("ZaprosSpeed38400");
break;
}




//Парсинг данных
if ((iN_bytes>=(iN_w_bytes+iN_r_bytes)) && (xBuffer_Empty)){      //Если количество ожидаемых и считанных байт совпало, то начинается парсинг
   

    for (int i=0; i<iN_r_bytes; i++) {                            //Отсеивание байт эха                             
        abRead_Buffer[i] = abRead_Buffer_Eho[i+iN_w_bytes];       //Формирование буффера данных без эха

         //Serial.print(abRead_Buffer[i], HEX);
         //Serial.print(" ");

           }
           

    bCS_read = 0;                                                //Предварителное обнуление контрольной суммы полученного сообщения
    
    //Serial.println(" ");                                                   

    switch (iType_parsing) {

    //Определение установления связи с ЭБУ
    case 1: for (int i=0; i<(iN_r_bytes-1); i++) {              //Подсчет контрольной суммы полученного сообщения не включая последний байт
             bCS_read = bCS_read + abRead_Buffer[i];                
             }
            if (bCS_read == abRead_Buffer[iN_r_bytes-1]) {      //Если контрольная сумма совпала, то считаем, что связь с ЭБУ установлена
              xFlag_Read_Done=1;
              xFlag_Communication=1;
              xFlag_Read_Error=0;
              iN_bytes=0;
              Serial.println("Connect Done");                   
             } else {
                xFlag_Read_Done=0;
                xFlag_Communication=0;
                xFlag_Read_Error=1;
                iN_bytes=0;
                Serial.println("Connect Error");
             }
    break;

     //Формирование текущих параметров от ЭБУ
     case 3: for (int i=0; i<(iN_r_bytes-1); i++) {               //Подсчет контрольной суммы полученного сообщения не включая последний байт
             bCS_read = bCS_read + abRead_Buffer[i];                
             }
             
             if ((bCS_read == abRead_Buffer[iN_r_bytes-1]) && (abRead_Buffer[4]==0x61)) { //Если контрольная сумма совпала, а так же 4-й байт данных соответствует положительному ответу 0х61, то считаем, что данные считаны верно
             xFlag_Read_Done=1;
             xFlag_Read_Error=0;
             iN_bytes=0;
             //Serial.println("ReadDataDone");

             //Далее следует сам парсинг текущих данных. Прибавить 3 к номеру бита по таблице
            
            //Параметры, считываемые непрерывно и передваемые на панель и рейсхроно
            rVoltage = 5.2 + float(abRead_Buffer[24])*0.05;                        //напряжение для рейсхроно в float
            audata_Panel[0] = abRead_Buffer[8];                                    //Слово режима работы 1
            audata_Panel[1] = abRead_Buffer[9];                                    //Слово режима работы 2
            audata_Panel[2] = abRead_Buffer[10];                                   //Слово флагов текущих неисправностей 1
            audata_Panel[3] = abRead_Buffer[11];                                   //Слово флагов текущих неисправностей 2
            audata_Panel[4] = abRead_Buffer[12];                                   //Слово флагов текущих неисправностей 3
            audata_Panel[5] = abRead_Buffer[13];                                   //Слово флагов текущих неисправностей 4
            audata_Panel[6] = uint16_t(abRead_Buffer[14]-40);                      //Т охлаждающей жидкости
            audata_Panel[8] = uint16_t(abRead_Buffer[16]);                         //Положение дросселя
            audata_Panel[9] = uint16_t(abRead_Buffer[17]*40);                      //Обороты двигателя
            audata_Panel[14] = uint16_t(abRead_Buffer[24]*5+520);                  //Напряжение бортсети *100
            //Параметры, считываемые в режиме просмотра всех параметров ЭБУ и передаваемые на панель
               if (xMode_Parameters) {
                   Serial.println("Mode Parameters");
                   audata_Panel[7] = uint16_t(((abRead_Buffer[15]*100+128)/256)*14.7);    //Соотношение воздух/топливо x100
                   //abRead_Buffer[18]                                                    //обороты на холостом ходу. Точнее, но показвают максимум 2550 об/мин
                   audata_Panel[10] = uint16_t(abRead_Buffer[19]);                         //Желаемое положение регулятора холостого хода                
                   audata_Panel[11] = uint16_t(abRead_Buffer[20]);                         //Текущее положения регулятора холостого хода
                   audata_Panel[12] = uint16_t((abRead_Buffer[21]*100+128)/256);           //Коэффициент коррекции времени впрыска *100
                   audata_Panel[13] = uint16_t(abRead_Buffer[22]*10/2);                    //Угол опережения зажигания *10
                   //abRead_Buffer[23]                                                     //скорость автомобиля
                   audata_Panel[15] = uint16_t(abRead_Buffer[25]*10);                      //Желаемые обороты холостого хода
                   //Параметры, состоящие из двух байт. Соединяем два байта. Сдвигаем старший байт на 8 бит и через или прибавляем младший байт
                   audata_Panel[16] = abRead_Buffer[26] | (abRead_Buffer[27]<<8); audata_Panel[16] = audata_Panel[16]*125;    //Длительность импульса впрыска *1000 мсек
                   audata_Panel[17] = abRead_Buffer[28] | (abRead_Buffer[29]<<8);                                             //Массовый расход воздуха х10 кг/час
                   audata_Panel[18] = abRead_Buffer[30] | (abRead_Buffer[31]<<8); audata_Panel[18] = audata_Panel[18]*10/6;   //Цикловой расход воздуха х10 мг/такт
                   audata_Panel[19] = abRead_Buffer[32] | (abRead_Buffer[33]<<8); audata_Panel[19] = audata_Panel[19]*2;      //Часовой расход топлива х100 л/час
                   audata_Panel[20] = abRead_Buffer[34] | (abRead_Buffer[35]<<8); audata_Panel[20] = audata_Panel[20]*125;    //Путевой расход топлива х1000 л/100 км
               }

            //Serial.print("Voltage "); Serial.println(rVoltage, 1); Serial.println(" ");

             } else {
                xFlag_Read_Done=0;
                xFlag_Read_Error=1;
                iN_bytes=0;
                rVoltage = 0;
                audata_Panel[0] = 0; audata_Panel[1] = 0; audata_Panel[2] = 0; audata_Panel[3] = 0; audata_Panel[4] = 0; audata_Panel[5] = 0;
                audata_Panel[6] = 0; audata_Panel[7] = 0; audata_Panel[8] = 0; audata_Panel[9] = 0; audata_Panel[10] = 0; audata_Panel[11] = 0;
                audata_Panel[12] =0; audata_Panel[13] = 0; audata_Panel[14] = 0; audata_Panel[15] = 0; audata_Panel[16] = 0; audata_Panel[17] = 0;
                audata_Panel[18] = 0; audata_Panel[19] = 0; audata_Panel[20] = 0;
                Serial.println("Read Data Error");
             }

     break;

     case 4: for (int i=0; i<(iN_r_bytes-1); i++) {                      //Подсчет контрольной суммы полученного сообщения не включая последний байт
             bCS_read = bCS_read + abRead_Buffer[i];                
             }
             //Serial.print("CS ");
             //Serial.println(bCS_read, HEX);

             if ((bCS_read == abRead_Buffer[iN_r_bytes-1]) && (abRead_Buffer[3]==0x58)) {    //Если контрольная сумма совпала, а так же 3-й байт данных соответствует положительному ответу 0х58, то считаем, что данные считаны верно
             xFlag_Read_Done=1;
             xFlag_Read_Error=0;
             iN_bytes=0;
             Serial.println("ReadErrorDone");
             for ( int i=4; i<(iN_r_bytes-1); i++) {
                abRead_E_Eprom[i-4]=abRead_Buffer[i];
             }
             } else {
                xFlag_Read_Done=0;
                xFlag_Read_Error=1;
                iN_bytes=0;
                Serial.println("ReadErrorError"); 
             }
             Serial.print("N_Error "); Serial.println(abRead_E_Eprom[0], HEX); 
            xSB_Read_Error=0;
            //Передача кодов ошибок на панель
            audata_Panel[27] = abRead_E_Eprom[2] | (abRead_E_Eprom[1]<<8);   //Код ошибки №1
            audata_Panel[28] = abRead_E_Eprom[5] | (abRead_E_Eprom[4]<<8);   //Код ошибки №2
            audata_Panel[29] = abRead_E_Eprom[8] | (abRead_E_Eprom[7]<<8);   //Код ошибки №3
            audata_Panel[30] = abRead_E_Eprom[11] | (abRead_E_Eprom[10]<<8); //Код ошибки №4
            audata_Panel[31] = abRead_E_Eprom[14] | (abRead_E_Eprom[13]<<8); //Код ошибки №5
            audata_Panel[32] = abRead_E_Eprom[17] | (abRead_E_Eprom[16]<<8); //Код ошибки №6
            audata_Panel[33] = abRead_E_Eprom[20] | (abRead_E_Eprom[19]<<8); //Код ошибки №7
            audata_Panel[34] = abRead_E_Eprom[23] | (abRead_E_Eprom[22]<<8); //Код ошибки №8
            //Serial.print("  Error_1 "); Serial.print(audata_Panel[27], HEX);
            //Serial.println(" "); Serial.println(" ");
    break;

    case 5: for (int i=0; i<(iN_r_bytes-1); i++) {                      //Подсчет контрольной суммы полученного сообщения не включая последний байт
             bCS_read = bCS_read + abRead_Buffer[i];                
             }
             //Serial.print("CS ");
             //Serial.println(bCS_read, HEX);

             if (bCS_read == abRead_Buffer[iN_r_bytes-1]) {    //Если контрольная сумма совпала, то считаем, что ошибки сброшены
               xFlag_Read_Done=1;
               xFlag_Read_Error=0;
              iN_bytes=0;
              Serial.println("Sbros_Error_Done");
             } else {
                xFlag_Read_Done=0;
                xFlag_Read_Error=1;
                iN_bytes=0;
                Serial.println("Sbros_Error_False"); 
             }
             xSB_Sbros_Error=0;
             xSB_Read_Error=1;
    break;       

    case 6: for (int i=0; i<(iN_r_bytes-1); i++) {
             bCS_read = bCS_read + abRead_Buffer[i];
            }
            //Serial.print("CS ");
            //Serial.println(bCS_read, HEX);  

            if (bCS_read == abRead_Buffer[iN_r_bytes-1]) {    //Если контрольная сумма совпала, то считаем, что показания АЦП прочитаны
              xFlag_Read_Done=1;
              xFlag_Read_Error=0;
              iN_bytes=0;
              Serial.println("Read_AI_Done");
              audata_Panel[21] = abRead_Buffer[6]*100/256*5;    //x100В АЦП канала детонации
              audata_Panel[22] = abRead_Buffer[7]*100/256*5;    //x100В АЦП датчика температуры ОЖ
              audata_Panel[23] = abRead_Buffer[8]*100/256*5;    //x100В АЦП датчика расхода воздуха
              audata_Panel[24] = abRead_Buffer[9]*29*5/256;     //x100В АЦП напряжения бортсети
              audata_Panel[25] = abRead_Buffer[10]*100/256*5;   //x100В АЦП канала датчика кислорода
              audata_Panel[26] = abRead_Buffer[11]*100/256*5;   //x100В АЦП канала датчика положения дросселя
              //Serial.print("AI_1 "); Serial.print(audata_Panel[21]);
              //Serial.print("  AI_2 "); Serial.print(audata_Panel[22]);
              //Serial.print("  AI_3 "); Serial.print(audata_Panel[23]);
              //Serial.print("  AI_4 "); Serial.print(audata_Panel[24]);
              //Serial.print("  AI_5 "); Serial.print(audata_Panel[25]);
              //Serial.print("  AI_6 "); Serial.println(audata_Panel[26]); Serial.println(" ");
             } else {
                xFlag_Read_Done=0;
                xFlag_Read_Error=1;
                iN_bytes=0;
                Serial.println("Read_AI_False");
                audata_Panel[21] = 0;                         
                audata_Panel[22] = 0;                         
                audata_Panel[23] = 0;                           
                audata_Panel[24] = 0;                       
                audata_Panel[25] = 0;                          
                audata_Panel[26] = 0;                          
             }

    break;       

    case 7: for (int i=0; i<(iN_r_bytes-1); i++) {
             bCS_read = bCS_read + abRead_Buffer[i];
            }
            //Serial.print("CS ");
            //Serial.println(bCS_read, HEX);  

            if (bCS_read == abRead_Buffer[iN_r_bytes-1]) {    //Если контрольная сумма совпала, то считаем, что скорость изменили
              xFlag_Read_Done=1;
              xFlag_Read_Error=0;
              xFlag_38400=1;
              iN_bytes=0;
              Serial.println("Speed38400Done");
              } else {
                xFlag_Read_Done=0;
                xFlag_Read_Error=1;
                iN_bytes=0;
                xFlag_38400=0;
                Serial.println("Speed38400False");
              }
     } //Окончание switch

}   //Окончание условия if


//Обработка аналоговых входов


iAI0 = map(analogRead(0), 0, 1023, 0, 500); //Аналоговый вход №0, Вольт х100
iAI1 = map(analogRead(1), 0, 1023, 0, 500); //Аналоговый вход №0, Вольт х100
iAI2 = map(analogRead(2), 0, 1023, 0, 500); //Аналоговый вход №0, Вольт х100
iAI3 = map(analogRead(3), 0, 1023, 0, 500); //Аналоговый вход №0, Вольт х100

//Передача значений напряжений аналоговых входов на панель
audata_Panel[42] = iAI0;
audata_Panel[43] = iAI1;
audata_Panel[44] = iAI2;
audata_Panel[45] = iAI3;
//Масштабирование аналоговых входов
iPE_Break = map(iAI0, 50, 120, 0, 100);
rPE_Oil = (float(map(iAI1, 100, 500, 0, 100)))/10;
rPE_Fuel = (float(map(iAI2, 50, 500, 0, 60)))/10;
rAlf = float((map(iAI3, 0, 500, 735, 2239)))/100;


//Обработка энкодера
enc1.tick(); // обязательная функция отработки. Должна постоянно опрашиваться
if (xSB_Sbros_Angle) iCount_Encoder=0;      //Обнуление угла поворота руля по нажатию кнопки
iAngle = iCount_Encoder*10/15;


//Преобразование аналоговых параметров для панели
audata_Panel[35] = iPE_Break;              //Давление в торомозной системе в процентах
audata_Panel[36] = uint16_t(rPE_Oil*10);   //Давление масла
audata_Panel[37] = uint16_t(rPE_Fuel*10);  //Давление топлива
audata_Panel[38] = iAngle;                 //Угол поворота руля
audata_Panel[46] = uint16_t(rAlf*10);      //Соотношение воздух/топливо



//Формирование аварийных сообщений

//Температура ОЖ высокая
if (audata_Panel[6]>106) {
  if (!xInit_Alarm_TE){
    Time_Alarm_TE= millis();
    xInit_Alarm_TE=1;
  }
  if (millis() - Time_Alarm_TE>2000) {
    bitWrite(audata_Panel[41],0,1); 
  }   
} else {
  bitWrite(audata_Panel[41],0,0);
  xInit_Alarm_TE=0;
}

//Давление масла низкое
if ((audata_Panel[36]<10) & (audata_Panel[9]>800)) {
  if (!xInit_Alarm_Oil){
    Time_Alarm_Oil= millis();
    xInit_Alarm_Oil=1;
  }
  if (millis() - Time_Alarm_Oil>1000) {
    bitWrite(audata_Panel[41],1,1); 
  }   
} else {
  bitWrite(audata_Panel[41],1,0);
  xInit_Alarm_Oil=0;
}

//Давление топлива низкое
if ((audata_Panel[37]<15) & (audata_Panel[9]>800)) {
  if (!xInit_Alarm_Fuel){
    Time_Alarm_Fuel= millis();
    xInit_Alarm_Fuel=1;
  }
  if (millis() - Time_Alarm_Fuel>1000) {
    bitWrite(audata_Panel[41],2,1); 
  }   
} else {
  bitWrite(audata_Panel[41],2,0);
  xInit_Alarm_Fuel=0;
}
//Напряжение низкое
if ((audata_Panel[14]<1150) & (audata_Panel[9]>800)) {
  if (!xInit_Alarm_Voltage){
    Time_Alarm_Voltage= millis();
    xInit_Alarm_Voltage=1;
  }
  if (millis() - Time_Alarm_Voltage>1000) {
    bitWrite(audata_Panel[41],3,1); 
  }   
} else {
  bitWrite(audata_Panel[41],3,0);
  xInit_Alarm_Voltage=0;
}
//Смесь бедная
if ((audata_Panel[46]>160) & (audata_Panel[9]>800)) {
  if (!xInit_Alarm_Alf){
    Time_Alarm_Alf= millis();
    xInit_Alarm_Alf=1;
  }
  if (millis() - Time_Alarm_Alf>2000) {
    bitWrite(audata_Panel[41],4,1); 
  }   
} else {
  bitWrite(audata_Panel[41],4,0);
  xInit_Alarm_Alf=0;
}



//Таймер для отправки сообщения racechrono
xTON_racechrono = 0;
if (millis() - last_time4>100) {
   last_time4 = millis();
   xTON_racechrono = 1;
}
if (xTON_racechrono) {                    
    String str = String("$RC2,,") + String(count++) + ",,,,,,";  //$RC2,[time],[count],[xacc],[yacc],[zacc],[rpm/d1],[d2],
    str += String(audata_Panel[9]) + ",";                        //[a1], Обороты двигателя
    str += String(audata_Panel[8]) + ",";                        //[a2], Положение дросселя в %
    str += String(iPE_Break) + ",";                              //[a3], Давление тормозов в % 
    str += String(iAngle) + ",";                                 //[a4], Угол поворота руля
    str += String(audata_Panel[6]) + ",";                        //[a5], Температура охлаждающей жидкости 
    str += String(rPE_Oil,1) + ",";                              //[a6], Давление масла
    str += String(rPE_Fuel,1) + ",";                             //[a7], Давление топлива
    str += String(rAlf) + "*";                                   //[a8]* Соотношение воздух/топливо
    // Отправление данных
    Serial2.println(str + checksum( str ));
    //Serial.print("rAlf "); Serial.println(rAlf); 
}

//Serial.print("iState "); Serial.println(iState);


Serial.print("iState "); Serial.println(iState);   //Не удалять! Без из этой строчки нихуя не работает!


slave.poll(audata_Panel, 50 ); //Обмен данными по Modbus-Slave 




} //Окончание цикла loop 

Более подробно о проекте

4 лайка