Опаньки, вот это обнадежил. А Мега пришла буквально позавчера. Я просто такого нюанса как-то не учел, и думал вдруг втиснемся в память Уно. Но если такие пироги, перехожу на нее.
По идее по протоколу ТС делали считывание ошибок. Там определенные биты отвечают за пассивный DTC или активный. Но тут видимо чето отличается, поэтому он не пишет passive или active
На Мега запустилось, но буковки прыгают каждый раз при посылке запроса.... Как там на hardvare serial перейти?
Все, разобрался. #define mySerial Serial1
Как-то Оп-ком и Опель-сканер смотрят активная или пассивная. Да в принципе, не большая проблема. Если на приборке Джеки-чан горит, значит есть активная ошибка. Если посыпался ворох, то стер и смотришь что вылезет снова.
В конечном скече нужно будет делать проверку и fastinit(); повторять если, например, после пяти секунд отправки запроса Init ничего не меняется. Мало ли из-за чего связь прервется. Сейчас, например, если включить Дуню, а потом зажигание, то ничего не добьешья.
так попробуй
#include <Button.h>
Button test;
#define BUTTON_PIN 4 // пин подключения тактовой кнопки
#define BUTTON 0 // программный номер кнопки
//#define ARDUINO_MEGA // закоментировать эту строку если НЕ будем мегу использовать
#ifdef ARDUINO_MEGA
#define K_LINE Serial3
#define TX 14
#else
#include <SoftwareSerial.h>
#define RX 12
#define TX 13
SoftwareSerial K_LINE (RX, TX);
#endif
byte messageInit[] = {0x81,0x11,0xF1,0x81,0x04}; // запрос инициализации
byte messagePids[] = {0x82,0x11,0xF1,0x21,0x01,0xA6}; // запрос пид 2101
byte messagePresent[] = {0x81,0x11,0xF1,0x3E,0xC1}; // запрос присутствия
byte messageRead_DTC [] = {0x84,0x11,0xF1,0x18,0x00,0xFF,0x00,0x9D}; // запрос ошибок
byte messageErase_DTC[] = {0x83,0x11,0xF1,0x14,0xFF,0x00,0x98}; // запрос стирания ошибок
uint32_t curmillis =0; // снимок текущего времени
uint32_t prevRequest = 0; // таймер периодических запросов
int RequestPeriod = 100; // периодичность запросов , мс
uint32_t prevRESETheader=0; // таймер сброса заголовка если в момент приёма заголовка данные оборвались
bool RESETheader_timer; // таймер сброса заголовка если в момент приёма заголовка данные оборвались
uint32_t prev_NOanswer=0; // таймер контроля неответов от ЭБУ после запросов
bool NOanswer_timer = 0; // таймер контроля неответов от ЭБУ после запросов
byte noanswers = 0; // количество подряд неответов от ЭБУ
uint32_t timerdelay = 0; // таймер ожидания байт (для успевания появления данных в буфере UART)
bool Delay = 0; // таймер ожидания байт (для успевания появления данных в буфере UART)
byte waitbyte_RX = 1; // задержка, мс для успевания появления данных в буфере RX
// (подрегулировать в зависимости от уровня жизнидеятельности на Марсе)
#define TIMER_DELAY Delay = 0; timerdelay = curmillis // включение этого таймера
byte delaybyte_TX = 1; // задержка между посылкой байт в запросе, мс
// возможные варианты запросов на ЭБУ:
enum REQUEST
{
INIT_bus,
INIT,
PID,
DTCREAD,
DTCERASE,
PRESENT
} ;
byte request = INIT; // переменная, показывающая какой запрос будем делать
byte header = 0; // состояние заголовка
byte message_size = 0; // размер тела сообщения
byte j = 3; // инкремент
byte n = 3; // количество старт байт
const byte bufsize = 100; // размер буфера принятого сообщения
byte buf [bufsize] = {0}; // буфер принятого сообщения
byte crc =0; // байт контрольной суммы
// переменные трип компьютера
float MAP = 0; //13 байт Датчик абсолютного давления
float SysVolt = 0; //14 байт Напряжение в сети
int TempAir = 0; //16 байт Температура воздуха в градусах
int Temp = 0; //18 байт Температура охлаждающей жидкости в градусах
int EngLoad = 0; //20 байы нагрузка на двигатель
byte Throtle = 0; //28 байт Открытие дроссельной заслонки в процентах
unsigned int RPM = 0; //30 байт Обороты двигателя
unsigned int Speed = 0; //29 байт Скорость а/м
float InjPulse = 0; //31 байт Время впрыска форсунок
unsigned int IdleAir = 0; //32 байт Клапан холостого хода, шаги
unsigned int O2sens = 0; //35 байт Лямбда мВ
unsigned int O2int = 0; //36 байт Интегратор лямда, шагов
float FuelRatio = 0; //41 байт Соотношение воздуха/топлива
int STFT = 0; // Краткосрочная коррекция топлива
void setup() {
delay(3000);
// ниже настройки кнопок
test.NO(); // кнопка нормально разомкнутая
test.pullUp(); // внутренняя подтяжка к питанию вкючена
test.duration_bounce ( 50); // время антидребезга, мс
test.duration_click_Db ( 250); // время дабл клика, мс
test.duration_inactivity_Up(5000);
test.duration_inactivity_Dn(1000);
test.duration_press ( 500); // время длительного нажатия, мс
test.button(BUTTON_PIN); // подключенные кнопки (пишутся через запятую)
Serial.begin(115200);
K_LINE.begin(10400);
pinMode(TX, OUTPUT);
fastinit();
}
void loop() {
curmillis = millis(); // снимок текущего времени
if (test.event_click_Dn (BUTTON)) {request = DTCREAD; RequestPeriod = 1000;} // если было короткое нажатие на тактовую кнопку запросим DTC
if (test.event_press_long (BUTTON)){request = DTCERASE; RequestPeriod = 1000;} // если было длительное нажатие на тактовую кнопку удалим DTC
if (curmillis - prevRequest > RequestPeriod && header == 0) {
NOanswer_timer = 1; prev_NOanswer = curmillis; //т.к. сейчас будем делать запрос, то запускаем таймер контроля неответов
if (request == INIT_bus) fastinit();
else if (request == INIT){
Serial.println ("Otpravil zapros Init");
for (byte i = 0; i<sizeof(messageInit); i++) {K_LINE.write(messageInit[i]); delay (5);}
delay (55); }
else if (request == PID){
//Serial.println ("Otpravil zapros 21 01");
for (int i = 0; i < sizeof(messagePids); i++) {K_LINE.write(messagePids[i]); delay (delaybyte_TX); }}
else if (request == DTCREAD) {
Serial.println ("Otpravil zapros DTC read");
for (int i = 0; i < sizeof(messageRead_DTC); i++) {K_LINE.write(messageRead_DTC[i]); delay (delaybyte_TX); }}
else if (request == DTCERASE) {
Serial.println ("Otpravil zapros DTC clear");
for (int i = 0; i < sizeof(messageErase_DTC); i++) {K_LINE.write(messageErase_DTC[i]); delay (delaybyte_TX); }}
prevRequest = curmillis;
}
//разбор входящих сообщений
receive ();
}
//стартовая инициализация PCM на 7 пине ОБД (fast init - 25ms LOW 25ms HIGH)
void fastinit() {
digitalWrite (TX, HIGH); // makes K-line high 3
delay(360); // wait for K-line to be clear 3
digitalWrite (TX, LOW); // makes K-line low 3
delay(25);
digitalWrite (TX, HIGH); // makes K-line high 3
delay(25); //last delay before first message
K_LINE.begin(10400); // baud rate of the OBD
request = INIT; RequestPeriod = 500;
}
//получение данных от ЭБУ, разборка входящих сообщений
void receive () {
if (K_LINE.available() ){
// первый старт байт
if (header == 0 && Delay){TIMER_DELAY ; buf[0]=K_LINE.read();
if (buf[0]!=0xFF && bitRead (buf[0],7)){header = 1; RESETheader_timer =1; prevRESETheader = curmillis;
Serial.print (buf[0], HEX); Serial.print (" "); }}
// второй старт байт
if (header == 1 && Delay){TIMER_DELAY ; buf[1]=K_LINE.read(); Serial.print (buf[1], HEX); Serial.print (" ");if (buf[1]==0xF1){ header = 2;} else {header = 0; RESETheader_timer = 0;}}
// третий старт байт
if (header == 2 && Delay){
TIMER_DELAY ;
buf[2]=K_LINE.read(); Serial.print (buf[2], HEX); Serial.print (" ");
if (buf[2]==0x11){ message_size = buf[0];
if (buf[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; RESETheader_timer = 0;}
}
// если размер сообщения указан в дополнительном байте (нулевой байт 0x80) читаем этот дополнительный байт:
if (header == 3 && Delay){
TIMER_DELAY ;
buf[3]=K_LINE.read(); Serial.print (buf[3], HEX); Serial.print (" ");
message_size = buf[3];
if (message_size > bufsize) message_size = bufsize;
crc = 0; header = 4;
}
// пишем тело сообщения
if (header == 4 && Delay && j< message_size+n+1) {
buf[j] = K_LINE.read();
if (j<message_size+n) crc+= buf[j]; // подсчёт КС
if (j==message_size+n) header = 5;
TIMER_DELAY ; Serial.print (buf[j], HEX); Serial.print (" "); j++;}
}
// сообщение приняли, действуем
if (header == 5) {TIMER_DELAY ;
Serial.println();
NOanswer_timer = 0; noanswers = 0; // сбрасываем таймер контроля неответов
for(byte i = 0; i<n; i++) crc+=buf[i]; // прибавляем к контрольной сумме старт байты
// если контрольная сумма верна:
if ( crc == buf[message_size+n]) {Serial.println("Received message is OK! Checksum is correct!" ); // Если КС совпала, тут чёнибудь нужное делаем
if (buf[n]==0xC1 && buf[n+1]==0xEF && buf[n+2]==0x8F) {request = PID; RequestPeriod = 100; Serial.println (" Initialization OK!!!!: "); }
else if (buf[n]==0x58 && buf[n+1]==0x00) {Serial.println (" NO DTC "); request = PID; RequestPeriod = 100;}
else if (buf[n]==0x58 && buf[n+1] >0x00) {Serial.println (" DTC is found!"); request = PID; RequestPeriod = 100;
for (byte i=0; i<buf[n+1]; i++ ) {
Serial.print("ERROR ");
Serial.print (i+1);
if (!bitRead(buf[n+2+(i*3)],6) && !bitRead(buf[n+2+(i*3)],7)) Serial.print(": P");
if (bitRead(buf[n+2+(i*3)],6) && !bitRead(buf[n+2+(i*3)],7)) Serial.print(": C");
if (!bitRead(buf[n+2+(i*3)],6) && bitRead(buf[n+2+(i*3)],7)) Serial.print(": B");
if (bitRead(buf[n+2+(i*3)],6) && bitRead(buf[n+2+(i*3)],7)) Serial.print(": U");
if (buf[n+2+(i*3)]<=0x0F) Serial.print("0");
Serial.print (buf[n+2+(i*3)],HEX);
if (buf[n+3+(i*3)]<=0x0F) Serial.print("0");
Serial.print (buf[n+3+(i*3)],HEX);
if (!bitRead(buf[n+4+(i*3)],6) && bitRead(buf[n+4+(i*3)],7)){
Serial.print(" -Passive-");}
if (bitRead(buf[n+4+(i*3)],7) && bitRead(buf[n+4+(i*3)],6)) {
Serial.print(" -Active-");}
Serial.println();
} }
else if (buf[n]==0x54 && buf[n+1]==0xFF && buf[n+2]==0x00){ Serial.println (" DTC CLEARED "); request = PID; RequestPeriod = 100;}
else if (buf[n]==0x61 && buf[n+1]==0x01) { Serial.println (" Receive DATA");
MAP = ((uint16_t)buf[n+9]*1.04/255.0); //13 байт Датчик абсолютного давления 102mbar
SysVolt = ((float)buf[n+10]/10.00); //14 байт Напряжение в сети 12.1v
{double t , cel , drob ;
t = (buf[n+12]*191ul/255.0)-40; //16 байт Температура воздуха в градусах 50
drob = modf(t, &cel); if (drob>=0.5) cel++;
TempAir = cel;}
{double t , cel , drob ;
t = (buf[n+14]*191ul/255.0)-40; //18 байт Температура охлаждающей жидкости в градусах104
drob = modf(t, &cel); if (drob>=0.5) cel++;
Temp = cel;}
EngLoad = ((uint16_t)buf[n+16]*100/255); //20 байы нагрузка на двигатель7%
Throtle = ((uint16_t)buf[n+24]*100/255); //28 байт Открытие дроссельной заслонки в процентах 0
RPM = ((uint32_t)buf[n+26]*6375ul/255ul); //30 байт Оборогты двигателя 0
Speed = (buf[n+25]); //29 байт Скорость 0
InjPulse = ((float)buf[n+27]*21.8/255.0); //31 байт Время впрыска форсунок 11.9
IdleAir = (buf[n+28]); //32 байт Клапан холостого хода, шаги 38
O2sens =(uint32_t) buf[n+31]*1127ul/255ul; //35 байт Лямбда мВ 380
O2int = (buf[n+32]); //36 байт Интегратор лямда, шагов 128
FuelRatio = ((float)buf[n+37]/10.00); //41 байт Соотношение воздуха/топлива 12.3
STFT = (((uint16_t)buf[n+32]-128)*100/128); // Краткосрочная коррекция топлива
Serial.print(" MAP=");Serial.print(MAP);Serial.print(" Battery=");Serial.print(SysVolt);
Serial.print(" Air=");Serial.print(TempAir);Serial.print(" Temp=");Serial.print(Temp);
Serial.print(" EngLoad=");Serial.print(EngLoad);Serial.print(" Throtle=");Serial.print(Throtle);
Serial.print(" RPM=");Serial.print(RPM); Serial.print(" Speed=");Serial.print(Speed);
Serial.print(" Inj=");Serial.print(InjPulse);Serial.print(" IdleAir=");Serial.print(IdleAir);
Serial.print(" O2sens=");Serial.print(O2sens);Serial.print(" O2int=");Serial.print(O2int);
Serial.print(" FuelRatio=");Serial.print(FuelRatio);Serial.print(" STFT=");Serial.println(STFT);
}
}
// если контрольная сумма не совпала:
else Serial.println("CRC fail!!!" );
message_size = 0; header=0; RESETheader_timer = 0; j=3; crc = 0;
}
// таймер ожидания байт (для успевания появления данных в буфере UART)
if (!Delay && curmillis - timerdelay > waitbyte_RX) Delay = 1;
// таймер сброса заголовка если данные оборвались во время приёма заголовка
if (RESETheader_timer && curmillis - prevRESETheader > 500) {RESETheader_timer = 0; header = 0;}
// если нет ответа после запроса: +1 к счетчику неответов. Если накопилось 6 и более: делаем реинит.
if (NOanswer_timer && curmillis - prev_NOanswer > RequestPeriod - RequestPeriod/8) {NOanswer_timer = 0; noanswers++;
if (noanswers>=6) { noanswers = 0; request = INIT_bus;} }
}
По софт-сериал коннектится, а по хардварному - нет. Кстати, на Дуне написано пин 18 - RX1, 19 - TX1. Но все равно никак. Пишет только «отправил запрос инит». Т.е. в скетче ставил 19. Поменял местами пины, ну а вдруг. Просто увидел ещё что шлёт запрос 81 11 F1 81Otpravil zapros Init и тд.
Значится, по софтсериал. Работает. Но повторное подключение при обрыве связи не происходит. Решил проблему добавление задержки в строке 116 перед fastinit:
if (request == INIT_bus) {Serial.println ("Fastinit");delay(1000); fastinit();}
Так отлично работает.
Теперь оп хардварному. Если оставить все как есть то выдает только следующее:
Otpravil zapros Init
81 11 F1 81 Otpravil zapros Init
81 11 F1 81 Otpravil zapros Init
81 11 F1 81 Otpravil zapros Init
81 11 F1 81 Otpravil zapros Init
81 11 F1 81 Otpravil zapros Init
81 11 F1 81 Fastinit
Otpravil zapros Init
81 11 F1 81 Otpravil zapros Init
81 11 F1 81 Otpravil zapros Init
81 11 F1 81 Otpravil zapros Init
81 11 F1 81 Otpravil zapros Init
81 11 F1 81 Otpravil zapros Init
81 11 F1 81 Fastinit
Otpravil zapros Init
Почему мы вообще видим часть запроса инициализации?
Далее я предположил, что это из-за того, что мы сперва стартуем наш серийный порт, а потом уже на скорости 10400 шлем fastinit, и действительно оказалось это так. В общем, вот скетч:
#include <Button.h>
Button test;
#define BUTTON_PIN 4 // пин подключения тактовой кнопки
#define BUTTON 0 // программный номер кнопки
#define ARDUINO_MEGA // закоментировать эту строку если НЕ будем мегу использовать
#ifdef ARDUINO_MEGA
#define K_LINE Serial3
#define TX 14
#else
#include <SoftwareSerial.h>
#define RX 12
#define TX 13
SoftwareSerial K_LINE (RX, TX);
#endif
byte messageInit[] = {0x81,0x11,0xF1,0x81,0x04}; // запрос инициализации
byte messagePids[] = {0x82,0x11,0xF1,0x21,0x01,0xA6}; // запрос пид 2101
byte messagePresent[] = {0x81,0x11,0xF1,0x3E,0xC1}; // запрос присутствия
byte messageRead_DTC [] = {0x84,0x11,0xF1,0x18,0x00,0xFF,0x00,0x9D}; // запрос ошибок
byte messageErase_DTC[] = {0x83,0x11,0xF1,0x14,0xFF,0x00,0x98}; // запрос стирания ошибок
uint32_t curmillis =0; // снимок текущего времени
uint32_t prevRequest = 0; // таймер периодических запросов
int RequestPeriod = 100; // периодичность запросов , мс
uint32_t prevRESETheader=0; // таймер сброса заголовка если в момент приёма заголовка данные оборвались
bool RESETheader_timer; // таймер сброса заголовка если в момент приёма заголовка данные оборвались
uint32_t prev_NOanswer=0; // таймер контроля неответов от ЭБУ после запросов
bool NOanswer_timer = 0; // таймер контроля неответов от ЭБУ после запросов
byte noanswers = 0; // количество подряд неответов от ЭБУ
uint32_t timerdelay = 1; // таймер ожидания байт (для успевания появления данных в буфере UART)
bool Delay = 1; // таймер ожидания байт (для успевания появления данных в буфере UART)
byte waitbyte_RX = 1; // задержка, мс для успевания появления данных в буфере RX
// (подрегулировать в зависимости от уровня жизнидеятельности на Марсе)
#define TIMER_DELAY Delay = 0; timerdelay = curmillis // включение этого таймера
byte delaybyte_TX = 1; // задержка между посылкой байт в запросе, мс
// возможные варианты запросов на ЭБУ:
enum REQUEST
{
INIT_bus,
INIT,
PID,
DTCREAD,
DTCERASE,
PRESENT
} ;
byte request = INIT; // переменная, показывающая какой запрос будем делать
byte header = 0; // состояние заголовка
byte message_size = 0; // размер тела сообщения
byte j = 3; // инкремент
byte n = 3; // количество старт байт
const byte bufsize = 100; // размер буфера принятого сообщения
byte buf [bufsize] = {0}; // буфер принятого сообщения
byte crc =0; // байт контрольной суммы
// переменные трип компьютера
float MAP = 0; //13 байт Датчик абсолютного давления
float SysVolt = 0; //14 байт Напряжение в сети
int TempAir = 0; //16 байт Температура воздуха в градусах
int Temp = 0; //18 байт Температура охлаждающей жидкости в градусах
int EngLoad = 0; //20 байы нагрузка на двигатель
byte Throtle = 0; //28 байт Открытие дроссельной заслонки в процентах
unsigned int RPM = 0; //30 байт Обороты двигателя
unsigned int Speed = 0; //29 байт Скорость а/м
float InjPulse = 0; //31 байт Время впрыска форсунок
unsigned int IdleAir = 0; //32 байт Клапан холостого хода, шаги
unsigned int O2sens = 0; //35 байт Лямбда мВ
unsigned int O2int = 0; //36 байт Интегратор лямда, шагов
float FuelRatio = 0; //41 байт Соотношение воздуха/топлива
int STFT = 0; // Краткосрочная коррекция топлива
void setup() {
delay(3000);
// ниже настройки кнопок
test.NO(); // кнопка нормально разомкнутая
test.pullUp(); // внутренняя подтяжка к питанию вкючена
test.duration_bounce ( 50); // время антидребезга, мс
test.duration_click_Db ( 250); // время дабл клика, мс
test.duration_inactivity_Up(5000);
test.duration_inactivity_Dn(1000);
test.duration_press ( 500); // время длительного нажатия, мс
test.button(BUTTON_PIN); // подключенные кнопки (пишутся через запятую)
Serial.begin(115200);
pinMode(TX, OUTPUT);
Serial.println ("Fastinit");
fastinit();
K_LINE.begin(10400);
}
void loop() {
curmillis = millis(); // снимок текущего времени
if (test.event_click_Dn (BUTTON)) {request = DTCREAD; RequestPeriod = 1000;} // если было короткое нажатие на тактовую кнопку запросим DTC
if (test.event_press_long (BUTTON)){request = DTCERASE; RequestPeriod = 1000;} // если было длительное нажатие на тактовую кнопку удалим DTC
if (curmillis - prevRequest > RequestPeriod && header == 0) {
NOanswer_timer = 1; prev_NOanswer = curmillis; //т.к. сейчас будем делать запрос, то запускаем таймер контроля неответов
if (request == INIT_bus) {K_LINE.end();Serial.println ("Fastinit");delay(1000); fastinit();K_LINE.begin(10400);}
else if (request == INIT){
Serial.println ("Otpravil zapros Init");
for (byte i = 0; i<sizeof(messageInit); i++) {K_LINE.write(messageInit[i]); delay (5);}
delay (55); }
else if (request == PID){
//Serial.println ("Otpravil zapros 21 01");
for (int i = 0; i < sizeof(messagePids); i++) {K_LINE.write(messagePids[i]); delay (delaybyte_TX); }}
else if (request == DTCREAD) {
Serial.println ("Otpravil zapros DTC read");
for (int i = 0; i < sizeof(messageRead_DTC); i++) {K_LINE.write(messageRead_DTC[i]); delay (delaybyte_TX); }}
else if (request == DTCERASE) {
Serial.println ("Otpravil zapros DTC clear");
for (int i = 0; i < sizeof(messageErase_DTC); i++) {K_LINE.write(messageErase_DTC[i]); delay (delaybyte_TX); }}
prevRequest = curmillis;
}
//разбор входящих сообщений
receive ();
}
//стартовая инициализация PCM на 7 пине ОБД (fast init - 25ms LOW 25ms HIGH)
void fastinit() {
digitalWrite (TX, HIGH); // makes K-line high 3
delay(360); // wait for K-line to be clear 3
digitalWrite (TX, LOW); // makes K-line low 3
delay(25);
digitalWrite (TX, HIGH); // makes K-line high 3
delay(25); //last delay before first message
K_LINE.begin(10400); // baud rate of the OBD
request = INIT; RequestPeriod = 500;
}
//получение данных от ЭБУ, разборка входящих сообщений
void receive () {
if (K_LINE.available() ){
// первый старт байт
if (header == 0 && Delay){TIMER_DELAY ; buf[0]=K_LINE.read();
if (buf[0]!=0xFF && bitRead (buf[0],7)){header = 1; RESETheader_timer =1; prevRESETheader = curmillis;
Serial.print (buf[0], HEX); Serial.print (" "); }}
// второй старт байт
if (header == 1 && Delay){TIMER_DELAY ; buf[1]=K_LINE.read(); Serial.print (buf[1], HEX); Serial.print (" ");if (buf[1]==0xF1){ header = 2;} else {header = 0; RESETheader_timer = 0;}}
// третий старт байт
if (header == 2 && Delay){
TIMER_DELAY ;
buf[2]=K_LINE.read(); Serial.print (buf[2], HEX); Serial.print (" ");
if (buf[2]==0x11){ message_size = buf[0];
if (buf[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; RESETheader_timer = 0;}
}
// если размер сообщения указан в дополнительном байте (нулевой байт 0x80) читаем этот дополнительный байт:
if (header == 3 && Delay){
TIMER_DELAY ;
buf[3]=K_LINE.read(); Serial.print (buf[3], HEX); Serial.print (" ");
message_size = buf[3];
if (message_size > bufsize) message_size = bufsize;
crc = 0; header = 4;
}
// пишем тело сообщения
if (header == 4 && Delay && j< message_size+n+1) {
buf[j] = K_LINE.read();
if (j<message_size+n) crc+= buf[j]; // подсчёт КС
if (j==message_size+n) header = 5;
TIMER_DELAY ; Serial.print (buf[j], HEX); Serial.print (" "); j++;}
}
// сообщение приняли, действуем
if (header == 5) {TIMER_DELAY ;
Serial.println();
NOanswer_timer = 0; noanswers = 0; // сбрасываем таймер контроля неответов
for(byte i = 0; i<n; i++) crc+=buf[i]; // прибавляем к контрольной сумме старт байты
// если контрольная сумма верна:
if ( crc == buf[message_size+n]) {Serial.println("Received message is OK! Checksum is correct!" ); // Если КС совпала, тут чёнибудь нужное делаем
if (buf[n]==0xC1 && buf[n+1]==0xEF && buf[n+2]==0x8F) {request = PID; RequestPeriod = 100; Serial.println (" Initialization OK!!!!: "); }
else if (buf[n]==0x58 && buf[n+1]==0x00) {Serial.println (" NO DTC "); request = PID; RequestPeriod = 100;}
else if (buf[n]==0x58 && buf[n+1] >0x00) {Serial.println (" DTC is found!"); request = PID; RequestPeriod = 100;
for (byte i=0; i<buf[n+1]; i++ ) {
Serial.print("ERROR ");
Serial.print (i+1);
if (!bitRead(buf[n+2+(i*3)],6) && !bitRead(buf[n+2+(i*3)],7)) Serial.print(": P");
if (bitRead(buf[n+2+(i*3)],6) && !bitRead(buf[n+2+(i*3)],7)) Serial.print(": C");
if (!bitRead(buf[n+2+(i*3)],6) && bitRead(buf[n+2+(i*3)],7)) Serial.print(": B");
if (bitRead(buf[n+2+(i*3)],6) && bitRead(buf[n+2+(i*3)],7)) Serial.print(": U");
if (buf[n+2+(i*3)]<=0x0F) Serial.print("0");
Serial.print (buf[n+2+(i*3)],HEX);
if (buf[n+3+(i*3)]<=0x0F) Serial.print("0");
Serial.print (buf[n+3+(i*3)],HEX);
if (!bitRead(buf[n+4+(i*3)],6) && bitRead(buf[n+4+(i*3)],7)){
Serial.print(" -Passive-");}
if (bitRead(buf[n+4+(i*3)],7) && bitRead(buf[n+4+(i*3)],6)) {
Serial.print(" -Active-");}
Serial.println();
} }
else if (buf[n]==0x54 && buf[n+1]==0xFF && buf[n+2]==0x00){ Serial.println (" DTC CLEARED "); request = PID; RequestPeriod = 100;}
else if (buf[n]==0x61 && buf[n+1]==0x01) { Serial.println (" Receive DATA");
MAP = ((uint16_t)buf[n+9]*1.04/255.0); //13 байт Датчик абсолютного давления 102mbar
SysVolt = ((float)buf[n+10]/10.00); //14 байт Напряжение в сети 12.1v
{double t , cel , drob ;
t = (buf[n+12]*191ul/255.0)-40; //16 байт Температура воздуха в градусах 50
drob = modf(t, &cel); if (drob>=0.5) cel++;
TempAir = cel;}
{double t , cel , drob ;
t = (buf[n+14]*191ul/255.0)-40; //18 байт Температура охлаждающей жидкости в градусах104
drob = modf(t, &cel); if (drob>=0.5) cel++;
Temp = cel;}
EngLoad = ((uint16_t)buf[n+16]*100/255); //20 байы нагрузка на двигатель7%
Throtle = ((uint16_t)buf[n+24]*100/255); //28 байт Открытие дроссельной заслонки в процентах 0
RPM = ((uint32_t)buf[n+26]*6375ul/255ul); //30 байт Оборогты двигателя 0
Speed = (buf[n+25]); //29 байт Скорость 0
InjPulse = ((float)buf[n+27]*21.8/255.0); //31 байт Время впрыска форсунок 11.9
IdleAir = (buf[n+28]); //32 байт Клапан холостого хода, шаги 38
O2sens =(uint32_t) buf[n+31]*1127ul/255ul; //35 байт Лямбда мВ 380
O2int = (buf[n+32]); //36 байт Интегратор лямда, шагов 128
FuelRatio = ((float)buf[n+37]/10.00); //41 байт Соотношение воздуха/топлива 12.3
STFT = (((uint16_t)buf[n+32]-128)*100/128); // Краткосрочная коррекция топлива
Serial.print(" MAP=");Serial.print(MAP);Serial.print(" Battery=");Serial.print(SysVolt);
Serial.print(" Air=");Serial.print(TempAir);Serial.print(" Temp=");Serial.print(Temp);
Serial.print(" EngLoad=");Serial.print(EngLoad);Serial.print(" Throtle=");Serial.print(Throtle);
Serial.print(" RPM=");Serial.print(RPM); Serial.print(" Speed=");Serial.print(Speed);
Serial.print(" Inj=");Serial.print(InjPulse);Serial.print(" IdleAir=");Serial.print(IdleAir);
Serial.print(" O2sens=");Serial.print(O2sens);Serial.print(" O2int=");Serial.print(O2int);
Serial.print(" FuelRatio=");Serial.print(FuelRatio);Serial.print(" STFT=");Serial.println(STFT);
}
}
// если контрольная сумма не совпала:
else Serial.println("CRC fail!!!" );
message_size = 0; header=0; RESETheader_timer = 0; j=3; crc = 0;
}
// таймер ожидания байт (для успевания появления данных в буфере UART)
if (!Delay && curmillis - timerdelay > waitbyte_RX) Delay = 1;
// таймер сброса заголовка если данные оборвались во время приёма заголовка
if (RESETheader_timer && curmillis - prevRESETheader > 500) {RESETheader_timer = 0; header = 0;}
// если нет ответа после запроса: +1 к счетчику неответов. Если накопилось 6 и более: делаем реинит.
if (NOanswer_timer && curmillis - prev_NOanswer > RequestPeriod - RequestPeriod/8) {NOanswer_timer = 0; noanswers++;
if (noanswers>=6) { noanswers = 0; request = INIT_bus;} }
}
С этим скетчем получаем вот такую картину:
Fastinit
Otpravil zapros Init
81 11 F1 81 83 F1 11 C1 EF 8F C4
Received message is OK! Checksum is correct!
Initialization OK!!!!:
82 11 F1 21 A6 B0 F1 11 FA 76 84 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 84 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 84 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 84 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 84 98 8A F 97 2D Fastinit
Otpravil zapros Init
80 12 84 34 82 11 F1 21 A6 B0 F1 11 FA 76 84 98 8A F 97 2D 80 72 81 11 F1 81 Otpravil zapros Init
81 11 F1 81 83 F1 11 C1 EF 8F C4
Received message is OK! Checksum is correct!
Initialization OK!!!!:
82 11 F1 21 A6 B0 F1 11 FA 76 84 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 84 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 84 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 84 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 84 98 8A F 97 2D Fastinit
Otpravil zapros Init
80 12 84 27 82 11 F1 21 A6 B0 F1 11 FA 76 84 98 8A F 97 2D 81 11 F1 81 Otpravil zapros Init
81 11 F1 81 83 F1 11 C1 EF 8F C4
Received message is OK! Checksum is correct!
Initialization OK!!!!:
82 11 F1 21 A6 B0 F1 11 FA 76 84 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 84 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 84 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 85 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 84 98 8A F 97 2D Fastinit
Otpravil zapros Init
80 12 82 11 F1 21 B0 F1 11 61 1 1 1 70 22 0 0 0 FA 76 3F 6F 85 98 8A F 34 0 0 0 0 0 1E 0 0 0 97 2D 0 65 12 0 76 0 8 34 0 0 81 11 F1 81 4 Otpravil zapros Init
81 11 F1 81 83 F1 11 C1 EF 8F C4
Received message is OK! Checksum is correct!
Initialization OK!!!!:
82 11 F1 21 A6 B0 F1 11 FA 76 85 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 85 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 85 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 85 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 85 98 8A F 97 2D Fastinit
Otpravil zapros Init
80 12 84 27 82 11 F1 21 A6 B0 F1 11 FA 76 85 98 8A F 97 0 84 34 81 11 F1 81 Otpravil zapros Init
81 11 F1 81 83 F1 11 C1 EF 8F C4
Received message is OK! Checksum is correct!
Initialization OK!!!!:
82 11 F1 21 A6 B0 F1 11 FA 76 85 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 85 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 85 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 85 98 8A F 97 2D 80 12 84 8 82 11 F1 21 A6 B0 F1 11 FA 76 85 98 8A F 97 2D Fastinit
Otpravil zapros Init
Я так понимаю, проблема кроется в задержках? Но вот где какую крутить? Поигрался с byte waitbyte_RX = 1; ставил вплоть до 100. Но не помогло. Видать на Марсе жизни нет :)
Это по тойже причине. Аналогично нужнг вставить клайн.Реад и в те requestы. Причина в том что шина к лайн эхо даёт и мы в приёмнике видим свои отправленные мессаги . клайн.Реад вычитывает мусорные эхо байты сразу после отправки и освобождает приемный буфер для приёма уже нужных байтов от оппонента. Вопрос почему на софтсериале работало
UPDATE. а вообще я нечаянно снёс опрос кнопки (вставить в первую строку цикла loop() )
По цилиндрам это не уоз, а уменьшение уоз. Здесь показания должны увеличиваться при наличии детонации. Резко дать газу и возможно параметр будет больше нуля.
Работает! И вроде даже совпадает со штатным бортовиком, но это нужно смотреть уже с экрана, поставив два рядышком, а то в ноут отвлекаться в бегущие строчки не айс.
FuelHour = (InjPulse*169*RPM*14400/1000/60000/120); // Расход топлива литров в час
FuelKm= (FuelHour/Speed*100); // Мгновенный расход топлива на сотню
MAP=0.32 Battery=13.40 Air=17 Temp=90 EngLoad=9 Throtle=0 RPM=875 Speed=20 Inj=4.87 IdleAir=29 O2sens=738 O2int=178 FuelRatio=14.60 STFT=39 SparkAngel=8 Cyl1=0 Cyl2=0 Cyl3=0 Cyl4=0 FuelHour=1.44 FuelKm=7.21
B0 F1 11 61 1 1 1 70 22 0 0 0 50 86 81 4C 68 AD 8B 17 34 A 0 0 0 0 1E 0 13 23 39 1D 7 4C A6 B1 12 73 0 0 92 0 0 47 8C 8 7 34 0 0 0 C1
Received message is OK! Checksum is correct!
Receive DATA
MAP=0.33 Battery=13.40 Air=17 Temp=90 EngLoad=9 Throtle=0 RPM=875 Speed=19 Inj=4.87 IdleAir=29 O2sens=733 O2int=177 FuelRatio=14.60 STFT=38 SparkAngel=8 Cyl1=0 Cyl2=0 Cyl3=0 Cyl4=0 FuelHour=1.44 FuelKm=7.59
B0 F1 11 61 1 1 1 70 22 0 0 0 52 85 81 4C 68 AD 8C 17 34 A 0 0 0 0 1E 0 12 22 3A 1E 7 4C A6 B1 12 73 0 0 92 0 0 47 8C 8 7 34 0 0 0 C3
Received message is OK! Checksum is correct!
Receive DATA
MAP=0.33 Battery=13.30 Air=17 Temp=90 EngLoad=9 Throtle=0 RPM=850 Speed=18 Inj=4.96 IdleAir=30 O2sens=733 O2int=177 FuelRatio=14.60 STFT=38 SparkAngel=8 Cyl1=0 Cyl2=0 Cyl3=0 Cyl4=0 FuelHour=1.42 FuelKm=7.91
B0 F1 11 61 1 1 1 70 22 0 0 0 53 87 81 4C 68 AD 8C 17 34 A 0 0 0 0 1E 0 10 22 3A 1E 7 4C A6 B0 12 73 0 0 92 0 0 47 8C 8 7 34 0 0 0 C3
Received message is OK! Checksum is correct!
Receive DATA
MAP=0.34 Battery=13.50 Air=17 Temp=90 EngLoad=9 Throtle=0 RPM=850 Speed=16 Inj=4.96 IdleAir=30 O2sens=733 O2int=176 FuelRatio=14.60 STFT=37 SparkAngel=8 Cyl1=0 Cyl2=0 Cyl3=0 Cyl4=0 FuelHour=1.42 FuelKm=8.90
B0 F1 11 61 1 1 1 70 22 0 0 0 53 87 81 4C 69 AC 8C 17 34 A 0 0 0 0 1E 0 F 22 3A 1E 9 4C A5 B0 12 73 0 0 92 0 0 47 8C 8 7 34 0 0 0 C3
Received message is OK! Checksum is correct!
Receive DATA
MAP=0.34 Battery=13.50 Air=17 Temp=89 EngLoad=9 Throtle=0 RPM=850 Speed=15 Inj=4.96 IdleAir=30 O2sens=729 O2int=176 FuelRatio=14.60 STFT=37 SparkAngel=8 Cyl1=0 Cyl2=0 Cyl3=0 Cyl4=0 FuelHour=1.42 FuelKm=9.50
B0 F1 11 61 1 1 1 70 22 0 0 0 54 85 81 4C 69 AC 8A 17 34 A 0 0 0 0 1E 0 E 22 3A 1E 9 4B A4 AF 12 73 0 0 92 0 0 47 8C 8 7 34 0 0 0 BC
Received message is OK! Checksum is correct!
Receive DATA
MAP=0.34 Battery=13.30 Air=17 Temp=89 EngLoad=9 Throtle=0 RPM=850 Speed=14 Inj=4.96 IdleAir=30 O2sens=724 O2int=175 FuelRatio=14.60 STFT=36 SparkAngel=7 Cyl1=0 Cyl2=0 Cyl3=0 Cyl4=0 FuelHour=1.42 FuelKm=10.18
B0 F1 11 61 1 1 1 70 22 0 0 0 54 84 81 4C 69 AC 8A 17 34 A 0 0 0 0 1E 0 D 22 3A 1E 9 4B A4 AE 12 73 0 0 92 0 0 47 8C 8 7 34 0 0 0 B9
Received message is OK! Checksum is correct!
Receive DATA
MAP=0.34 Battery=13.20 Air=17 Temp=89 EngLoad=9 Throtle=0 RPM=850 Speed=13 Inj=4.96 IdleAir=30 O2sens=724 O2int=174 FuelRatio=14.60 STFT=35 SparkAngel=7 Cyl1=0 Cyl2=0 Cyl3=0 Cyl4=0 FuelHour=1.42 FuelKm=10.96
B0 F1 11 61 1 1 1 70 22 0 0 0 54 86 81 4C 69 AC 8A 17 34 A 0 0 0 0 1E 0 D 22 3A 1E 9 4B A4 AE 12 73 0 0 92 0 0 47 8C 8 7 34 0 0 0 BB
Received message is OK! Checksum is correct!
Receive DATA
MAP=0.34 Battery=13.40 Air=17 Temp=89 EngLoad=9 Throtle=0 RPM=850 Speed=13 Inj=4.96 IdleAir=30 O2sens=724 O2int=174 FuelRatio=14.60 STFT=35 SparkAngel=7 Cyl1=0 Cyl2=0 Cyl3=0 Cyl4=0 FuelHour=1.42 FuelKm=10.96
B0 F1 11 61 1 1 1 70 22 0 0 0 54 88 81 4C 69 AC 8A 17 34 A 0 0 0 0 1E 0 C 23 39 1E 9 4B A4 AD 12 73 0 0 92 0 0 47 8C 8 7 34 0 0 0 BB
Received message is OK! Checksum is correct!
Receive DATA
MAP=0.34 Battery=13.60 Air=17 Temp=89 EngLoad=9 Throtle=0 RPM=875 Speed=12 Inj=4.87 IdleAir=30 O2sens=724 O2int=173 FuelRatio=14.60 STFT=35 SparkAngel=7 Cyl1=0 Cyl2=0 Cyl3=0 Cyl4=0 FuelHour=1.44 FuelKm=12.01
B0 F1 11 61 1 1 1 70 22 0 0 0 60 87 81 4C 69 AC 8A 20 34 A 0 0 0 0 28 B C 22 42 23 9 4B A4 AB A 87 0 0 92 0 0 43 8C 8 7 34 0 0 0 F7
Received message is OK! Checksum is correct!
Receive DATA
MAP=0.39 Battery=13.50 Air=17 Temp=89 EngLoad=12 Throtle=4 RPM=850 Speed=12 Inj=5.64 IdleAir=35 O2sens=724 O2int=171 FuelRatio=14.60 STFT=33 SparkAngel=7 Cyl1=0 Cyl2=0 Cyl3=0 Cyl4=0 FuelHour=1.62 FuelKm=13.51
B0 F1 11 61 1 1 1 70 22 0 0 0 9B 87 81 4C 69 AC 8A 47 34 5 0 0 0 0 47 3A C 27 61 36 9 4B 94 A9 A 87 0 1E 92 0 0 43 8C 8 7 34 0 0 0 E5
Received message is OK! Checksum is correct!
Receive DATA
MAP=0.63 Battery=13.50 Air=17 Temp=89 EngLoad=27 Throtle=22 RPM=975 Speed=12 Inj=8.29 IdleAir=54 O2sens=654 O2int=169 FuelRatio=14.60 STFT=32 SparkAngel=7 Cyl1=0 Cyl2=0 Cyl3=0 Cyl4=0 FuelHour=2.73 FuelKm=22.77
B0 F1 11 61 1 1 1 70 22 0 0 0 BA 87 81 4C 69 AC 86 4C 34 5 2 0 14 0 4B 40 B 32 74 40 9 4A A8 A7 E 78 0 6D 92 0 0 47 8C 8 7 34 0 0 0 A5
Received message is OK! Checksum is correct!
Receive DATA
MAP=0.76 Battery=13.50 Air=17 Temp=89 EngLoad=29 Throtle=25 RPM=1250 Speed=11 Inj=9.92 IdleAir=64 O2sens=742 O2int=167 FuelRatio=14.60 STFT=30 SparkAngel=4 Cyl1=0 Cyl2=0 Cyl3=7 Cyl4=0 FuelHour=4.19 FuelKm=38.09
B0 F1 11 61 1 1 1 70 22 0 0 0 CB 87 81 4C 69 AC 82 4E 34 0 1 1 13 0 4D 43 B 2F 7D 40 9 4A A6 A4 E 78 0 84 92 0 0 47 8C 8 7 34 0 0 0 CB
Received message is OK! Checksum is correct!
Receive DATA
MAP=0.83 Battery=13.50 Air=17 Temp=89 EngLoad=30 Throtle=26 RPM=1175 Speed=11 Inj=10.69 IdleAir=64 O2sens=733 O2int=164 FuelRatio=14.60 STFT=28 SparkAngel=1 Cyl1=0 Cyl2=0 Cyl3=6 Cyl4=0 FuelHour=4.24 FuelKm=38.58
B0 F1 11 61 1 1 1 70 22 0 0 0 E3 87 81 4C 69 AC 7B 55 34 0 1 1 13 0 53 4B B 29 86 3F 9 4A A3 A2 E 78 0 90 92 0 0 47 8C 8 7 34 0 0 0 FA
Осталось только средний расход на сотню как-то сделать. Жаль, конечно, что одновременно с приборкой невозможна работа. Хотя от приборки всего то можно было бы сделать остаток пути на баке и напоминалку о замене масла...
Ну собственно, средний на сотню можно ж и без приборки. Расстояние ж равно скорость на время. Время можно хоть миллис использовать, хоть часики, у меня ж будут DS3231.
А с приборкой ж непонятка. Мало того, что последняя версия скеча не работала, так еще и переделывать из-за hardware serial.
а когда стоим., расход на сотню вообще бесконечность . и это нормально.поэтому если скорость ниже 10, можно просто выводить 99 чтоб двузначное число было.
Targitai пишет:
Ну собственно, средний на сотню можно ж и без приборки. Расстояние ж равно скорость на время. Время можно хоть миллис использовать, хоть часики, у меня ж будут DS3231.
Улыбнуло про скорость и время. Это тебе не 7 класс школы. Твоя формула для постоянной скорости. автомобиль так не ездит. Есть ещё такое понятие как ускоение.
С ускорением конечно тоже есть фомула, но тут ведь не лабораторная, где считается для движения прямолинейного равноукоренного. Автомобиль так тоже не ездит.
Тут полный пипец, и ускорение изменяемое и движение криволинейное, при котором возникает ускорение Кориолиса и т.п. Полная жопа рассчитать.
Не не, просто делаем условие - при скорости меньше 10 км/ч показывает л/ч, при большей - л/100.
Ну у нас и не звездолет чтоб так все считать. Грубо говоря, раз в 5-10 секунд расчитываем пройденное расстояние и складируем в массив. Потом находим среднее из массива. Вопрос, правда, в ОЗУ. Для более точных значений нужен большой массив. С приборкой же тоже не все так гладко - полезли в нее, потеряли связь с ЭБУ. Есть, правда, вариант подключиться вторым k-line адаптером к самой приборке. Но вариант не очень, т.к. тогда ее от OBD разъема придется отключить и сторонние сканеры уже не увидят...
Попробую залить последний рабочий скетч по приборке, переведя его на хардварный серийник, посмотрим что будет.
ЗыЖ.... кстати так же можно реализовать Long Term Fuel Trim. Было бы очень неплохо.
Проверил на всякий случай скетч 1321. Правда, ошибки забыл глянуть, ну да думаю будет работать. Добавил в него свои формулы по УОЗ и расходу. Кстати, обратил внимание, если STFT = (((uint16_t)buf[n+32]-128)*100/128); вот так, то формула работает неправильно. А если убрать (uint16_t), то все отлично.
В общем, получается финальный скетч (а то постоянно формулы прописываю :) ):
#include <Button.h>
Button test;
#define BUTTON_PIN 6 // пин подключения тактовой кнопки
#define BUTTON 0 // программный номер кнопки
#define ARDUINO_MEGA // закоментировать эту строку если НЕ будем мегу использовать
#ifdef ARDUINO_MEGA
#define K_LINE Serial3
#define TX 14
#else
#include <SoftwareSerial.h>
#define RX 7
#define TX 8
SoftwareSerial K_LINE (RX, TX);
#endif
// возможные варианты запросов на ЭБУ:
enum REQUEST {
INIT,
PID,
DTCERASE,
DTCREAD,
PRESENT,
INIT_bus};
//различные запросы на ЭБУ
byte TXmessage[][8] = {
{0x81,0x11,0xF1,0x81,0x04,0x00,0x00,0x00}, // запрос инициализации
{0x82,0x11,0xF1,0x21,0x01,0xA6,0x00,0x00}, // запрос пид 2101
{0x83,0x11,0xF1,0x14,0xFF,0x00,0x98,0x00}, // запрос стирания ошибок
{0x84,0x11,0xF1,0x18,0x00,0xFF,0x00,0x9D}, // запрос ошибок
{0x81,0x11,0xF1,0x3E,0xC1,0x00,0x00,0x00} // запрос поддержания связи
};
uint32_t curmillis =0; // снимок текущего времени
uint32_t prevRequest = 0; // таймер периодических запросов
int RequestPeriod = 100; // периодичность запросов , мс
uint32_t prevRESETheader=0; // таймер сброса заголовка если в момент приёма заголовка данные оборвались
bool RESETheader_timer; // таймер сброса заголовка если в момент приёма заголовка данные оборвались
uint32_t prev_NOanswer=0; // таймер контроля неответов от ЭБУ после запросов
bool NOanswer_timer = 0; // таймер контроля неответов от ЭБУ после запросов
byte noanswers = 0; // количество подряд неответов от ЭБУ
uint32_t timerdelay = 0; // таймер ожидания байт (для успевания появления данных в буфере UART)
bool Delay = 0; // таймер ожидания байт (для успевания появления данных в буфере UART)
byte waitbyte_RX = 1; // задержка, мс для успевания появления данных в буфере RX
// (подрегулировать в зависимости от уровня жизнидеятельности на Марсе)
#define TIMER_DELAY Delay = 0; timerdelay = curmillis // включение этого таймера
byte delaybyte_TX = 1; // задержка между посылкой байт в запросе, мс
byte request = INIT; // переменная, показывающая какой запрос будем делать
byte header = 0; // состояние заголовка
byte message_size = 0; // размер тела сообщения
byte j = 3; // инкремент
byte n = 3; // количество старт байт
const byte bufsize = 100; // размер буфера принятого сообщения
byte buf [bufsize] = {0}; // буфер принятого сообщения
byte crc =0; // байт контрольной суммы
// переменные трип компьютера
float MAP = 0; //13 байт Датчик абсолютного давления
float SysVolt = 0; //14 байт Напряжение в сети
int TempAir = 0; //16 байт Температура воздуха в градусах
int Temp = 0; //18 байт Температура охлаждающей жидкости в градусах
int EngLoad = 0; //20 байы нагрузка на двигатель
byte Throtle = 0; //28 байт Открытие дроссельной заслонки в процентах
unsigned int RPM = 0; //30 байт Обороты двигателя
unsigned int Speed = 0; //29 байт Скорость а/м
float InjPulse = 0; //31 байт Время впрыска форсунок
unsigned int IdleAir = 0; //32 байт Клапан холостого хода, шаги
unsigned int O2sens = 0; //35 байт Лямбда мВ
unsigned int O2int = 0; //36 байт Интегратор лямда, шагов
float FuelRatio = 0; //41 байт Соотношение воздуха/топлива
int STFT = 0; // Краткосрочная коррекция топлива
int SparkAngel = 0; //19 байт УОЗ
unsigned int Cyl1 =0; //23 цил1 уменшение УОЗ для уменьшения детонации
unsigned int Cyl2 =0; //24 цил2 уменшение УОЗ для уменьшения детонации
unsigned int Cyl3 =0; //25 цил3 уменшение УОЗ для уменьшения детонации
unsigned int Cyl4 =0; //26 цил4 уменшение УОЗ для уменьшения детонации
float FuelHour =0; // Расход топлива литров в час
float FuelKm=0; // Мгновенный расход топлива на сотню
void setup() {
delay(2000);
// ниже настройки кнопок
test.NO(); // кнопка нормально разомкнутая
test.pullUp(); // внутренняя подтяжка к питанию вкючена
test.duration_bounce ( 50); // время антидребезга, мс
test.duration_click_Db ( 250); // время дабл клика, мс
test.duration_inactivity_Up(5000);
test.duration_inactivity_Dn(1000);
test.duration_press ( 500); // время длительного нажатия, мс
test.button(BUTTON_PIN); // подключенные кнопки (пишутся через запятую)
Serial.begin(115200);
pinMode(TX, OUTPUT);
fastinit();
}
void loop() {
test.read(); // обновление состояния кнопок
curmillis = millis(); // снимок текущего времени
if (test.event_click_Dn (BUTTON)) {request = DTCREAD; RequestPeriod = 1000;} // если было короткое нажатие на тактовую кнопку запросим DTC
if (test.event_press_long (BUTTON)){request = DTCERASE; RequestPeriod = 1000;} // если было длительное нажатие на тактовую кнопку удалим DTC
if (curmillis - prevRequest > RequestPeriod && header == 0) {
NOanswer_timer = 1; prev_NOanswer = curmillis; //т.к. сейчас будем делать запрос, то запускаем таймер контроля неответов
if (request == INIT_bus) {K_LINE.end(); delay (450); fastinit();}
else {
byte mesSize;
if (TXmessage[request][0] !=0x80) {mesSize=TXmessage[request][0]; bitWrite (mesSize, 7 , 0);mesSize+=4;}
else mesSize=TXmessage[request][3]+5;
for (byte i = 0; i<mesSize; i++){K_LINE.write(TXmessage[request][i]); delay (delaybyte_TX); K_LINE.read(); } // отправляем соответсвтующий запрос
}
TX_otladka();
prevRequest = curmillis;
}
//разбор входящих сообщений
receive ();
}
//стартовая инициализация PCM на 7 пине ОБД (fast init - 25ms LOW 25ms HIGH)
void fastinit() {
digitalWrite (TX, HIGH); // makes K-line high 3
delay(360); // wait for K-line to be clear 3
digitalWrite (TX, LOW); // makes K-line low 3
delay(25);
digitalWrite (TX, HIGH); // makes K-line high 3
delay(25); //last delay before first message
K_LINE.begin(10400); // baud rate of the OBD
request = INIT; RequestPeriod = 500;
}
//получение данных от ЭБУ, разборка входящих сообщений
void receive () {
if (K_LINE.available() ){
// первый старт байт
if (header == 0 && Delay){TIMER_DELAY ; buf[0]=K_LINE.read();
if (buf[0]!=0xFF && bitRead (buf[0],7)){header = 1; RESETheader_timer =1; prevRESETheader = curmillis;
Serial.print (buf[0], HEX); Serial.print (" "); }}
// второй старт байт
if (header == 1 && Delay){TIMER_DELAY ; buf[1]=K_LINE.read(); Serial.print (buf[1], HEX); Serial.print (" ");if (buf[1]==0xF1){ header = 2;} else {header = 0; RESETheader_timer = 0;}}
// третий старт байт
if (header == 2 && Delay){
TIMER_DELAY ;
buf[2]=K_LINE.read(); Serial.print (buf[2], HEX); Serial.print (" ");
if (buf[2]==0x11){ message_size = buf[0];
if (buf[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; RESETheader_timer = 0;}
}
// если размер сообщения указан в дополнительном байте (нулевой байт 0x80) читаем этот дополнительный байт:
if (header == 3 && Delay){
TIMER_DELAY ;
buf[3]=K_LINE.read(); Serial.print (buf[3], HEX); Serial.print (" ");
message_size = buf[3];
if (message_size > bufsize) message_size = bufsize;
crc = 0; header = 4;
}
// пишем тело сообщения
if (header == 4 && Delay && j< message_size+n+1) {
buf[j] = K_LINE.read();
if (j<message_size+n) crc+= buf[j]; // подсчёт КС
if (j==message_size+n) header = 5;
TIMER_DELAY ; Serial.print (buf[j], HEX); Serial.print (" "); j++;}
}
// сообщение приняли, действуем
if (header == 5) {TIMER_DELAY ;
Serial.println();
NOanswer_timer = 0; noanswers = 0; // сбрасываем таймер контроля неответов
for(byte i = 0; i<n; i++) crc+=buf[i]; // прибавляем к контрольной сумме старт байты
// если контрольная сумма верна:
if ( crc == buf[message_size+n]) {Serial.println("Received message is OK! Checksum is correct!" ); // Если КС совпала, тут чёнибудь нужное делаем
if (buf[n]==0xC1 && buf[n+1]==0xEF && buf[n+2]==0x8F) {request = PID; RequestPeriod = 100; Serial.println (" Initialization OK!!!!: "); }
else if (buf[n]==0x58 && buf[n+1]==0x00) {Serial.println (" NO DTC "); request = PID; RequestPeriod = 100;}
else if (buf[n]==0x58 && buf[n+1] >0x00) {Serial.println (" DTC is found!"); request = PID; RequestPeriod = 100;
for (byte i=0; i<buf[n+1]; i++ ) {
Serial.print("ERROR ");
Serial.print (i+1);
if (!bitRead(buf[n+2+(i*3)],6) && !bitRead(buf[n+2+(i*3)],7)) Serial.print(": P");
if (bitRead(buf[n+2+(i*3)],6) && !bitRead(buf[n+2+(i*3)],7)) Serial.print(": C");
if (!bitRead(buf[n+2+(i*3)],6) && bitRead(buf[n+2+(i*3)],7)) Serial.print(": B");
if (bitRead(buf[n+2+(i*3)],6) && bitRead(buf[n+2+(i*3)],7)) Serial.print(": U");
if (buf[n+2+(i*3)]<=0x0F) Serial.print("0");
Serial.print (buf[n+2+(i*3)],HEX);
if (buf[n+3+(i*3)]<=0x0F) Serial.print("0");
Serial.print (buf[n+3+(i*3)],HEX);
if (bitRead(buf[n+4+(i*3)],7) && bitRead(buf[n+4+(i*3)],6)) {
Serial.print(" -Active-");}
else Serial.print(" -Passive-");
Serial.println();
} }
else if (buf[n]==0x54 && buf[n+1]==0xFF && buf[n+2]==0x00){ Serial.println (" DTC CLEARED "); request = PID; RequestPeriod = 100;}
else if (buf[n]==0x61 && buf[n+1]==0x01) { Serial.println (" Receive DATA");
MAP = ((uint16_t)buf[n+9]*1.04/255.0); //13 байт Датчик абсолютного давления 102mbar
SysVolt = ((float)buf[n+10]/10.00); //14 байт Напряжение в сети 12.1v
{double t , cel , drob ;
t = (buf[n+12]*191ul/255.0)-40; //16 байт Температура воздуха в градусах 50
drob = modf(t, &cel); if (drob>=0.5) cel++;
TempAir = cel;}
{double t , cel , drob ;
t = (buf[n+14]*191ul/255.0)-40; //18 байт Температура охлаждающей жидкости в градусах104
drob = modf(t, &cel); if (drob>=0.5) cel++;
Temp = cel;}
EngLoad = ((uint16_t)buf[n+16]*100/255); //20 байы нагрузка на двигатель7%
Throtle = ((uint16_t)buf[n+24]*100/255); //28 байт Открытие дроссельной заслонки в процентах 0
RPM = ((uint32_t)buf[n+26]*6375ul/255ul); //30 байт Оборогты двигателя 0
Speed = (buf[n+25]); //29 байт Скорость 0
InjPulse = ((float)buf[n+27]*21.8/255.0); //31 байт Время впрыска форсунок 11.9
IdleAir = (buf[n+28]); //32 байт Клапан холостого хода, шаги 38
O2sens =(uint32_t) buf[n+31]*1127ul/255ul; //35 байт Лямбда мВ 380
O2int = (buf[n+32]); //36 байт Интегратор лямда, шагов 128
FuelRatio = ((float)buf[n+37]/10.00); //41 байт Соотношение воздуха/топлива 12.3
STFT = ((buf[n+32]-128)*100/128); // Краткосрочная коррекция топлива
SparkAngel = ((uint16_t)buf[n+15]*180/255-90); //19 байт УОЗ
Cyl1 =((uint16_t)buf[n+19]*90/255); //23 цил1 уменшение УОЗ для уменьшения детонации
Cyl2 =((uint16_t)buf[n+20]*90/255); //24 цил2 уменшение УОЗ для уменьшения детонации
Cyl3 =((uint16_t)buf[n+21]*90/255); //25 цил3 уменшение УОЗ для уменьшения детонации
Cyl4 =((uint16_t)buf[n+22]*90/255); //26 цил4 уменшение УОЗ для уменьшения детонации
FuelHour = (InjPulse*169*RPM*14400/1000/60000/120); // Расход топлива литров в час
FuelKm= (FuelHour/Speed*100ul); // Мгновенный расход топлива на сотню
Serial.print(" MAP=");Serial.print(MAP);Serial.print(" Battery=");Serial.print(SysVolt);
Serial.print(" Air=");Serial.print(TempAir);Serial.print(" Temp=");Serial.print(Temp);
Serial.print(" EngLoad=");Serial.print(EngLoad);Serial.print(" Throtle=");Serial.print(Throtle);
Serial.print(" RPM=");Serial.print(RPM); Serial.print(" Speed=");Serial.print(Speed);
Serial.print(" Inj=");Serial.print(InjPulse);Serial.print(" IdleAir=");Serial.print(IdleAir);
Serial.print(" O2sens=");Serial.print(O2sens);Serial.print(" O2int=");Serial.print(O2int);
Serial.print(" FuelRatio=");Serial.print(FuelRatio);Serial.print(" STFT=");Serial.println(STFT);
Serial.print(" SparkAngel=");Serial.print(SparkAngel);Serial.print(" Cyl1=");Serial.print(Cyl1);
Serial.print(" Cyl2=");Serial.print(Cyl2);Serial.print(" Cyl3=");Serial.print(Cyl3);
Serial.print(" Cyl4=");Serial.print(Cyl4);
Serial.print(" FuelHour=");Serial.print(FuelHour);Serial.print(" FuelKm=");Serial.println(FuelKm);
}
}
// если контрольная сумма не совпала:
else Serial.println("CRC fail!!!" );
message_size = 0; header=0; RESETheader_timer = 0; j=3; crc = 0;
}
// таймер ожидания байт (для успевания появления данных в буфере UART)
if (!Delay && curmillis - timerdelay > waitbyte_RX) Delay = 1;
// таймер сброса заголовка если данные оборвались во время приёма заголовка
if (RESETheader_timer && curmillis - prevRESETheader > 500) {RESETheader_timer = 0; header = 0;}
// если нет ответа после запроса: +1 к счетчику неответов. Если накопилось 6 и более: делаем реинит.
if (NOanswer_timer && curmillis - prev_NOanswer > RequestPeriod - RequestPeriod/8) {NOanswer_timer = 0; noanswers++;
if (noanswers>=6) { noanswers = 0; request = INIT_bus;} }
}
void TX_otladka(){
if (request == INIT_bus) Serial.println ("Bus_INIT");
else if (request == INIT) Serial.println ("Otpravil zapros Init");
else if (request == DTCREAD) Serial.println ("Otpravil zapros DTC read");
else if (request == DTCERASE) Serial.println ("Otpravil zapros DTC clear");
}
По поводу приборки. Последний рабочий скеч, который без периодического опроса, по софтсериалу переделал на хард так:
#define BAUD_200 0
#define BAUD_5 1
bool Protocol = BAUD_5; // тут выбираем протокол 200 baud или 5 baud
byte GAUGE_ADDRESS = 0xE0; // тут выбираем адрес панели. Возможные варианты 0xE0, 0xE1, 0xB8, 0XB9, 0xBA
byte EndSession []= {0x02, 0xB2, 0x00, 0xB4};
int bit_time = 0;
//#include <SoftwareSerial.h>
#define RX_gauge 15
#define TX_gauge 14
#define Gauge_K_line Serial3 // (RX_gauge, TX_gauge);
bool InitGauge = 0; // флаг инита панели
void setup() {
Serial.begin (9600); //открываем соединение терминала для отладки
pinMode (TX_gauge, OUTPUT);
digitalWrite (TX_gauge, 1); // BUS idle
delay (2000);
// далее посылаем на панель адрес на скорости 5 baud или 200 baud
Serial.print("Delayu zapros na panel. Adress: "); Serial.println(GAUGE_ADDRESS, HEX);
if (Protocol) {bit_time = 200; Serial.println("5 baud Init"); }
else {bit_time = 5; Serial.println("200 baud Init"); }
digitalWrite (TX_gauge, 0); delay (bit_time); // старт бит
for(byte i = 0; i<8; i++) {digitalWrite (TX_gauge, bitRead(GAUGE_ADDRESS,i)); delay(bit_time);}
digitalWrite (TX_gauge, 1); delay (bit_time); // стоп бит
Gauge_K_line.begin(4800); // открываем к-лайн на приборку на 4800
}
byte head_count = 0;
byte head[4] = {0};
void loop() {
while(!InitGauge){
if (Gauge_K_line.available()) {
byte inByte = Gauge_K_line.read();
Serial.print(" ");
Serial.print(inByte,HEX);
if (inByte==0x80) {delay (10); Gauge_K_line.write (0x7F); }
delay (10);
if (inByte==0x78) {
delay (10);
Gauge_K_line.write (0x02); delay (2);
Gauge_K_line.write (0x11); delay (2);
Gauge_K_line.write (byte(0x00)); delay (2);
Gauge_K_line.write (0x13); delay (2); InitGauge=1; Serial.println(" Ura! Panel init proshla uspeshno!"); }}}
if (InitGauge && Gauge_K_line.available()) {
// ниже ищем шапку кадра
byte inbyte = Gauge_K_line.read();
delay (7);
if (inbyte == 0x21 && head_count == 0) {head_count = 1; head[0] = inbyte; }
else if (inbyte == 0xA1 && head_count == 1) {head_count = 2; head[1] = inbyte; }
else if (inbyte == 0x04 && head_count == 2) {head_count = 3; head[2] = inbyte; }
else {head_count = 0; for (byte i=0; i<sizeof(head); i++) head[i] = 0;}
// нашли шапку:
if (head_count == 3){
head_count = 0; // очищаем переменную поиска шапки
byte Length = head[0];
if (Length>100)Length=100;
const byte sizeMes = Length+2;
byte MessageRx [sizeMes] = {0};
uint16_t crc = 0;
for (byte i=0; i<3; i++){MessageRx[i]= head[i]; crc += MessageRx[i]; head[i] = 0; Serial.print (MessageRx[i], HEX); Serial.print (" ");} // очищаем переменные поиска шапки
bool CRC_OK = 0;
// ниже пишем сообщение в буфер и считаем КС
for (byte i = 3; i < sizeMes; i++) { MessageRx[i] = Gauge_K_line.read(); if (i<=sizeMes-3) crc += MessageRx[i]; delay (7); Serial.print (MessageRx[i], HEX); Serial.print (" "); }
// Serial.println();
int CRC = ( ( unsigned int )MessageRx [sizeMes-2] << 8 ) | MessageRx [sizeMes-1];
if (CRC==crc) CRC_OK = 1;
if (CRC_OK){
Serial.println (" OK!!!");
uint32_t Odometer = ((uint32_t) MessageRx[26] << 16 ) | ((uint32_t) MessageRx[25] << 8 ) | MessageRx[24];
float FuelLevel = MessageRx[21]/2.0 ;
Serial. print ("Odometer: "); Serial. print (Odometer/10); Serial. print (" km, FuelLevel: "); Serial. print (FuelLevel);Serial.println (" l");
for (byte i = 0; i < sizeof (EndSession); i++ ) { Gauge_K_line.write (EndSession [i]); delay (2);}
} // конец ифа с правильной CRC
else Serial.println(" CRC FAIL!!!");
}
}
}
С приборкой же тоже не все так гладко - полезли в нее, потеряли связь с ЭБУ. Есть, правда, вариант подключиться вторым k-line адаптером к самой приборке. Но вариант не очень, т.к. тогда ее от OBD разъема придется отключить и сторонние сканеры уже не увидят...
кстати вариант хороший. Отрезать приборку от обд. Поставить переключаюший тумблер да и всё, чтоб диагностику можно было подклчючать.
Ну шо, я такой себе радостный, что ECU отвечает адекватно. Запилил вывод на экран... И тут опять облом. Вечный инит. Опять где-то задержки крутить? Вот такой скеч:
#include <logo.h> //логотип Опель
#include <shema.h> //Разлинейка экрана
#include <font4x6.h>
#include <font6x8.h>
#include <font8x8.h>
#include <font8x8ext.h>
#include <fontALL.h>
#include <TVout.h>
#include <video_gen.h>
TVout TV;
#include <DS3231.h> // библиотека часов
DS3231 rtc(SDA, SCL);
#include <Button.h>
Button test;
#define BUTTON_PIN 6 // пин подключения тактовой кнопки
#define BUTTON 0 // программный номер кнопки
#define ARDUINO_MEGA // закоментировать эту строку если НЕ будем мегу использовать
#ifdef ARDUINO_MEGA
#define K_LINE Serial3
#define TX 14
#else
#include <SoftwareSerial.h>
#define RX 7
#define TX 8
SoftwareSerial K_LINE (RX, TX);
#endif
// возможные варианты запросов на ЭБУ:
enum REQUEST {
INIT,
PID,
DTCERASE,
DTCREAD,
PRESENT,
INIT_bus};
//различные запросы на ЭБУ
byte TXmessage[][8] = {
{0x81,0x11,0xF1,0x81,0x04,0x00,0x00,0x00}, // запрос инициализации
{0x82,0x11,0xF1,0x21,0x01,0xA6,0x00,0x00}, // запрос пид 2101
{0x83,0x11,0xF1,0x14,0xFF,0x00,0x98,0x00}, // запрос стирания ошибок
{0x84,0x11,0xF1,0x18,0x00,0xFF,0x00,0x9D}, // запрос ошибок
{0x81,0x11,0xF1,0x3E,0xC1,0x00,0x00,0x00} // запрос поддержания связи
};
uint32_t curmillis =0; // снимок текущего времени
uint32_t prevRequest = 0; // таймер периодических запросов
int RequestPeriod = 100; // периодичность запросов , мс
uint32_t prevRESETheader=0; // таймер сброса заголовка если в момент приёма заголовка данные оборвались
bool RESETheader_timer; // таймер сброса заголовка если в момент приёма заголовка данные оборвались
uint32_t prev_NOanswer=0; // таймер контроля неответов от ЭБУ после запросов
bool NOanswer_timer = 0; // таймер контроля неответов от ЭБУ после запросов
byte noanswers = 0; // количество подряд неответов от ЭБУ
uint32_t timerdelay = 0; // таймер ожидания байт (для успевания появления данных в буфере UART)
bool Delay = 0; // таймер ожидания байт (для успевания появления данных в буфере UART)
byte waitbyte_RX = 0; // задержка, мс для успевания появления данных в буфере RX
// (подрегулировать в зависимости от уровня жизнидеятельности на Марсе)
#define TIMER_DELAY Delay = 0; timerdelay = curmillis // включение этого таймера
byte delaybyte_TX = 0; // задержка между посылкой байт в запросе, мс
byte request = INIT; // переменная, показывающая какой запрос будем делать
byte header = 0; // состояние заголовка
byte message_size = 0; // размер тела сообщения
byte j = 3; // инкремент
byte n = 3; // количество старт байт
const byte bufsize = 100; // размер буфера принятого сообщения
byte buf [bufsize] = {0}; // буфер принятого сообщения
byte crc =0; // байт контрольной суммы
// переменные трип компьютера
float MAP = 0; //13 байт Датчик абсолютного давления
float SysVolt = 0; //14 байт Напряжение в сети
int TempAir = 0; //16 байт Температура воздуха в градусах
int Temp = 0; //18 байт Температура охлаждающей жидкости в градусах
int EngLoad = 0; //20 байы нагрузка на двигатель
byte Throtle = 0; //28 байт Открытие дроссельной заслонки в процентах
unsigned int RPM = 0; //30 байт Обороты двигателя
unsigned int Speed = 0; //29 байт Скорость а/м
float InjPulse = 0; //31 байт Время впрыска форсунок
unsigned int IdleAir = 0; //32 байт Клапан холостого хода, шаги
unsigned int O2sens = 0; //35 байт Лямбда мВ
unsigned int O2int = 0; //36 байт Интегратор лямда, шагов
float FuelRatio = 0; //41 байт Соотношение воздуха/топлива
int STFT = 0; // Краткосрочная коррекция топлива
int SparkAngel = 0; //19 байт УОЗ
unsigned int Cyl1 =0; //23 цил1 уменшение УОЗ для уменьшения детонации
unsigned int Cyl2 =0; //24 цил2 уменшение УОЗ для уменьшения детонации
unsigned int Cyl3 =0; //25 цил3 уменшение УОЗ для уменьшения детонации
unsigned int Cyl4 =0; //26 цил4 уменшение УОЗ для уменьшения детонации
float FuelHour =0; // Расход топлива литров в час
float FuelKm=0; // Мгновенный расход топлива на сотню
//Состояние дисплея
bool scr_clear=false; //Очищать ли экран
int scr_mode=1; //Номер отображаемого экрана
void setup() {
TV.begin(NTSC, 136, 72); // режим вывода на ТВ
TV.select_font(font8x8ext); // выбор шрифта
TV.bitmap(0, 0, logo); // вывод логотипа Опель
TV.delay(3000); // задержка 3 секунд
TV.clear_screen(); // очистить экран
TV.bitmap(0, 0, shema);
rtc.begin(); // Инициализация часов
// ниже настройки кнопок
test.NO(); // кнопка нормально разомкнутая
test.pullUp(); // внутренняя подтяжка к питанию вкючена
test.duration_bounce ( 50); // время антидребезга, мс
test.duration_click_Db ( 250); // время дабл клика, мс
test.duration_inactivity_Up(5000);
test.duration_inactivity_Dn(1000);
test.duration_press ( 500); // время длительного нажатия, мс
test.button(BUTTON_PIN); // подключенные кнопки (пишутся через запятую)
Serial.begin(115200);
pinMode(TX, OUTPUT);
fastinit();
}
void loop() {
test.read(); // обновление состояния кнопок
curmillis = millis(); // снимок текущего времени
if (test.event_click_Dn (BUTTON)) {
if (scr_mode >=5){
scr_mode=1;
scr_clear=true;
}
else {
scr_mode++;
scr_clear=true;
}
}
if (scr_mode == 1){func_main_display();}
if (scr_mode == 2){func_Diag1();}
if (scr_mode == 3){func_Diag2();}
if (scr_mode == 4){func_Diag3();}
if (scr_mode == 5){func_DTC();}
if (curmillis - prevRequest > RequestPeriod && header == 0) {
NOanswer_timer = 1; prev_NOanswer = curmillis; //т.к. сейчас будем делать запрос, то запускаем таймер контроля неответов
if (request == INIT_bus) {K_LINE.end(); delay (450); fastinit();Serial.println ("Bus_INIT");}
else {
byte mesSize;
if (TXmessage[request][0] !=0x80) {mesSize=TXmessage[request][0]; bitWrite (mesSize, 7 , 0);mesSize+=4;}
else mesSize=TXmessage[request][3]+5;
for (byte i = 0; i<mesSize; i++){K_LINE.write(TXmessage[request][i]); delay (delaybyte_TX); K_LINE.read(); } // отправляем соответсвтующий запрос
}
TX_otladka();
prevRequest = curmillis;
}
//разбор входящих сообщений
receive ();
}
//стартовая инициализация PCM на 7 пине ОБД (fast init - 25ms LOW 25ms HIGH)
void fastinit() {
digitalWrite (TX, HIGH); // makes K-line high 3
delay(360); // wait for K-line to be clear 3
digitalWrite (TX, LOW); // makes K-line low 3
delay(25);
digitalWrite (TX, HIGH); // makes K-line high 3
delay(25); //last delay before first message
K_LINE.begin(10400); // baud rate of the OBD
request = INIT; RequestPeriod = 500;
}
//получение данных от ЭБУ, разборка входящих сообщений
void receive () {
if (K_LINE.available() ){
// первый старт байт
if (header == 0 && Delay){TIMER_DELAY ; buf[0]=K_LINE.read();
if (buf[0]!=0xFF && bitRead (buf[0],7)){header = 1; RESETheader_timer =1; prevRESETheader = curmillis;
Serial.print (buf[0], HEX); Serial.print (" "); }}
// второй старт байт
if (header == 1 && Delay){TIMER_DELAY ; buf[1]=K_LINE.read(); Serial.print (buf[1], HEX); Serial.print (" ");if (buf[1]==0xF1){ header = 2;} else {header = 0; RESETheader_timer = 0;}}
// третий старт байт
if (header == 2 && Delay){
TIMER_DELAY ;
buf[2]=K_LINE.read(); Serial.print (buf[2], HEX); Serial.print (" ");
if (buf[2]==0x11){ message_size = buf[0];
if (buf[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; RESETheader_timer = 0;}
}
// если размер сообщения указан в дополнительном байте (нулевой байт 0x80) читаем этот дополнительный байт:
if (header == 3 && Delay){
TIMER_DELAY ;
buf[3]=K_LINE.read(); Serial.print (buf[3], HEX); Serial.print (" ");
message_size = buf[3];
if (message_size > bufsize) message_size = bufsize;
crc = 0; header = 4;
}
// пишем тело сообщения
if (header == 4 && Delay && j< message_size+n+1) {
buf[j] = K_LINE.read();
if (j<message_size+n) crc+= buf[j]; // подсчёт КС
if (j==message_size+n) header = 5;
TIMER_DELAY ; Serial.print (buf[j], HEX); Serial.print (" "); j++;}
}
// сообщение приняли, действуем
if (header == 5) {TIMER_DELAY ;
Serial.println();
NOanswer_timer = 0; noanswers = 0; // сбрасываем таймер контроля неответов
for(byte i = 0; i<n; i++) crc+=buf[i]; // прибавляем к контрольной сумме старт байты
// если контрольная сумма верна:
if ( crc == buf[message_size+n]) {Serial.println("Received message is OK! Checksum is correct!" ); // Если КС совпала, тут чёнибудь нужное делаем
if (buf[n]==0xC1 && buf[n+1]==0xEF && buf[n+2]==0x8F) {request = PID; RequestPeriod = 100; Serial.println (" Initialization OK!!!!: "); }
else if (buf[n]==0x58 && buf[n+1]==0x00) {Serial.println (" NO DTC "); request = PID; RequestPeriod = 100;}
else if (buf[n]==0x58 && buf[n+1] >0x00) {Serial.println (" DTC is found!"); request = PID; RequestPeriod = 100;
for (byte i=0; i<buf[n+1]; i++ ) {
Serial.print("ERROR ");
Serial.print (i+1);
if (!bitRead(buf[n+2+(i*3)],6) && !bitRead(buf[n+2+(i*3)],7)) Serial.print(": P");
if (bitRead(buf[n+2+(i*3)],6) && !bitRead(buf[n+2+(i*3)],7)) Serial.print(": C");
if (!bitRead(buf[n+2+(i*3)],6) && bitRead(buf[n+2+(i*3)],7)) Serial.print(": B");
if (bitRead(buf[n+2+(i*3)],6) && bitRead(buf[n+2+(i*3)],7)) Serial.print(": U");
if (buf[n+2+(i*3)]<=0x0F) Serial.print("0");
Serial.print (buf[n+2+(i*3)],HEX);
if (buf[n+3+(i*3)]<=0x0F) Serial.print("0");
Serial.print (buf[n+3+(i*3)],HEX);
if (bitRead(buf[n+4+(i*3)],7) && bitRead(buf[n+4+(i*3)],6)) {
Serial.print(" -Active-");}
else Serial.print(" -Passive-");
Serial.println();
} }
else if (buf[n]==0x54 && buf[n+1]==0xFF && buf[n+2]==0x00){ Serial.println (" DTC CLEARED "); request = PID; RequestPeriod = 100;}
else if (buf[n]==0x61 && buf[n+1]==0x01) { Serial.println (" Receive DATA");
MAP = ((uint16_t)buf[n+9]*1.04/255.0); //13 байт Датчик абсолютного давления 102mbar
SysVolt = ((float)buf[n+10]/10.00); //14 байт Напряжение в сети 12.1v
{double t , cel , drob ;
t = (buf[n+12]*191ul/255.0)-40; //16 байт Температура воздуха в градусах 50
drob = modf(t, &cel); if (drob>=0.5) cel++;
TempAir = cel;}
{double t , cel , drob ;
t = (buf[n+14]*191ul/255.0)-40; //18 байт Температура охлаждающей жидкости в градусах104
drob = modf(t, &cel); if (drob>=0.5) cel++;
Temp = cel;}
EngLoad = ((uint16_t)buf[n+16]*100/255); //20 байы нагрузка на двигатель7%
Throtle = ((uint16_t)buf[n+24]*100/255); //28 байт Открытие дроссельной заслонки в процентах 0
RPM = ((uint32_t)buf[n+26]*6375ul/255ul); //30 байт Оборогты двигателя 0
Speed = (buf[n+25]); //29 байт Скорость 0
InjPulse = ((float)buf[n+27]*21.8/255.0); //31 байт Время впрыска форсунок 11.9
IdleAir = (buf[n+28]); //32 байт Клапан холостого хода, шаги 38
O2sens =(uint32_t) buf[n+31]*1127ul/255ul; //35 байт Лямбда мВ 380
O2int = (buf[n+32]); //36 байт Интегратор лямда, шагов 128
FuelRatio = ((float)buf[n+37]/10.00); //41 байт Соотношение воздуха/топлива 12.3
STFT = ((buf[n+32]-128)*100/128); // Краткосрочная коррекция топлива
SparkAngel = ((uint16_t)buf[n+15]*180/255-90); //19 байт УОЗ
Cyl1 =((uint16_t)buf[n+19]*90/255); //23 цил1 уменшение УОЗ для уменьшения детонации
Cyl2 =((uint16_t)buf[n+20]*90/255); //24 цил2 уменшение УОЗ для уменьшения детонации
Cyl3 =((uint16_t)buf[n+21]*90/255); //25 цил3 уменшение УОЗ для уменьшения детонации
Cyl4 =((uint16_t)buf[n+22]*90/255); //26 цил4 уменшение УОЗ для уменьшения детонации
FuelHour = (InjPulse*169*RPM*14400/1000/60000/120); // Расход топлива литров в час
FuelKm= (FuelHour/Speed*100ul); // Мгновенный расход топлива на сотню
Serial.print(" MAP=");Serial.print(MAP);Serial.print(" Battery=");Serial.print(SysVolt);
Serial.print(" Air=");Serial.print(TempAir);Serial.print(" Temp=");Serial.print(Temp);
Serial.print(" EngLoad=");Serial.print(EngLoad);Serial.print(" Throtle=");Serial.print(Throtle);
Serial.print(" RPM=");Serial.print(RPM); Serial.print(" Speed=");Serial.print(Speed);
Serial.print(" Inj=");Serial.print(InjPulse);Serial.print(" IdleAir=");Serial.print(IdleAir);
Serial.print(" O2sens=");Serial.print(O2sens);Serial.print(" O2int=");Serial.print(O2int);
Serial.print(" FuelRatio=");Serial.print(FuelRatio);Serial.print(" STFT=");Serial.println(STFT);
Serial.print(" SparkAngel=");Serial.print(SparkAngel);Serial.print(" Cyl1=");Serial.print(Cyl1);
Serial.print(" Cyl2=");Serial.print(Cyl2);Serial.print(" Cyl3=");Serial.print(Cyl3);
Serial.print(" Cyl4=");Serial.print(Cyl4);
Serial.print(" FuelHour=");Serial.print(FuelHour);Serial.print(" FuelKm=");Serial.println(FuelKm);
}
}
// если контрольная сумма не совпала:
else Serial.println("CRC fail!!!" );
message_size = 0; header=0; RESETheader_timer = 0; j=3; crc = 0;
}
// таймер ожидания байт (для успевания появления данных в буфере UART)
if (!Delay && curmillis - timerdelay > waitbyte_RX) Delay = 1;
// таймер сброса заголовка если данные оборвались во время приёма заголовка
if (RESETheader_timer && curmillis - prevRESETheader > 500) {RESETheader_timer = 0; header = 0;}
// если нет ответа после запроса: +1 к счетчику неответов. Если накопилось 6 и более: делаем реинит.
if (NOanswer_timer && curmillis - prev_NOanswer > RequestPeriod - RequestPeriod/8) {NOanswer_timer = 0; noanswers++;
if (noanswers>=6) { noanswers = 0; request = INIT_bus;} }
}
void TX_otladka(){
if (request == INIT_bus) Serial.println ("Bus_INIT");
else if (request == INIT) Serial.println ("Otpravil zapros Init");
else if (request == DTCREAD) Serial.println ("Otpravil zapros DTC read");
else if (request == DTCERASE) Serial.println ("Otpravil zapros DTC clear");
}
void func_main_display()
{
//if ((millis() % 2000) == 0)
//{
if (scr_clear==true){
TV.clear_screen();
scr_clear=false;
TV.bitmap(0, 0, shema);
}
TV.select_font(font8x8ext);
TV.set_cursor(20, 5);
TV.print(TempAir); //температура с наружнего датчика
TV.set_cursor(52, 5);
TV.print(rtc.getTimeStr(FORMAT_SHORT)); // выодим время в формате чч:мм
TV.set_cursor(116, 5);
TV.print(int(rtc.getTemp())); //температура внутри с датчика часов
TV.set_cursor(20, 62);
TV.print(Temp); // температура двигла
TV.set_cursor(49, 62); // ставим курсор
TV.select_font(font6x8);
TV.print(rtc.getDateStr(FORMAT_SHORT)); // выводим дату
TV.set_cursor(118, 62);
TV.print(SysVolt); // выводим Вольтаж
if (Speed >= 10){ //Если скороть больше 10 км/ч
TV.set_cursor(1, 23);
TV.print("INT.CONSUM.:");
TV.print(FuelKm); //Выводим мгновенный расход на сотню
TV.print(" l/100");}
else{
TV.set_cursor(1, 23);
TV.print("INT.CONSUM.:");
TV.print(FuelHour); //Иначе часовой расход
TV.print(" l/h");}
TV.set_cursor(1, 33);
TV.print("STFT :");
TV.print(STFT); //кратоскрочная коррекция
TV.print(" %");
TV.set_cursor(1, 43);
TV.print("ENGINE LOAD:");
TV.print(EngLoad); //нагрузка на двигатель
TV.print(" %");
//}
}
void func_Diag1()
{
if (scr_clear==true){
TV.clear_screen();
scr_clear=false;
}
TV.select_font(font6x8);
TV.set_cursor(20, 0);
TV.print("DIAGNOSTIC MODE 1");
TV.set_cursor(0, 10);
TV.print("AIR TEMP : ");
TV.print(TempAir);
TV.set_cursor(0, 20);
TV.print("ENGINE TEMP: ");
TV.print(Temp);
TV.set_cursor(0, 30);
TV.print("ENGINE LOAD: ");
TV.print(EngLoad);
TV.set_cursor(0, 40);
TV.print("THROTLE : ");
TV.print(Throtle);
TV.set_cursor(0, 50);
TV.print("RPM : ");
TV.print(RPM);
TV.set_cursor(0, 60);
TV.print("SPEED : ");
TV.print(Speed);
}
void func_Diag2()
{
if (scr_clear==true){
TV.clear_screen();
scr_clear=false;
}
TV.select_font(font6x8);
TV.set_cursor(20, 0);
TV.print("DIAGNOSTIC MODE 2");
TV.set_cursor(0, 10);
TV.print("MAP : ");
TV.print(MAP);
TV.set_cursor(0, 20);
TV.print("INJ. PULSE : ");
TV.print(InjPulse);
TV.set_cursor(0, 30);
TV.print("O2 SENSOR : ");
TV.print(O2sens);
TV.set_cursor(0, 40);
TV.print("O2 INTEGRATOR: ");
TV.print(O2int);
TV.set_cursor(0, 50);
TV.print("FUEL RATIO : ");
TV.print(FuelRatio);
TV.set_cursor(0, 60);
TV.print("IDLE AIR : ");
TV.print(IdleAir);
}
void func_Diag3()
{
if (scr_clear==true){
TV.clear_screen();
scr_clear=false;
}
TV.select_font(font6x8);
TV.set_cursor(20, 0);
TV.print("DIAGNOSTIC MODE 3");
TV.set_cursor(0, 10);
TV.print("SPARK ANGEL : ");
TV.print(SparkAngel);
TV.set_cursor(0, 20);
TV.print("DETONATION CYL 1: ");
TV.print(Cyl1);
TV.set_cursor(0, 30);
TV.print("DETONATION CYL 2: ");
TV.print(Cyl2);
TV.set_cursor(0, 40);
TV.print("DETONATION CYL 3: ");
TV.print(Cyl3);
TV.set_cursor(0, 50);
TV.print("DETONATION CYL 4: ");
TV.print(Cyl4);
}
void func_DTC(){
{
if (scr_clear==true){
TV.clear_screen();
scr_clear=false;
}
TV.select_font(font6x8);
TV.set_cursor(40, 0);
TV.print("DTC MODE");
}}
Не разобрался как вывести на экран ошибки DTC. Кнопку повесил на перебор экранов, но вообще их нужно 4-ре. Две для установки часов, две для управления экаранами и стирания ошибок/сброса трипа/сервиса. Мучал и так и эдак, что-то у меня с этой библиотекой не срастается.
И еще вопрос, строка 113, где инициализируем серийник. Он что, софтварный разве? Это ж хардварный серийник в который мы с компа глядим. Если он включен, то экран дергается постоянно. Еслим закоментить, то нормально. После отладки его ж можно будет убрать?
Ну шо, я такой себе радостный, что ECU отвечает адекватно. Запилил вывод на экран... И тут опять облом. Вечный инит. Опять где-то задержки крутить?
нужно проще сначала делать. Просто сначала добавь чисто библу ТВ, смотри будет ли работать. Если да, то усложняй потихоньку (например просто вывод какой-либо фразы на экран), каждый раз проверяя работает ли, чтобы потом понять на каком этапе перестало работать.
Targitai пишет:
Не разобрался как вывести на экран ошибки DTC. Кнопку повесил на перебор экранов, но вообще их нужно 4-ре. Две для установки часов, две для управления экаранами и стирания ошибок/сброса трипа/сервиса. Мучал и так и эдак, что-то у меня с этой библиотекой не срастается.
потом покажу когда заработает.
Targitai пишет:
И еще вопрос, строка 113, где инициализируем серийник. Он что, софтварный разве? Это ж хардварный серийник в который мы с компа глядим. Если он включен, то экран дергается постоянно. Еслим закоментить, то нормально. После отладки его ж можно будет убрать?
Не вижу в строке 113 инита Сериала. Попробуй в свой рабочий скетч с ТВ аут вставить только инит Serial. Если перестанет работать, стало быть ТВ аут не совместим и с хард сериалом, поэтому у тебя рабочий скетч с PCM перестал работать.
Мучал и так и эдак, что-то у меня с этой библиотекой не срастается.
пины кнопок настраиваются так, покажу на примере, где подключены 3 кнопки :
#include <Button.h>
Button test;
#define StartButtonpin 7 // пин старт кнопки 7
#define LEFTButtonpin 8 // пин кнопки лево 8
#define RIGHTButtonpin 9 // пин кнопки право 9
#define StartButton 0
#define LEFTButton 1
#define RIGHTButton 2
void setup() {
test.NO();
test.pullUp();
test.duration_bounce ( 50);
test.duration_click_Db ( 250);
test.duration_inactivity_Up(5000);
test.duration_inactivity_Dn(1000);
test.duration_press ( 500);
// ниже через запятую пишутся пины кнопок, соответственно в скетче программные номера у этих кнопок будут 0, 1 , 2 и т.д. и обращение к ним далее уже будет по программым номера, поэтому выше рядом с дефайнами пинов сделаны дефайны программных номеров:
test.button(StartButtonpin, LEFTButtonpin, RIGHTButtonpin);
}
void loop (){
test.read();
if (test.event_click_Dn (StartButton)){ если нажата старт};
if (test.event_click_Dn (LEFTButton)){ если нажата лево};
if (test.event_click_Dn (RIGHTButton)){ если нажата право};
}
Чет нумерация строк отличается, смотрел в IDE. Я имел ввиду вот этот серийник: serial.begin(115200), это ж тот в который мы смотрим с компа и он будет не нужен в финале, так?
Ок, буду постепенно добавлять и смотреть шо будет.
А с кнопками я смотрел примеры по ссылке, что ты дал.
#include <Button.h>
Button test;
void setup() {
test.NO(); // N.O. Normal Open
// test.NC(); // N.C. Normal Closed
test.pullUp();
// test.pullDn();
test.duration_bounce ( 50);
test.duration_click_Db ( 250);
test.duration_inactivity_Up(5000);
test.duration_inactivity_Dn(1000);
test.duration_press ( 500);
test.button( 5, 4, 9, 7, 8); // arduino pins connected to button
// test.button();
}
void loop() {
test.read();
if (test.state_button (0) == 1) {}
if (test.state_inactivity_Up(0) == 1) {}
if (test.state_inactivity_Dn(0) == 1) {}
if (test.event_click_Up (0) == 1) {}
if (test.event_click_Dn (0) == 1) {}
if (test.event_click_Db (0) == 1) {}
if (test.event_inactivity_Up(0) == 1) {}
if (test.event_inactivity_Dn(0) == 1) {}
if (test.event_press_short (0) == 1) {}
if (test.event_press_long (0) == 1) {}
// test....................(*) == 1) {}
if (test.state_button (4) == 1) {}
if (test.state_inactivity_Up(4) == 1) {}
if (test.state_inactivity_Dn(4) == 1) {}
if (test.event_click_Up (4) == 1) {}
if (test.event_click_Dn (4) == 1) {}
if (test.event_click_Db (4) == 1) {}
if (test.event_inactivity_Up(4) == 1) {}
if (test.event_inactivity_Dn(4) == 1) {}
if (test.event_press_short (4) == 1) {}
if (test.event_press_long (4) == 1) {}
if (test.state_button () == 1) {}
if (test.state_inactivity_Up() == 1) {}
if (test.state_inactivity_Dn() == 1) {}
if (test.event_click_Up () == 1) {}
if (test.event_click_Dn () == 1) {}
if (test.event_click_Db () == 1) {}
if (test.event_inactivity_Up() == 1) {}
if (test.event_inactivity_Dn() == 1) {}
if (test.event_press_short () == 1) {}
if (test.event_press_long () == 1) {}
}
И так же пытался сделать. И одна кнопка на перебор экрана работала, а вторая, по которой по длинному нажатию я хотел заходить в настройку часов - никак. Не могут же define'ы так влиять, это ж чисто для своего удобства мы кнопки обзываем. Хотя подтяжка включилась. Попробую переписать свой старый скеч с часами на эту библиотеку....
с кнопками тоже потренируйся, напиши простой скетч с выводом каждого нажатия в монитор порта . Все сложное нужно начинать с простого. Так проще понять где не работает.
дак смотри в той теме, в последнем посту объяснили, что блокирует UART звуковые функции библиотеки и выложили другую либу, где эти функции вырезаны и теперь типа уарт должен задышать.
ато ТВ-аут не дышит в последних IDE.... Хоть с вырезанными звуковыми функциями. Я еще раз попытаюсь найти тему, где редактируют эту либу. Там вместо макросов заменяют что-то типа /nop /nop и вот тогда IDE ее хавает. Я ночью сидел ковырял и так точно не понял что я сделал :) Но либа заработала на последнем IDE. Хопошо хотть сохранил.
Да и к тому же, там получилось передать по серийнику данные с одной Дуни на другую и вывести на экран, что и будет нужно, если что....
Но либа от BoRKeLSNoRKeL не заработала и я начал в ней ковыряться, сравнивая. Нашел несовпадение в какой-то строке и изменил, после чего все заработало. Вот где нашел разницу - увы, не вспомню. Могу выложить ту либу, что работает под последним IDE и сравнить ее с порезанной на звук, если поможет.
Таки все же ТВ аут виноват. Если уменьшить разрешение экрана до 128*96, то можно вывести аж целую одну цифру на экран. Начинаешь еще что-то добавлять - и все.
Попробовал сделать через pollserial. Экран мерцает даже с отключенным монитором порта (serial0) (на машине не пробовал). На тему про pollserial натукнулся тут: https://forum.arduino.cc/index.php?topic=412718.msg2842942#msg2842942 Там же поправленная библиотека, чтобы его на Мега можно было назначить на любой serial
Сейчас поковырялся в либе, которая без звука. Завтра испытаю на машине.
Но такой вопрос - а на столе то должно работать? Если в Уно загрузить скетч эмулятора нашего ECU, ну и соединить все через k-line адаптеры? Т.е. чтоб Мега сейчас выступала в роли OP-COM K-Line? А то что-то у меня так не фурычит...
PS... заказал Нано на всякий случай. Но пока можно будет попробовать в качестве видеодрайвера Уно. Как бы скетч дописать для отправки пакета с одной на другую и разбором сообщений....
PPS... А кстати, если получится с двумя Ардуинами, то выйдет даже неплохо. Тогда можно две Нано будет использовать. И места меньше занимают, и дешевле. Итоговый скеч для приема данных от ЭБУ машины вполне вмещается в Уно (Нано же столько же памяти имеет).
Но такой вопрос - а на столе то должно работать? Если в Уно загрузить скетч эмулятора нашего ECU, ну и соединить все через k-line адаптеры? Т.е. чтоб Мега сейчас выступала в роли OP-COM K-Line? А то что-то у меня так не фурычит...
да так должно работать. Может 12В забыл подать на к-лайн адаптеры?
Targitai пишет:
PS... заказал Нано на всякий случай. Но пока можно будет попробовать в качестве видеодрайвера Уно. Как бы скетч дописать для отправки пакета с одной на другую и разбором сообщений....
дак по какой шине данные то передавать? по Serial? получается от чего ушли к тому и пришли. ТВ то блокирует Serial. По SPI нужно пробовать будет ли она работать с ТВ аут
да так должно работать. Может 12В забыл подать на к-лайн адаптеры?
Аднака на хочет, чтоб его! Напряжение подавал, ессно. Я эту схему скоро по среди ночи с закрытими глазами уже собирать буду....
MaksVV пишет:
дак по какой шине данные то передавать? по Serial? получается от чего ушли к тому и пришли. ТВ то блокирует Serial. По SPI нужно пробовать будет ли она работать с ТВ аут
Ну так вот в той теме то получилось по Сериал передать. Используя библиотеку pollserial. И тут ведь у меня хотя б одну цифру передать получилось, значит все же не совсем блокирует, просто своими прерываниями влияет на наши. А их в скетче слишком много. Если же Ардуина будет без лишних задержек принимать и просто выводить на экран данные, то, думаю, может и получится. Можно же на столе проверить. Мега в качестве эмулятора работы, Уно в качестве видеодрайвера.
Аднака на хочет, чтоб его! Напряжение подавал, ессно. Я эту схему скоро по среди ночи с закрытими глазами уже собирать буду....
могу только предположить, что на меге к-лайн повесил на софтсериал 7,8 (софтсериал на 7,8 на меге не пашет). А если на меге Сериал3 у меня всё работает. скетч диаг #1325 и эмуль #1205
Помогите разобраться в данной проблеме: При использовании rx tx на пинах 0 1 , соединяется с opendiag. При использовании SoftSerial на 10 и 11 пин информация , Opendiag перестает видеть. Гугл говорит что не понимает скорость 10400. Решения которое там есть( Внести изменение в SoftSerial....cpp) устарело. Нету данной таблицы уже там.
Скетч выложите, оба. (кстати, сразу возьмите за правило его выкладывать).
У меня работало на пинах 8,9 и 12,13 без проблем. А вот при переходе на Мега и хардварный сериал, пришлось вновь вылавливать задержки при инициализации. Возможно, у вас такой же случай - задержки.
Библиотека софт сериал не совместима с тв оут. Надо ждать мегу и использовать хард сериал
Опаньки, вот это обнадежил. А Мега пришла буквально позавчера. Я просто такого нюанса как-то не учел, и думал вдруг втиснемся в память Уно. Но если такие пироги, перехожу на нее.
По идее по протоколу ТС делали считывание ошибок. Там определенные биты отвечают за пассивный DTC или активный. Но тут видимо чето отличается, поэтому он не пишет passive или active
На Мега запустилось, но буковки прыгают каждый раз при посылке запроса.... Как там на hardvare serial перейти?
Все, разобрался. #define mySerial Serial1
Как-то Оп-ком и Опель-сканер смотрят активная или пассивная. Да в принципе, не большая проблема. Если на приборке Джеки-чан горит, значит есть активная ошибка. Если посыпался ворох, то стер и смотришь что вылезет снова.
Дак считай ошибку когда она активна и когда пассивна, посмотрим что там в ответе отличается.
В конечном скече нужно будет делать проверку и fastinit(); повторять если, например, после пяти секунд отправки запроса Init ничего не меняется. Мало ли из-за чего связь прервется. Сейчас, например, если включить Дуню, а потом зажигание, то ничего не добьешья.
так попробуй
По софт-сериал коннектится, а по хардварному - нет. Кстати, на Дуне написано пин 18 - RX1, 19 - TX1. Но все равно никак. Пишет только «отправил запрос инит». Т.е. в скетче ставил 19. Поменял местами пины, ну а вдруг. Просто увидел ещё что шлёт запрос 81 11 F1 81Otpravil zapros Init и тд.
походу есть китайские меги с перепутанными TX1 и RX1 судя по фотам в сети. Поменяй на TX3 RX3
строка 10 и 11 будет
Менял на Serial2. Попробую, конечно, на 3 поменять...
Читаю, у многих проблемы с хардварными 10400 бод. Как бы проверить двумя Дунями? На столе, так сказать
#1306 поправил на сериал3. Должно работать. Внимательней с подключением. А на софтверном работало на этом же скетче?
Значится, по софтсериал. Работает. Но повторное подключение при обрыве связи не происходит. Решил проблему добавление задержки в строке 116 перед fastinit:
Так отлично работает.
Теперь оп хардварному. Если оставить все как есть то выдает только следующее:
Почему мы вообще видим часть запроса инициализации?
Далее я предположил, что это из-за того, что мы сперва стартуем наш серийный порт, а потом уже на скорости 10400 шлем fastinit, и действительно оказалось это так. В общем, вот скетч:
С этим скетчем получаем вот такую картину:
Я так понимаю, проблема кроется в задержках? Но вот где какую крутить? Поигрался с byte waitbyte_RX = 1; ставил вплоть до 100. Но не помогло. Видать на Марсе жизни нет :)
Строка 290 попробуй задержку более 500
Также попробовать строка 125 после delay поставить
K_LINE.read помогло. Заработало!
только теперь на кнопку ее реагирует никак. Запросы не чтение и стирание ошибок не шлёт ))))
Это по тойже причине. Аналогично нужнг вставить клайн.Реад и в те requestы. Причина в том что шина к лайн эхо даёт и мы в приёмнике видим свои отправленные мессаги . клайн.Реад вычитывает мусорные эхо байты сразу после отправки и освобождает приемный буфер для приёма уже нужных байтов от оппонента. Вопрос почему на софтсериале работало
UPDATE. а вообще я нечаянно снёс опрос кнопки (вставить в первую строку цикла loop() )
можно еще так попробовать
Отлично работает 1316. Переподключается, все читает, все сбрасывает и даже определил активную ошибку.
Было:
Снял реле топливного насоса, и стало:
Поставил реле назад:
Вот смотрю на код распознования ошибки и в упор не могу его понять. А хотелось бы для общего развития:
Далее захотел все же добавить УОЗ, добавил так:
SparkAngel показывает правильно, а по цилиндрам по нулям. Потому не уверен, может оно только на ходу будет видно?
И еще формула часового расхода, которая была найдена для программы Torque под двигатель z16xe, почему-то у меня показывает ноль:
Понятно, что с коэффициентами поиграться нужно будет и подобрать, но вот, например, при таких параметрах:
FuelHour=(((3.25/1000)*(169/60000)*(850/120)*14400)= 0,933725 л/ч а у меня ноль. (((
Сначала все умножать, а потом делить
По цилиндрам это не уоз, а уменьшение уоз. Здесь показания должны увеличиваться при наличии детонации. Резко дать газу и возможно параметр будет больше нуля.
Работает! И вроде даже совпадает со штатным бортовиком, но это нужно смотреть уже с экрана, поставив два рядышком, а то в ноут отвлекаться в бегущие строчки не айс.
Осталось только средний расход на сотню как-то сделать. Жаль, конечно, что одновременно с приборкой невозможна работа. Хотя от приборки всего то можно было бы сделать остаток пути на баке и напоминалку о замене масла...
да почему, можно и приборку добить. вот чуть правленый скетч, добавил passive DTC , и убрал балласт из массива TX сообщений
Осталось только средний расход на сотню как-то сделать.
Это просто. Правда это будет мгновенный расход на сотню
Да мгновенный я то сделал, в логе есть. FuelKm=inf - когда стоим, А когда трогаемся, немного пугает :)))
На скорости 1 км/ч расход 301 литр :)
Ну собственно, средний на сотню можно ж и без приборки. Расстояние ж равно скорость на время. Время можно хоть миллис использовать, хоть часики, у меня ж будут DS3231.
А с приборкой ж непонятка. Мало того, что последняя версия скеча не работала, так еще и переделывать из-за hardware serial.
а когда стоим., расход на сотню вообще бесконечность . и это нормально.поэтому если скорость ниже 10, можно просто выводить 99 чтоб двузначное число было.
Ну собственно, средний на сотню можно ж и без приборки. Расстояние ж равно скорость на время. Время можно хоть миллис использовать, хоть часики, у меня ж будут DS3231.
Не не, просто делаем условие - при скорости меньше 10 км/ч показывает л/ч, при большей - л/100.
Ну у нас и не звездолет чтоб так все считать. Грубо говоря, раз в 5-10 секунд расчитываем пройденное расстояние и складируем в массив. Потом находим среднее из массива. Вопрос, правда, в ОЗУ. Для более точных значений нужен большой массив. С приборкой же тоже не все так гладко - полезли в нее, потеряли связь с ЭБУ. Есть, правда, вариант подключиться вторым k-line адаптером к самой приборке. Но вариант не очень, т.к. тогда ее от OBD разъема придется отключить и сторонние сканеры уже не увидят...
Попробую залить последний рабочий скетч по приборке, переведя его на хардварный серийник, посмотрим что будет.
ЗыЖ.... кстати так же можно реализовать Long Term Fuel Trim. Было бы очень неплохо.
Проверил на всякий случай скетч 1321. Правда, ошибки забыл глянуть, ну да думаю будет работать. Добавил в него свои формулы по УОЗ и расходу. Кстати, обратил внимание, если STFT = (((uint16_t)buf[n+32]-128)*100/128); вот так, то формула работает неправильно. А если убрать (uint16_t), то все отлично.
В общем, получается финальный скетч (а то постоянно формулы прописываю :) ):
По поводу приборки. Последний рабочий скеч, который без периодического опроса, по софтсериалу переделал на хард так:
И получил только так:
С приборкой же тоже не все так гладко - полезли в нее, потеряли связь с ЭБУ. Есть, правда, вариант подключиться вторым k-line адаптером к самой приборке. Но вариант не очень, т.к. тогда ее от OBD разъема придется отключить и сторонние сканеры уже не увидят...
кстати вариант хороший. Отрезать приборку от обд. Поставить переключаюший тумблер да и всё, чтоб диагностику можно было подклчючать.
по приборке пока такой скетч
если не заработает. пробовать регулировать задержки в строках 9 , 51, 53
Строка 9, наилучший результат при задержке 3 мс. Хватает 4 правильных результата. Но в любом случае, конектиться только со второго раза.
Лог:
Скеч:
Ну шо, я такой себе радостный, что ECU отвечает адекватно. Запилил вывод на экран... И тут опять облом. Вечный инит. Опять где-то задержки крутить? Вот такой скеч:
Не разобрался как вывести на экран ошибки DTC. Кнопку повесил на перебор экранов, но вообще их нужно 4-ре. Две для установки часов, две для управления экаранами и стирания ошибок/сброса трипа/сервиса. Мучал и так и эдак, что-то у меня с этой библиотекой не срастается.
И еще вопрос, строка 113, где инициализируем серийник. Он что, софтварный разве? Это ж хардварный серийник в который мы с компа глядим. Если он включен, то экран дергается постоянно. Еслим закоментить, то нормально. После отладки его ж можно будет убрать?
Ну шо, я такой себе радостный, что ECU отвечает адекватно. Запилил вывод на экран... И тут опять облом. Вечный инит. Опять где-то задержки крутить?
нужно проще сначала делать. Просто сначала добавь чисто библу ТВ, смотри будет ли работать. Если да, то усложняй потихоньку (например просто вывод какой-либо фразы на экран), каждый раз проверяя работает ли, чтобы потом понять на каком этапе перестало работать.
Не разобрался как вывести на экран ошибки DTC. Кнопку повесил на перебор экранов, но вообще их нужно 4-ре. Две для установки часов, две для управления экаранами и стирания ошибок/сброса трипа/сервиса. Мучал и так и эдак, что-то у меня с этой библиотекой не срастается.
потом покажу когда заработает.
И еще вопрос, строка 113, где инициализируем серийник. Он что, софтварный разве? Это ж хардварный серийник в который мы с компа глядим. Если он включен, то экран дергается постоянно. Еслим закоментить, то нормально. После отладки его ж можно будет убрать?
Не вижу в строке 113 инита Сериала. Попробуй в свой рабочий скетч с ТВ аут вставить только инит Serial. Если перестанет работать, стало быть ТВ аут не совместим и с хард сериалом, поэтому у тебя рабочий скетч с PCM перестал работать.
пины кнопок настраиваются так, покажу на примере, где подключены 3 кнопки :
Чет нумерация строк отличается, смотрел в IDE. Я имел ввиду вот этот серийник: serial.begin(115200), это ж тот в который мы смотрим с компа и он будет не нужен в финале, так?
Ок, буду постепенно добавлять и смотреть шо будет.
А с кнопками я смотрел примеры по ссылке, что ты дал.
И так же пытался сделать. И одна кнопка на перебор экрана работала, а вторая, по которой по длинному нажатию я хотел заходить в настройку часов - никак. Не могут же define'ы так влиять, это ж чисто для своего удобства мы кнопки обзываем. Хотя подтяжка включилась. Попробую переписать свой старый скеч с часами на эту библиотеку....
да это для отладки серийник, потом не нужен будет. Просто если с ним косяки, то и с Serial1 Serial2 Serial3, наверное, тоже самое будет.
с кнопками тоже потренируйся, напиши простой скетч с выводом каждого нажатия в монитор порта . Все сложное нужно начинать с простого. Так проще понять где не работает.
Да нет, его заккоментил и картинка прекратила дергаться. Хотя, может ты и прав и из-за ТВ-аут проблемы. Проверим.
На крайняк уже смирился со второй Дуней для вывода изображения.
только как ей данные передавать? по сериал? ))))
есть ещё SPI и i2С . Надеюсь их твой ТВ аут не глушит. но моя не уметь этим пользоваться
"только как ей данные передавать? по сериал? ))))"
Таки да, почти. даже с этого сайта: http://arduino.ru/forum/programmirovanie/peredacha-dannykh-po-uart-pri-aktivnom-tvout
Но пока начну с постепенного добавления в скетч функций и посмотрю где начнется косяк. Немного занят, надеюсь завтра занятся.
дак смотри в той теме, в последнем посту объяснили, что блокирует UART звуковые функции библиотеки и выложили другую либу, где эти функции вырезаны и теперь типа уарт должен задышать.
ато ТВ-аут не дышит в последних IDE.... Хоть с вырезанными звуковыми функциями. Я еще раз попытаюсь найти тему, где редактируют эту либу. Там вместо макросов заменяют что-то типа /nop /nop и вот тогда IDE ее хавает. Я ночью сидел ковырял и так точно не понял что я сделал :) Но либа заработала на последнем IDE. Хопошо хотть сохранил.
Да и к тому же, там получилось передать по серийнику данные с одной Дуни на другую и вывести на экран, что и будет нужно, если что....
Ага, вот, отсюда я начал: https://github.com/sheaivey/rx5808-pro-diversity/issues/89
Но либа от BoRKeLSNoRKeL не заработала и я начал в ней ковыряться, сравнивая. Нашел несовпадение в какой-то строке и изменил, после чего все заработало. Вот где нашел разницу - увы, не вспомню. Могу выложить ту либу, что работает под последним IDE и сравнить ее с порезанной на звук, если поможет.
Таки все же ТВ аут виноват. Если уменьшить разрешение экрана до 128*96, то можно вывести аж целую одну цифру на экран. Начинаешь еще что-то добавлять - и все.
Попробовал сделать через pollserial. Экран мерцает даже с отключенным монитором порта (serial0) (на машине не пробовал). На тему про pollserial натукнулся тут: https://forum.arduino.cc/index.php?topic=412718.msg2842942#msg2842942 Там же поправленная библиотека, чтобы его на Мега можно было назначить на любой serial
Сейчас поковырялся в либе, которая без звука. Завтра испытаю на машине.
Но такой вопрос - а на столе то должно работать? Если в Уно загрузить скетч эмулятора нашего ECU, ну и соединить все через k-line адаптеры? Т.е. чтоб Мега сейчас выступала в роли OP-COM K-Line? А то что-то у меня так не фурычит...
PS... заказал Нано на всякий случай. Но пока можно будет попробовать в качестве видеодрайвера Уно. Как бы скетч дописать для отправки пакета с одной на другую и разбором сообщений....
PPS... А кстати, если получится с двумя Ардуинами, то выйдет даже неплохо. Тогда можно две Нано будет использовать. И места меньше занимают, и дешевле. Итоговый скеч для приема данных от ЭБУ машины вполне вмещается в Уно (Нано же столько же памяти имеет).
Но такой вопрос - а на столе то должно работать? Если в Уно загрузить скетч эмулятора нашего ECU, ну и соединить все через k-line адаптеры? Т.е. чтоб Мега сейчас выступала в роли OP-COM K-Line? А то что-то у меня так не фурычит...
да так должно работать. Может 12В забыл подать на к-лайн адаптеры?
PS... заказал Нано на всякий случай. Но пока можно будет попробовать в качестве видеодрайвера Уно. Как бы скетч дописать для отправки пакета с одной на другую и разбором сообщений....
дак по какой шине данные то передавать? по Serial? получается от чего ушли к тому и пришли. ТВ то блокирует Serial. По SPI нужно пробовать будет ли она работать с ТВ аут
да так должно работать. Может 12В забыл подать на к-лайн адаптеры?
Аднака на хочет, чтоб его! Напряжение подавал, ессно. Я эту схему скоро по среди ночи с закрытими глазами уже собирать буду....
дак по какой шине данные то передавать? по Serial? получается от чего ушли к тому и пришли. ТВ то блокирует Serial. По SPI нужно пробовать будет ли она работать с ТВ аут
Ну так вот в той теме то получилось по Сериал передать. Используя библиотеку pollserial. И тут ведь у меня хотя б одну цифру передать получилось, значит все же не совсем блокирует, просто своими прерываниями влияет на наши. А их в скетче слишком много. Если же Ардуина будет без лишних задержек принимать и просто выводить на экран данные, то, думаю, может и получится. Можно же на столе проверить. Мега в качестве эмулятора работы, Уно в качестве видеодрайвера.
Аднака на хочет, чтоб его! Напряжение подавал, ессно. Я эту схему скоро по среди ночи с закрытими глазами уже собирать буду....
могу только предположить, что на меге к-лайн повесил на софтсериал 7,8 (софтсериал на 7,8 на меге не пашет). А если на меге Сериал3 у меня всё работает. скетч диаг #1325 и эмуль #1205
Помогите разобраться в данной проблеме: При использовании rx tx на пинах 0 1 , соединяется с opendiag. При использовании SoftSerial на 10 и 11 пин информация , Opendiag перестает видеть. Гугл говорит что не понимает скорость 10400. Решения которое там есть( Внести изменение в SoftSerial....cpp) устарело. Нету данной таблицы уже там.
А opendiag на какой скорости с компом коннектиться? Зачем вам 10400 скорость?
А opendiag на какой скорости с компом коннектиться? Зачем вам 10400 скорость?
Для извлечения данных с ЭбУ(Январь 5.1). На скорости 10400(По умолчанию)
Подождите, вы Ардуино с чем соединяете? С ЭБУ? Если да, то прекрасно работает софт-сериал на 10400. При чем тут opendiag?
И Ардуино какая?
Подождите, вы Ардуино с чем соединяете? С ЭБУ? Если да, то прекрасно работает софт-сериал на 10400. При чем тут opendiag?
И Ардуино какая?
Uno ATmega 16U2. Для проверки использую данную программу.
Скетч выложите, оба. (кстати, сразу возьмите за правило его выкладывать).
У меня работало на пинах 8,9 и 12,13 без проблем. А вот при переходе на Мега и хардварный сериал, пришлось вновь вылавливать задержки при инициализации. Возможно, у вас такой же случай - задержки.