Обмен данными по Uart между Arduino и Webasto
- Войдите на сайт для отправки комментариев
Всем привет, помогите разобраться пожалуйста...
В ходе своих очередных своих экспериментов, решил изучить 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
Подскажите где ошибка, или как быть? очень интересно понять.
для начала почитать эту ветку . там вроде я бросал тестовые скетчи работы с вашим котлом. Также читаем пост #414 . А вообще в ближайшее время хочу найти время и добавить ваш котёл в скетче девайса, обсуждаемого в той ветке.
и прочитайте головную тему песочницы
пробуем такой скетч
#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]); } }