Обмен данными по Uart между Arduino и Webasto

vag
vag аватар
Offline
Зарегистрирован: 24.03.2019

Всем привет, помогите разобраться пожалуйста...

В ходе своих очередных своих экспериментов, решил изучить Uart, как происходит обмен данными, взаимосвязь между пакетами данных и т.д.., для этого подключил Arduino к Webasto через K-Line адаптер (его собрал на интерфейсной микросхеме L9637D), адаптер подключил к Webasto, у Webasto есть диагностическая шина (W-bus), это однопроводная шина, которая полностью соответствуют стандартам K-Line шине.

«K-Line - симплексный интерфейс, обмен по которому происходит, как правило, по принципу "ведущий-ведомый». Ведущее устройство посылает команды ведомому, а ведомое устройство на эти команды отвечает.»

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

Суть такова…

Для инициализации начала обмена c ЭБУ Webasto необходимо подать следующую последовательность уровней на K-линию: LOW (300ms), HIGH (25ms), LOW (25 ms), HIGH (3025ms), за тем на скорости 10400 бод необходимо отправить 5 байт инициализации в HEX 81 51 F1 81 44 , в Arduino (Rx) приходит ответ 12 байт - 81 51 F1 81 44  83 F1 10 C1 E9 8F BD, из которых 5 байт это "эхо" запроса, а 7 байт ответ от самой Webasto, в ответе байт C1 означает положительный ответ (ОК).

 

 

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

запрос - 81 51 F1 81 44 (5 байт)

ответ - 81 51 F1 81 44  83 F1 10 C1 E9 8F BD (12 байт из которых 5 байт 81 51 F1 81 44 Эхо)

после этого, должно происходить считывание из буфера поступивших данных, а это, я так понимаю 12 байт, потом выполняется условие (если кол-во байт соответствует 12, и байт 8 соответствует C1), 

далее очистка буфера, и новый запрос 83 51 F1 2A 01 01 F1

 

Но! нечего не работает, вернее происходит так:

выполняется запрос - 81 51 F1 81 44

выполняется ответ - 81 51 F1 81 44  83 F1 10 C1 E9 8F BD

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

 

Подскажите где ошибка, или как быть? очень интересно понять.

 
byte Init1[] = {0x81, 0x51, 0xF1, 0x81, 0x44}; // иницилизациии связи
byte Request1[] = {0x83, 0x51, 0xF1, 0x2A, 0x01, 0x01, 0xF1}; //*1 запрос на динамические даннные (темп, напряжение и т.д..)
byte Request2[] = {0x83, 0x51, 0xF1, 0x2A, 0x01, 0x02, 0xF2}; //*2 запрос на статические данные ( текущее сост, ошибки, и т.д..)
byte Request3[] = {0x83, 0x51, 0xF1, 0x2A, 0x01, 0x05, 0xF5}; //*3 запрос на статические данные (версия прошивки, тип топлива, и т.д..)
int n; 
String s;
int pac =0;
#define K_line_RX 0 
#define K_line_TX 1
 
 
void setup()
{
pinMode(K_line_RX, INPUT); 
pinMode(K_line_TX, OUTPUT);
digitalWrite(K_line_TX, LOW), delay(300); 
digitalWrite(K_line_TX, HIGH), delay(50);   
digitalWrite(K_line_TX, LOW), delay(25);
digitalWrite(K_line_TX, HIGH), delay(3025); 
Serial.begin(10400); // ISO 14230-4 KWP 10.4 Kbaud
Serial.flush(); 
Serial.write(Init1, 5); // 81 51 F1 81 44 иницилизациия связи (K-line шины)
delay(100);
}
 
void loop()
{  
char byfer[30]; //массив типа char размером 30 (по факту насчитал 29 байт входящий массив)
n = Serial.available(); //Функция получает количество байт(символов) доступных для чтения из последовательного интерфейса связи. 
if (n > 0) 
pac++; //int pac =0;
for (int i=0;i<n;i++) byfer[i]=Serial.read();
String byte8 = String(byfer[8],HEX); // С1 (HEX) = 193 (DEC) // С1 успешный ответ                                        
if (n == 12 && byte8 == "C1")  // ждем инициализхации шины  
{                                    
Serial.flush();   
Serial.write(Request1,7);  
delay(100);                                     
}
                                     
}
}             

       

 

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

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

