Данные из K-line Эбу

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

кстати раз 328 вытаскивается, просто соединяете к-лайн адаптер к пинам 0 и 1 и вытаскиваете атмегу, и получаете юсб-клайн адаптер - можно опендиагом работать. 

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

TWANs пишет:
Получается когда мы пишем Softwareserial (8 ,9) мы подключаем к 8 rx а к 9 tx? Сейчас проверю пойду 25.

да

TWANs
Offline
Зарегистрирован: 08.02.2019

Взял #25 залил его подключил в 10 rx в 11 tx. Он сказал что обнаружил адаптер, но при попытке считать данные он пишет не удалось открыть порт. 

С другой стороны если не так собрана схема то , по идее, она бы не показывала данные с блока?

PRC
Offline
Зарегистрирован: 03.02.2019

Теперь пробуй 27))) Тоько про подключение 8,9 не забывай))

TWANs
Offline
Зарегистрирован: 08.02.2019

Попробовал #27 с изменением строчки. Так же говорит что адаптер есть а порт открыть не может 

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

не стоит в опендиаге определять к-лайн адаптер, не найдет он его. Но работать БУДЕТ. 

TWANs
Offline
Зарегистрирован: 08.02.2019

MaksVV пишет:

не стоит в опендиаге определять к-лайн адаптер, не найдет он его. Но работать БУДЕТ. 

 

Вот. Теперь сделаем маленький шаг вперёд. И 25 и 27 получается работает. Вчерашний протокол я прочитал так же пробежался по протоколу мозгов(АвтоВАЗ). Теперь мне получается нужно найти алгоритм запроса данных.

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

TWANs пишет:

Попробовал #27 с изменением строчки. Так же говорит что адаптер есть а порт открыть не может 

скрин скиньте что говорит опендиаг, не понятно что вы имеете ввиду

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

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

#include <SoftwareSerial.h>

SoftwareSerial K_LINE(10, 11); // RX, TX

byte StartSession[] = {0x81, 0x10, 0xF1, 0x82, 0x04};

void setup() {
 Serial.begin(9600);
 K_LINE.begin(10400);
  delay (2000);
K_LINE.write(StartSession, sizeof (StartSession));
             }

void loop()  { 
  if (K_LINE.available()) {Serial.print(K_LINE.read(), HEX); Serial.print(" ");}
  
             }

 

TWANs
Offline
Зарегистрирован: 08.02.2019

TWANs пишет:

 

Исполтзовал #41 скетч , только пины были 8 и 9.

 

 

Вот такое сообщение выдает. В самом низу окна Opendiag написаного : Не удалось открыть открыть порт 

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

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

#include <SoftwareSerial.h>

SoftwareSerial K_LINE(10, 11); // RX, TX

const byte PCMaddress = 0x10; // адрес эбу

byte header = 0;          // состояние заголовка 
byte message_size = 0;    // размер тела принимаемого сообщения, кол-во байт

byte j = 2;               // инкремент
byte n = 2;
const byte bufsize = 140;  // размер буфера принятого сообщения
byte buf [bufsize] = {0};  // буфер принятого сообщения
byte checksum = 0;         // контрольная сумма входящего сообщения
uint32_t curmillis = 0;    // снимок системного времени
byte delaybyte_TX = 0 ;    // задержка между байтами отправляемого сообщения 
byte waitbyte_RX = 1;      // задержка, мс для успевания заполнения буфера RX (подрегулировать в зависимости от уровня жизнидеятельности на Марсе)
uint32_t timerdelay = 0;   // таймер ожидания байт (для успевания заполнения буфера УАРТ)
bool Delay = 0;            // таймер ожидания байт (для успевания заполнения буфера УАРТ)
#define TIMER_DELAY Delay = 0; timerdelay = curmillis  // включение этого таймера

uint32_t prevRESETheader=0; // таймер сброса заголовка если в момент приёма сообщения данные оборвались
bool RESETheader_timer = 0; // таймер сброса заголовка если в момент приёма сообщения данные оборвались



