Всем привет. Может быть кому-то будет интересна эта тема.
Сделал вот такой проект. 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
Более подробно о проекте