и прочитайте головную тему песочницы

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

пробуем такой скетч 

#define K_LINE Serial      //UART для соединения с шиной котла
#define TX 1    

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; // таймер сброса заголовка если в момент приёма сообщения данные оборвались


// команды для котлов ТТС/TTE
byte START_SESSION[]        {0x81};
byte REQUEST_2A10101[]      {0x2A, 0x01, 0x01};
byte REQUEST_2A10102[]      {0x2A, 0x01, 0x02};
byte REQUEST_2A10105[]      {0x2A, 0x01, 0x05};
byte REQUEST_DTC[]          {0xA1};
byte START_TTC[]            {0x31, 0x22, 0xFF};
byte STOP_TTC[]             {0x31, 0x22, 0x00};


byte w_bus_init = 1;                            //автомат состояния инициализация шины (300ms LOW, 50ms HIGH, 25ms LOW, 3025ms HIGH для TTC)

uint32_t Prev_PeriodW_BusMessage = 0;           //переменная для таймера периодической отправки сообщений состояния котла в шину W-Bus 
uint32_t prevInitreset = 0;                     //переменная для таймера сброса инита шины
bool Initreset = 0;                             //переменная для таймера сброса инита шины
uint32_t timerInit = 0; bool timerInitflag = 0; //для таймера инита шины W-BUS


void setup() {

K_LINE.begin(10400);
}



void loop() {
curmillis = millis(); 
Heater_BUS ();
}




void Heater_BUS (){
  
if (!timerInitflag && w_bus_init==1) {K_LINE.end(); pinMode (TX, OUTPUT); digitalWrite(TX, 0); timerInit = millis(); timerInitflag = 1;}
if ( timerInitflag && (millis() - timerInit>299)  && w_bus_init==1) {timerInit = millis(); digitalWrite(TX, 1); w_bus_init=2; }
if ( timerInitflag && (millis() - timerInit>49)   && w_bus_init==2) {timerInit = millis(); digitalWrite(TX, 0); w_bus_init=3; }
if ( timerInitflag && (millis() - timerInit>24)   && w_bus_init==3) {timerInit = millis(); digitalWrite(TX, 1); w_bus_init=4; }
if ( timerInitflag && (millis() - timerInit>3024) && w_bus_init==4) {K_LINE.begin (10400); timerInitflag = 0; w_bus_init=9;  sendMessage (START_SESSION, sizeof(START_SESSION));}

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]==0x51 || buf[2]==0x10){ 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]; // прибавляем к контрольной сумме старт байты

//for (byte i=0; i<message_size+n+1; i++) {Serial.print (buf[i], HEX); Serial.print(" ");}

 // если контрольная сумма верна: 
if (buf[message_size+n] == checksum) {
  
  if (buf[n]== 0xC1) {w_bus_init=10;}  // если инит прошёл успешно, даём добро на последующие запросы 
  
  
  
  
  }   

// если контрольная сумма не совпала: 
//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;}   

if (Initreset && curmillis - prevInitreset>17000) {Initreset = 0; w_bus_init = 0;}  // сброс инита, если прошло более 17 сек после отправки последнего сообщения


if (w_bus_init>=10 && curmillis - Prev_PeriodW_BusMessage>1000) {   
             if (w_bus_init==10) {sendMessage (REQUEST_2A10101, sizeof(REQUEST_2A10101)); w_bus_init=11;}
        else if (w_bus_init==11) {sendMessage (REQUEST_2A10102, sizeof(REQUEST_2A10102)); w_bus_init=12;}
        else if (w_bus_init==12) {sendMessage (REQUEST_2A10105, sizeof(REQUEST_2A10105)); w_bus_init=10;}
        
               Prev_PeriodW_BusMessage = curmillis; 
        }

        
 


}


void sendMessage(const byte *command, const size_t size){

 Initreset = 1;  prevInitreset = curmillis;  // включение таймера сброса инита
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] = 0x51;
    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]); 
      }
}