//**************************** команды, посылаемые на ЭБУ

byte StartSession[] = {0x82};  // команда на старт диагностики (может также быть 81)


//****************************


void setup() {
 Serial.begin(9600);      // настойки монитора порта отладки
 K_LINE.begin(10400);     // настройки шины к-лайн
  delay (2000);
SendMessage (StartSession, sizeof (StartSession));
             }

void loop()  { 
  curmillis = millis(); // снимок системного времени 
 
 K_LINEread();          // читаем шину к-лайн
 
  
             }




void SendMessage (const byte *command, const size_t size){
const byte siZe = size+4;
  byte Mes[siZe];
  byte Checksum = 0;
  for(byte i=0; i<siZe; i++) {
    if (i==0) {Mes[i]=size; bitWrite(Mes[i], 7 , 1);}
    if (i==1) Mes[i] = PCMaddress;
    if (i==2) Mes[i] = 0xF1;    
    if (i==3) {for (byte t=0; t<size; t++ ) {Mes[i]=command[t]; Checksum+=Mes[i] ;K_LINE.write (Mes[i]);  i++;}}
    if (i!=siZe-1) Checksum+=Mes[i];
    else Mes[i] = Checksum;    
    K_LINE.write (Mes[i]); 
      }
}


void K_LINEread () {

if (K_LINE.available()){
    
    

 // первый старт байт
 if (header == 0 && Delay){TIMER_DELAY ; buf[0]=K_LINE.read(); 
         if (!bitRead (buf[0],6) && bitRead (buf[0],7)){header = 1; RESETheader_timer=1; prevRESETheader = curmillis; }
         
         }                  

 // второй старт байт
 if (header == 1 && Delay){TIMER_DELAY ; buf[1]=K_LINE.read(); if (buf[1]==0xF1){ header = 2;} else {header = 0; RESETheader_timer=0;}} 

 // третий старт байт
 if (header == 2 && Delay){ 
  TIMER_DELAY ;
  buf[2]=K_LINE.read(); 
  if (buf[2]==PCMaddress){ message_size = buf[0]; 
  if (buf[0] !=0x80) {header = 4;  message_size&=~0x80; j=3; n=3;}
  else {header = 3; j=4;n=4;}
  if (message_size > bufsize) message_size = bufsize;  checksum = 0;} else {header = 0; RESETheader_timer=0; }
  
                          }  
// если размер сообщения указан в дополнительном байте (нулевой байт 0x80) читаем этот дополнительный байт:
if (header == 3 && Delay){
  TIMER_DELAY ;
  buf[3]=K_LINE.read(); 
  message_size = buf[3]; 
  if (message_size > bufsize) message_size = bufsize;  
  checksum = 0; header = 4;  
                         }

  // пишем тело сообщения 
 if (header == 4 && Delay && j< message_size+n+1) {
 buf[j] = K_LINE.read(); 
 if (j<message_size+n) checksum+= buf[j]; // подсчёт КС
 
 if (j==message_size+n) header = 5; 
 TIMER_DELAY ; j++;} 

 } // end of K_LINE.available()

 // сообщение приняли, действуем
 if (header == 5) {TIMER_DELAY ;  

for(byte i = 0; i<n; i++) checksum+=buf[i]; // прибавляем к контрольной сумме старт байты

Serial.print (F("Receive from PCM:     "));
for (byte i=0; i<message_size+n+1; i++) {if (buf[i]<= 0x0F) Serial.print (F("0")); Serial.print (buf[i], HEX); Serial.print(" ");} // Отладка в монитор порта
Serial.println();

 // если контрольная сумма верна: 
if (buf[message_size+n] == checksum) {
  

  
// ТУТ ЧТО НИБУДЬ ДЕЛАЕМ КОГДА ПОЛУЧИЛИ СООБЩЕНИЕ ОТ ЭБУ 
  
  
  }   

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



// таймер ожидания байт (для успевания появления данных в буфере UART)
if (!Delay && curmillis - timerdelay > waitbyte_RX) Delay = 1; 

// таймер сброса заголовка если данные оборвались во время приёма заголовка
if (RESETheader_timer && curmillis - prevRESETheader > 500) {RESETheader_timer = 0; header = 0;}  
}

 

 

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

а вот скетч с периодическим запросом параметров. Уж что с ними делать сами разбирайтесь. (я в ответе от ЭБУ запарсил только t ДВС, см. строка 140) Кстати полезная ссылка

#include <SoftwareSerial.h>

SoftwareSerial K_LINE(10, 11); // RX, TX

const byte PCMaddress = 0x10; // адрес эбу

byte header = 0;          // состояние заголовка 
byte message_size = 0;    // размер тела принимаемого сообщения, кол-во байт

byte j = 2;               // инкремент
byte n = 2;
const byte bufsize = 140;  // размер буфера принятого сообщения
byte buf [bufsize] = {0};  // буфер принятого сообщения
byte checksum = 0;         // контрольная сумма входящего сообщения
uint32_t curmillis = 0;    // снимок системного времени
byte delaybyte_TX = 0 ;    // задержка между байтами отправляемого сообщения 
byte waitbyte_RX = 1;      // задержка, мс для успевания заполнения буфера RX (подрегулировать в зависимости от уровня жизнидеятельности на Марсе)
uint32_t timerdelay = 0;   // таймер ожидания байт (для успевания заполнения буфера УАРТ)
bool Delay = 0;            // таймер ожидания байт (для успевания заполнения буфера УАРТ)
#define TIMER_DELAY Delay = 0; timerdelay = curmillis  // включение этого таймера

uint32_t prevRESETheader=0; // таймер сброса заголовка если в момент приёма сообщения данные оборвались
bool RESETheader_timer = 0; // таймер сброса заголовка если в момент приёма сообщения данные оборвались


uint32_t prevtimeRequest = 0; 
uint16_t  periodRequest = 1000;   // периодичность запроса параметров ЭБУ, мс
bool Init = 0; 
uint32_t prevInit = 0; 

int Temperature; 


//**************************** команды, посылаемые на ЭБУ

byte StartSession[] =  {0x81};           // команда на старт диагностики (может также быть 82)
byte DataRequest[]  =  {0x21, 0x01};     // команда на запрос параметров

//****************************


void setup() {
 Serial.begin(9600);      // настойки монитора порта отладки
 K_LINE.begin(10400);     // настройки шины к-лайн
  delay (2000);
             }

void loop()  { 
  curmillis = millis(); // снимок системного времени 
 
 K_LINEread();          // читаем шину к-лайн

 if (curmillis - prevtimeRequest > periodRequest) { // периодически делаем запрос параметров
  
       if (Init) SendMessage (DataRequest,  sizeof (DataRequest));
       else      SendMessage (StartSession, sizeof (StartSession));
  prevtimeRequest = curmillis;}

 if (curmillis - prevInit > 10000) {Init =0; prevInit=curmillis;}     // периодически делаем сброс инита, если ЭБУ не отвечает
             }




void SendMessage (const byte *command, const size_t size){
const byte siZe = size+4;
  byte Mes[siZe];
  byte Checksum = 0;
  for(byte i=0; i<siZe; i++) {
    if (i==0) {Mes[i]=size; bitWrite(Mes[i], 7 , 1);}
    if (i==1) Mes[i] = PCMaddress;
    if (i==2) Mes[i] = 0xF1;    
    if (i==3) {for (byte t=0; t<size; t++ ) {Mes[i]=command[t]; Checksum+=Mes[i] ;K_LINE.write (Mes[i]);  i++;}}
    if (i!=siZe-1) Checksum+=Mes[i];
    else Mes[i] = Checksum;    
    K_LINE.write (Mes[i]); 
      }
}


void K_LINEread () {

if (K_LINE.available()){
    
    

 // первый старт байт
 if (header == 0 && Delay){TIMER_DELAY ; buf[0]=K_LINE.read(); 
         if (!bitRead (buf[0],6) && bitRead (buf[0],7)){header = 1; RESETheader_timer=1; prevRESETheader = curmillis; }
         
         }                  

 // второй старт байт
 if (header == 1 && Delay){TIMER_DELAY ; buf[1]=K_LINE.read(); if (buf[1]==0xF1){ header = 2;} else {header = 0; RESETheader_timer=0;}} 

 // третий старт байт
 if (header == 2 && Delay){ 
  TIMER_DELAY ;
  buf[2]=K_LINE.read(); 
  if (buf[2]==PCMaddress){ message_size = buf[0]; 
  if (buf[0] !=0x80) {header = 4;  message_size&=~0x80; j=3; n=3;}
  else {header = 3; j=4;n=4;}
  if (message_size > bufsize) message_size = bufsize;  checksum = 0;} else {header = 0; RESETheader_timer=0; }
  
                          }  
// если размер сообщения указан в дополнительном байте (нулевой байт 0x80) читаем этот дополнительный байт:
if (header == 3 && Delay){
  TIMER_DELAY ;
  buf[3]=K_LINE.read(); 
  message_size = buf[3]; 
  if (message_size > bufsize) message_size = bufsize;  
  checksum = 0; header = 4;  
                         }

  // пишем тело сообщения 
 if (header == 4 && Delay && j< message_size+n+1) {
 buf[j] = K_LINE.read(); 
 if (j<message_size+n) checksum+= buf[j]; // подсчёт КС
 
 if (j==message_size+n) header = 5; 
 TIMER_DELAY ; j++;} 

 } // end of K_LINE.available()

 // сообщение приняли, действуем
 if (header == 5) {TIMER_DELAY ;  

for(byte i = 0; i<n; i++) checksum+=buf[i]; // прибавляем к контрольной сумме старт байты

Serial.print (F("Receive from PCM:     "));
for (byte i=0; i<message_size+n+1; i++) {if (buf[i]<= 0x0F) Serial.print (F("0")); Serial.print (buf[i], HEX); Serial.print(" ");} // Отладка в монитор порта
Serial.println();

 // если контрольная сумма верна: 
if (buf[message_size+n] == checksum) {
    prevInit=curmillis; // сбрасываем таймер сброса инита, если получили хоть какое-то сообщение от ЭБУ

     if (buf[n]==0xC1) Init=1;  // если пришёл ответ на запрос инита, делаем инит прошёл успешно

// ниже если получили длинный ответ от ЭБУ с параметрами парсим его, я взял только температуру   ДВС
else if (buf[n]==0x61 && buf[n+1]==0x01){ Temperature = buf[n+10]-40; Serial.print(F("TempEngine: ")); Serial.println (Temperature);}

// ТУТ ЧТО НИБУДЬ ДЕЛАЕМ КОГДА ПОЛУЧИЛИ СООБЩЕНИЕ ОТ ЭБУ 
  
  
  }   

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



// таймер ожидания байт (для успевания появления данных в буфере UART)
if (!Delay && curmillis - timerdelay > waitbyte_RX) Delay = 1; 

// таймер сброса заголовка если данные оборвались во время приёма заголовка
if (RESETheader_timer && curmillis - prevRESETheader > 500) {RESETheader_timer = 0; header = 0;}  
}

 

TWANs
Offline
Зарегистрирован: 08.02.2019

Спасибо! Все работает.(:

Mike_Levin_
Offline
Зарегистрирован: 16.10.2019

А если будем использовать к примеру мегу/due с ее хардварными сериалпортами - просто убираем //SoftwareSerial.h и меняем K_LINE. на Serial1 к примеру?

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

в общем да , только проще убрать две строки 

#include <SoftwareSerial.h>
SoftwareSerial K_LINE(10, 11); // RX, TX

и вместо них поставить 

#define K_LINE Serial1

 

Mike_Levin_
Offline
Зарегистрирован: 16.10.2019

Спасибо! Вечером буду пробовать!