В общем, пошел в машину. Беру скеч из 1250. Заливаю. Побежала инфа. Получил 3 сообщения с ОК, остальные CRC FAIL. Ну ок, думаю, играемся с задержками. И тут начинаются чудеса! Поменял в 87 строке задержку на 15 и получил только успешную инициализацию. Т.е.
Дальше какие бы значения не ставил, все оставалось так же. И даже вернувшись на значение 10 - тоже самое. Более того! Загрузил предыдущий скеч, коим я логи то и получил, из поста 1234. И тут опять такая же ерунда, несмотря на все значения, что ставил раньше, т.е. 150 мс. Опытным путем выяснил, что если Ардуину со скетчем из 1234 раза 4-5 сбросить кнопкой, то получим
скорее всего гдето беда с задержками . при рестарте ардуины несколько раз одно накладывается на другое с задержкой - в итоге прокатывает. Нужно попробовать еще в #1250 между 048 и 049 delay поставить например 10мс.
накатал эмулятор панели, но так и не смог добиться отображения текущих данных от проги ОПКОМ. Странно программа себя ведёт. Даже страницы и наименование данных можно листать, а в окошках пусто. Нужно попробовать подсунуть этот эмулятор программе ОПКОМ ориг , а также второму вашему сканеру, может заработает.
Постоянно первые 3 сообщения Ок, потом Фэил. И постоянно после сброса Ардуино он коннектится со второго раза. Может, мы не шлем запрос на закрытие соединения и в первый сброс приборка его закрывает? В любом случае, только три правильных ответа как-то маловато....
Почему три правильных мало? Хватит за глаза - километраж и остаток топлива считать. Нужно заснифить какая команда идет на закрытие диагностической сессии. После двух например правильных ответов закрываем сессию и связываемся с PCM.
понятно только что первый байт после нулей 0х78 (120DEC/10) это напряжение акб. и пятый байт 0х32 (в dec 50) это температуа ДВС. Остальное зашифровано както
Возможно второй байт это напряжение датчика уровня топлива. 0x2С в DEC 44 делим на 10 получаем 4,4 В
Хотя нет, есть трип. В первом случае 03 03 это и есть 771, т.е. без запятой пробег Во втором случае 74 06 это и есть 1652, только байты местами поменяны. 7C FF 24 так же справа на лево это пробег - 2424700
Тут изменилась только температура двигателя. (ну трип и одометр не в счет)
И судя по третьему логу, он где-то в первых трех значащих байтах. Причем, первый байт с наполнением бака уменьшился, что позволяет думать, что это вольты. А второй и третий байт увеличился. Значит это литры. Вот теперь как бы это увязать с формулой. 40,5л =0х51 = 81; 22л = 0х2c = 44
Тьфу млин, да банально на два делить. Дискретность измерения бака 0,5 литра.
Интересный вопрос - где ж он напряжение берет. но в принципе оно нас не интересует, как и скорость.
Уфффф..... Кажись все данные есть. Теперь самое сложное - сам БК написать :)
Скетч из 1272 работает хорошо. Цепляет одно сообщение с CRC Fail, думаю не проблема. Задержку уменьшил до 10 мс, работает. Одометр нужно на 10 делить, отсекая сотые метра. Убрал выбор протокола и адреса, уже ведь не нужны. Глянь, ничего не пропустил?
#include <SoftwareSerial.h>
#define RX_gauge 7
#define TX_gauge 8
SoftwareSerial Gauge_K_line (RX_gauge, TX_gauge);
bool InitGauge = 0; // флаг инита панели
byte EndSession []= {0x02, 0xB2, 0x00, 0xB4};
void setup() {
Serial.begin (9600); //открываем соединение терминала для отладки
pinMode (TX_gauge, OUTPUT);
digitalWrite (TX_gauge, 1); // BUS idle
delay (2000);
// далее посылаем на панель адрес на скорости 5 baud
Serial.print("Delayu zapros na panel. Adress: "); Serial.println("0xE0, 5 baud");
digitalWrite (TX_gauge, 0); delay (5); // старт бит
for(byte i = 0; i<8; i++) {digitalWrite (TX_gauge, bitRead(0xE0,i)); delay(5);}
digitalWrite (TX_gauge, 1); delay (5); // стоп бит
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) {
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 (" "); }
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!!!");
}
}
}
По периодическому обращению (скетч 1273). Если период так и оставить - 1 минута, то ничего вообще не происходит. Думал, он только через минуту обратиться, но нет. А вот если поставить 1/2, то так:
Т.е. не успев закончить получение, опять начинает запрос, ловит пару последних данных с неверным CRC и на этом виснет.
В принципе, я думаю, это периодическое обращение нужно уже в код готового скетча добавлять, чтоб было видно куда и как. Перед этим запросом нужно ж будет закрывать соединение с ЭБУ.
Кстати, нужно проверить как с ЭБУ данные читаться будут.
Пытаюсь что-то накропать сам. К сожалению, и так не программист, а тут чужой код понять нужно. Для начала постарался вырезать все, что касается LCD, чтоб он мне просто пиды в серийник выводил.
#include <SoftwareSerial.h>
SoftwareSerial mySerial (12, 13); //RХ,TХ
#define TX 13
unsigned long TimewaitPID, timerwaitPID = 0;
bool timerenabledPID = 0;
#define TIMEREXPIRED_PID (TimewaitPID - timerwaitPID)> 200 // здесь задержка на ожидание правильного ответа пидов, мс
unsigned long TimewaitInit, timerwaitInit = 0;
bool timerenabledInit = 0;
#define TIMEREXPIRED_Init (TimewaitInit - timerwaitInit)> 500 // здесь задержка на ожидание ответа об удачной инициализации, мс
byte messageInit[5] = {0x81, 0x11, 0xF1, 0x81, 0x04}; // запрос инициализации
byte messagePids[6] = {0x82,0x11,0xF1,0x21,0x01,0xA6}; // запрос пид 2101
byte messagePresent[5] = {0x81,0x11,0xF1,0x3E,0xC1}; // запрос присутствия
unsigned long prevPID = 0;
int PIDTime = 120; // задержка ожидания запроса следующего pid 2101, мс
unsigned long prevpres = 0;
int PresTime = 8000; // задержка между посылками запросов присутствия, мс
int waitbyte = 1; // задержка между отправкой байт в сообщении, мс
byte MessageRx[55] = {0}; // массив байтов принимаемого сообщения
bool Init = 0;
int MAP = 0; //13 байт Датчик абсолютного давления
float SysVolt = 0; //14 байт Напряжение в сети
int TempAir = 0; //16 байт Температура воздуха в градусах
int Temp = 0; //18 байт Температура охлаждающей жидкости в градусах
int EngLoad = 0; //20 байы нагрузка на двигатель
int Throtle = 0; //28 байт Открытие дроссельной заслонки в процентах
int RPM = 0; //30 байт Оборогты двигателя
int Speed = 0; //29 байт Скорость
float InjPulse = 0; //31 байт Время впрыска форсунок
int IdleAir = 0; //32 байт Клапан холостого хода, шаги
float O2sens = 0; //35 байт Лямбда мВ
float O2int = 0; //36 байт Интегратор лямда, шагов
float FuelRatio = 0; //41 байт Соотношение воздуха/топлива
int STFT = 0; // Краткосрочная коррекция топлива
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//стартовая инициализация 7 пина ОБД
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
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
mySerial.begin(10400); } // baud rate of the OBD
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//отправка запроса на диагностическое соединение
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void initialization() {
Serial.println ("Otpravil zapros Init");
for (int i = 0; i < 5; i++) {
mySerial.write(messageInit[i]);
delay (5); }
delay (55); }
///////////////////////////////////////////////////////////////////////////
//VOID PIDs// отправка запроса пид 2101////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
void PIDs() {
Serial.println ("Otpravil zapros 21 01");
for (int i = 0; i < 6; i++) {
mySerial.write(messagePids[i]);
delay (waitbyte); }}
///////////////////////////////////////////////////////////////////////////
//BOID PIDsGAUGR//отправка запроса присутствия/////////////////////////////
///////////////////////////////////////////////////////////////////////////
void present() {
Serial.println ("Otpravil zapros Present");
for (int i = 0; i < 55; i++) {
mySerial.write(messagePresent[i]);
delay (waitbyte); }}
/////////////////////////////////////////////////////////////////////////////////////////////
//получение данных от ЭБУ, разборка входящих сообщений
/////////////////////////////////////////////////////////////////////////////////////////////
void receive () {
////////////////////////////////////////////////////////////////////
////////////////// работа с К-Line софт сериал 12-13 (7 контакт ОБД)
////////////////////////////////////////////////////////////////////
if (mySerial.available()) {
delay(195);
int k=0;
byte inbyte=0;
while( mySerial.available() && k < 55) {
inbyte = mySerial.read();
MessageRx[k] = inbyte;
k++; }
Serial.print ("Receive: ");
for (int i = 0; i < k; i++) {
Serial.print(MessageRx[i],HEX); Serial.print (" ");}
Serial.println ("");
if (MessageRx[2]==0x83 && MessageRx[3]==0xF1 && MessageRx[4]==0x11 && MessageRx[5]==0xC1 && MessageRx[6]==0x6B && MessageRx[7]==0x8F && MessageRx[8]==0x40) {Init=1;
timerenabledInit=0;
Serial.println (" Initialization OK!!!!: "); }
///////////////////////////////////////////////////////////////////////////////////////////////////
//Чтение и стирание ошибок
///////////////////////////////////////////////////////////////////////////////////////////////////
//при получении этого сообщения выдавать на третий экран "NO ERROR"
if (MessageRx[4]==0x82 && MessageRx[5]==0xF1 && MessageRx[6]==0x11 && MessageRx[7]==0x58 && MessageRx[8]==0x00 && MessageRx[9]==0xDC){
Serial.println (" NO DTC "); }
//при получении этого сообщения выдавать на третий экран "CLEAR DTC"
if (MessageRx[3]==0x83 && MessageRx[4]==0xF1 && MessageRx[5]==0x11 && MessageRx[6]==0x54 && MessageRx[7]==0xFF && MessageRx[8]==0x00 && MessageRx[9]==0xD8){
Serial.println (" DTC CLEARED "); }
// при получении сообщения о наличии ошибок DTC разберем сообщение выведем на экран ошибки
if (MessageRx[5]==0xF1 && MessageRx[6]==0x11 && MessageRx[7]==0x58 && MessageRx[8]>0){
Serial.println ("DTC is found!");
for (int i=0; i<MessageRx[8]; i++ ) {
int y = i*35;
bool nolA=0; bool nolB =0;
if (!bitRead(MessageRx[11+(i*3)],6) && bitRead(MessageRx[11+(i*3)],7)){
Serial.println(" -Passive-");} // если DTC пасивныый делаем цвет зеленый
if (bitRead(MessageRx[11+(i*3)],7) && bitRead(MessageRx[11+(i*3)],6)) {
Serial.println(" -Active-");} // если DTC активный, делаем цвет красный
Serial.println("ERROR ");
Serial.println(i+1);
if (!bitRead(MessageRx[9+(i*3)],6) && !bitRead(MessageRx[9+(i*3)],7)) Serial.println(": P");
if (bitRead(MessageRx[9+(i*3)],6) && !bitRead(MessageRx[9+(i*3)],7)) Serial.println(": C");
if (!bitRead(MessageRx[9+(i*3)],6) && bitRead(MessageRx[9+(i*3)],7)) Serial.println(": B");
if (bitRead(MessageRx[9+(i*3)],6) && bitRead(MessageRx[9+(i*3)],7)) Serial.println(": U");
}}
///////////////////////////////////////////////////////////////////////////////////////////////////////////
//прописываем формулы к данным ///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////
else if (MessageRx[4]==0xB0 && MessageRx[5]==0xF1 && MessageRx[6]==0x11 && MessageRx[7]==0x61 && MessageRx[8]==0x01) {
MAP = (MessageRx[16]*4,97/255); //13 байт Датчик абсолютного давления
SysVolt = (MessageRx[17]/10); //14 байт Напряжение в сети
TempAir = ((MessageRx[19]*191/255)-40); //16 байт Температура воздуха в градусах
Temp = ((MessageRx[21]*191/255)-40); //18 байт Температура охлаждающей жидкости в градусах
EngLoad = (MessageRx[23]*100/255); //20 байы нагрузка на двигатель
Throtle = (MessageRx[31]*100/255); //28 байт Открытие дроссельной заслонки в процентах
RPM = (MessageRx[33]*6375/255); //30 байт Оборогты двигателя
Speed = (MessageRx[32]); //29 байт Скорость
InjPulse = (MessageRx[34]*21,8/255); //31 байт Время впрыска форсунок
IdleAir = (MessageRx[35]); //32 байт Клапан холостого хода, шаги
O2sens = (MessageRx[38]*1127/255); //35 байт Лямбда мВ
O2int = (MessageRx[39]); //36 байт Интегратор лямда, шагов
FuelRatio = (MessageRx[44]/10); //41 байт Соотношение воздуха/топлива
int STFT = (MessageRx[39]*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.print(STFT);
timerenabledPID=0; }
for (int i = 0; i < 55; i++) MessageRx[i]=0; }} // очистка байтов массива
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//SETUP
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void setup() {
Serial.begin(115200);
mySerial.begin(10400);
pinMode(TX, OUTPUT);
fastinit();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//loop
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void loop() {
TimewaitPID = millis ();
TimewaitInit = millis ();
if (!Init) { if (!timerenabledInit){ timerwaitInit=TimewaitInit; timerenabledInit=1; initialization(); }
else if (TIMEREXPIRED_Init) timerenabledInit=0;}
if (millis() - prevPID > PIDTime) { PIDs(); prevPID = millis(); }
else if (millis() - prevpres > PresTime) {present(); prevpres = millis();}
receive ();
}
И каким-то чудом один раз все же мне выдало показания, но часть из них почему-то неверны. Я бы понял, если б все, но тут только часть. Вот этого вообще не могу понять. Например температура двигателя почему -162 ? По формуле она максимум -40 может быть. Из-за неверного типа переменных такое возможно?
Скобки.... Либо их где-то не хватает, либо они не там, где надо.... Если скобка стоит после GAUGE_SESSION (); , то prevgauge на каждом цикле равен millis :)
#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
uint32_t Odometer = 0;
float FuelLevel = 0,0;
byte interval_gaugesession = 1; // периодичность опроса щитка приборов, мин
uint32_t prevgauge = 0;
byte GAUGE_EndSession []= {0x02, 0xB2, 0x00, 0xB4};
byte GAUGE_DataRequest []= {0x02, 0x11, 0x00, 0x13};
int bit_time = 0;
#include <SoftwareSerial.h>
#define RX_gauge 7
#define TX_gauge 8
SoftwareSerial Gauge_K_line (RX_gauge, TX_gauge);
bool InitGauge = 0; // флаг инита панели
void setup() {
Serial.begin (9600); //открываем соединение терминала для отладки
}
byte head_count = 0;
byte head[4] = {0};
void loop() {
if (millis() - prevgauge > (uint32_t)interval_gaugesession*60000UL){
ZAPROS_GAUGE ();
GAUGE_SESSION ();
prevgauge = millis();
}
}
void ZAPROS_GAUGE () {
pinMode (TX_gauge, OUTPUT);
digitalWrite (TX_gauge, 1); // BUS idle
delay (250);
// далее посылаем на панель адрес на скорости 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
}
void GAUGE_SESSION (){
while (1) {
while(!InitGauge){
if (Gauge_K_line.available()) {
byte inByte = Gauge_K_line.read();
Serial.print(" ");
Serial.print(inByte,HEX);
if (inByte==0x80) {delay (150); Gauge_K_line.write (0x7F); }
if (inByte==0x78) {
delay (10);
for (byte i=0; i < sizeof (GAUGE_DataRequest); i++) {Gauge_K_line.write (GAUGE_DataRequest[i]); 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!!!");
Odometer = ((uint32_t) MessageRx[26] << 16 ) | ((uint32_t) MessageRx[25] << 8 ) | MessageRx[24]; Odometer/=10;
FuelLevel = MessageRx[21]/2.0 ;
Serial. print ("Odometer: "); Serial. print (Odometer); Serial. print (" km, FuelLevel: "); Serial. print (FuelLevel);Serial.println (" l");
for (byte i = 0; i < sizeof (GAUGE_EndSession); i++ ) { Gauge_K_line.write (GAUGE_EndSession [i]); delay (2);}
break;
} // конец ифа с правильной CRC
else Serial.println(" CRC FAIL!!!");
}
}
}
}
Для пробы уменьшил интервал до 10 секунд. Так вот, первый запрос проходит хорошо и данные получает. А вот второй, через десять секунд, получает два сообщения CRC Fail и программа дальше никуда уже не двигается. Кажись, что-то не то шлем на закрытие соединения.....
После инициализации, мы ждем байта 0х80 и шлем 0x7F. Затем ищем 0x78 и сразу шлем запрос пидов. Но ведь IDEN от приборки приходит два раза. Может второй раз нужно подождать ответ...
Потом Опель-сканер отправляет 02 B0 00 B2 и получает дважды ответ (присутствия?) 06 F0 AA 10 32 10 01 F2.... И только потом уже шлет запрос на пиды 02 11 00 13.... Не кроется ли тут причина остальных неверных сообщений?
При прекращении запросов пид он шлет 02 B2 00 B4, но в ответ получает еще один отзыв присутствия. Вот интересно как же он все-таки закрывает соединение? Нет ли в описании протокола каких-то подсказок, типа как с инициализацией на 5 бод?
Ок, завтра запроверю че покажет. Пару вопросов, так сказать для общего развития.
MAP = ((uint16_t)buf[12]*100/255); //13 байт Датчик абсолютного давления
Для чего uint16_t? Это ж, если я правильно понимаю, объявление длины переменной в 16 бит.... Просто до этого было вообще MessageRx[16] и усе. И вкладывалось значение в ранее объявленную переменную float MAP = 0; (кстати МАП с точкой, потому с float)
И второй вопросик, я то ориентировался по снифу, где в логе
первые 3 байта - FF, потому вместо 13 байта брал 16. А тут в скейче наоборот, сдвинуто все в лево на один. Ну, хочется понять. Может повтыкаю в код хорошо, да дойдет.... как до жирафа
Почему формулы корявые? Я проверял на эмуляторе, все сошлось отлично.
Для чего uint16_t? Это ж, если я правильно понимаю, объявление длины переменной в 16 бит.... Просто до этого было вообще MessageRx[16] и усе. И вкладывалось значение в ранее объявленную переменную float MAP = 0; (кстати МАП с точкой, потому с float)
когда пишем формулу, то в ней нужно приводить все переменные к одному типу. например MessageRx[16] это тип byte у которого диапазон от 0 до 255. и если его умножить на 100, например, он выйдет за пределы и возможна ошибка в формуле, поэтому я на всякий привел к двухбатовому числу. числовые константы, на сколько знаю, имеют тип int , поэтому их тоже нужно переводить соответвующе.
Targitai пишет:
И второй вопросик, я то ориентировался по снифу, где в логе .......первые 3 байта - FF, потому вместо 13 байта брал 16. А тут в скейче наоборот, сдвинуто все в лево на один. Ну, хочется понять. Может повтыкаю в код хорошо, да дойдет.... как до жирафа
FF пробегали потому что мы с ТС очень корявый вариант разбора входящих сообщений сделали. delay там используется. По факту на шине FF скорее всего не пробегают. Щас опыта прибавилось немного. Поэтому пробуем по правильному принимать, без лишних байт. все как положено с Checksum. А влево сдвинуто на один, т.к номера байт в программировании с нулевого начинаются. а в описании разбайтовки мы написали, начиная с первого.
Так и я по эмулятору. 13 байт ставим равным 0, минимальное значение МАП = 0 Бар, ставим равным 255 - максимальное - 1,04 бар. Вот и получается X*1.04/255=Bar
С остальными параметрами так же. Например, обороты двигателя при 0х00 = 0, а при 0хFF = 6375. Вот и получается X*6375/255
Почему у тебя 245?
У меня формулы вида X*100/255 - выдают проценты. Типа нагрузка на двигатель или процент открытия дроссельной заслонки.
Ладно, собственно, чего думать, пойти и проверить :)
постоянно шлёт инит, т.к. после отправки запроса инита не получаем правильного сообщения от PCM. А это, в свою очередь, происходит из-за того, что keyword при разборе входящего сообщения перепутали.
исправил данный косяк в #1282
ну а скобки ты конечно убрал... Это похоже как студенты на лабораторных работах измерения под результат подгоняют....
Скобки.... Либо их где-то не хватает, либо они не там, где надо.... Если скобка стоит после GAUGE_SESSION (); , то prevgauge на каждом цикле равен millis :)
Для пробы уменьшил интервал до 10 секунд. Так вот, первый запрос проходит хорошо и данные получает. А вот второй, через десять секунд, получает два сообщения CRC Fail и программа дальше никуда уже не двигается. Кажись, что-то не то шлем на закрытие соединения.....
Всё там нормально со скобками. prevgauge присваивается значение millis не каждый проход луп, а только когда выполняется условие if a.
вот сделал интервал можно изменять в секундах, добавил двойное ожидание идентов от панели.
#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
uint32_t Odometer = 0;
float FuelLevel = 0;
byte interval_gaugesession = 10; // периодичность опроса щитка приборов, сек
uint32_t prevgauge = 0-(interval_gaugesession*1000UL);
uint32_t prevsec=0;
byte GAUGE_EndSession []= {0x02, 0xB2, 0x00, 0xB4};
byte GAUGE_DataRequest []= {0x02, 0x11, 0x00, 0x13};
int bit_time = 0;
#include <SoftwareSerial.h>
#define RX_gauge 7
#define TX_gauge 8
SoftwareSerial Gauge_K_line (RX_gauge, TX_gauge);
byte InitGauge = 0; // флаг инита панели
void setup() {
Serial.begin (9600); //открываем соединение терминала для отладки
delay(10);
}
byte head_count = 0;
byte head[4] = {0};
void loop() {
if (millis()-prevsec>1000){ Serial.println ((millis()-prevgauge)/1000+1); prevsec = millis();}
if (millis() - prevgauge > (uint32_t)interval_gaugesession*1000UL){
Serial.println ("Prohod cylce loop"); Serial.println(); // для контроля как часто пробегает цикл луп
ZAPROS_GAUGE ();
GAUGE_SESSION ();
prevgauge = millis();
}
}
void ZAPROS_GAUGE () {
pinMode (TX_gauge, OUTPUT);
digitalWrite (TX_gauge, 1); // BUS idle
delay (250);
// далее посылаем на панель адрес на скорости 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
}
void GAUGE_SESSION (){
Serial.println ("function Gauge Session");
uint16_t p = 0;
while (p<2000) {
uint16_t v = 0;
while(InitGauge<2 && v<2000){
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); }
if (inByte==0x78) {
delay (10);
for (byte i=0; i < sizeof (GAUGE_DataRequest); i++) {Gauge_K_line.write (GAUGE_DataRequest[i]); delay (2);}
InitGauge++; Serial.print(" Receive Panel ID "); Serial.println (InitGauge);}}v++;}
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!!!");
Odometer = ((uint32_t) MessageRx[26] << 16 ) | ((uint32_t) MessageRx[25] << 8 ) | MessageRx[24]; Odometer/=10;
FuelLevel = MessageRx[21]/2.0 ;
Serial. print ("Odometer: "); Serial. print (Odometer); Serial. print (" km, FuelLevel: "); Serial. print (FuelLevel);Serial.println (" l");
for (byte i = 0; i < sizeof (GAUGE_EndSession); i++ ) { Gauge_K_line.write (GAUGE_EndSession [i]); delay (2);}
break;
} // конец ифа с правильной CRC
else Serial.println(" CRC FAIL!!!");
}
}
p++;
}
Serial.println("Gauge_session is end");
}
Лог РСМ с моей формулой МАП, т.е. Х*1,04/255, а так же поправил формулу для коррекции, не верно ее написал. Вот так надо: int STFT = (((uint16_t)buf[35]-128)*100/128);
Initialization OK!!!!:
Otpravil zapros 21 01
B0 F1 11 61 1 1 1 70 22 0 0 0 4B 8B 4E 64 6B AB 86 17 34 A 1 0 0 0 1E 0 0 22 25 1B C 44 47 80 12 6F 0 0 92 0 0 4 CC A 7 34 0 0 0 E1
Received message is OK!
Receive DATA
MAP=0.32 Battery=13.90 Air=34 Temp=88 EngLoad=9 Throtle=0 RPM=850 Speed=0 Inj=3.16 IdleAir=27 O2sens=313 O2int=128 FuelRatio=14.60 STFT=0
Otpravil zapros 21 01
B0 F1 11 61 1 1 1 70 22 0 0 0 4B 8B 4E 64 6B AB 86 17 34 A 1 0 0 0 1E 0 0 22 25 1B C 44 47 80 12 6F 0 0 92 0 0 4 CC A 7 34 0 0 0 E1
Received message is OK!
Receive DATA
MAP=0.32 Battery=13.90 Air=34 Temp=88 EngLoad=9 Throtle=0 RPM=850 Speed=0 Inj=3.16 IdleAir=27 O2sens=313 O2int=128 FuelRatio=14.60 STFT=0
Otpravil zapros 21 01
B0 F1 11 61 1 1 1 70 22 0 0 0 4A 8B 4E 64 6B AB 82 17 34 A 1 0 0 0 1E 0 0 23 24 1B C 44 47 80 12 6F 0 0 92 0 0 4 CC A 7 34 0 0 0 DC
Received message is OK!
Все показывает отлично. Осталось с ошибками разобраться как глядеть/расшифорвывать и стирать. Прикрутить кнопку к Дуне для перехода в режим ошибок и стирания?
А вот с приборкой так происходит:
После включения идет до:
Prohod cylce loop
Delayu zapros na panel. Adress: E0
5 baud Init
function Gauge Session
да, твоя правда, почему то не заметил сразу. Смотри ка по панели , ведь после первого идента начинает нормально сыпать сообщениями с данными. поправлю позже код может, нормально заработает
добавил в #1282 округление температур, теперь температуры достоверно показывают. И формулу MAP как у тебя сделал. Не понятно почему в твоём логе показывает мап 0.32 когда должно по эмулю 0,31. С моей формулой как положено 0,31 показывает.
- в разбор входящих сообщений дополнительный байт длины при его наличии
- чтение ошибок - короткое нажатие на кнопку (подключена пин 4)
- удаление ошибок - длительное нажатие на кнопку (подключена пин 4)
Логика такая - коротко нажимаем на кнопку - запросы 2101 перестают подаваться, а подаются запросы чтения ошибок, пока не получим ответ с ошибками, если ответ получили - далее опять долбим запросами 2101
длительно нажимаем на кнопку - запросы 2101 перестают подаваться, а подаются запросы удаления ошибок, пока не получим отчёт что DTC удалены , если отчёт получили - далее опять долбим запросами 2101
Ну может быть, спорить не буду :) Часы делал без нее.
В общем, отлично все работает, читает и сбрасывает ошибки. Правда, как отличить присутсвует или просто в памяти? Иногда проскакивают какие-то длинные сообщения, но на работу не влияют, да и редко.
Received message is OK!
Receive DATA
MAP=1.02 Battery=12.10 Air=15 Temp=93 EngLoad=7 Throtle=0 RPM=0 Speed=0 Inj=12.14 IdleAir=39 O2sens=83 O2int=128 FuelRatio=12.60 STFT=0
Otpravil zapros DTC read
85 F1 11 58 1 1 70 22 73
Received message is OK!
DTC is found!
ERROR 1: P0170
B0 F1 11 61 1 1 1 70 22 0 0 0 FA 79 85 4A 62 B1 8A 12 34 0 0 0 0 0 1E 0 0 0 8E 27 0 0 13 80 12 71 0 FF 7E 0 0 0 84 8 27 34 0 0 0 1A
Received message is OK!
Receive DATA
MAP=1.02 Battery=12.10 Air=15 Temp=93 EngLoad=7 Throtle=0 RPM=0 Speed=0 Inj=12.14 IdleAir=39 O2sens=83 O2int=128 FuelRatio=12.60 STFT=0
B0 F1 11 FA 85 B1 8A 12 8E 27 80 12 84 8 B0 F1 11 FA 85 4A B1 8A 8E 27 80 12 84 B0 F1 11 FA 79 85 4A B1 8A 8E 80 84 B0 F1 11 61 1 1 1 70 22 0 0 0 FA 79 84 4A 62 B1 8A 12 34 0 0 0 0 0 1E 0 0 0 8E 27 0 0 13 80 12 71 0 FF 7E 0 0 0 84 8 27 34 0 0 0 19
Received message is OK!
Receive DATA
MAP=1.02 Battery=12.10 Air=15 Temp=93 EngLoad=7 Throtle=0 RPM=0 Speed=0 Inj=12.14 IdleAir=39 O2sens=83 O2int=128 FuelRatio=12.60 STFT=0
.....
Otpravil zapros DTC clear
83 F1 11 54 FF 0 D8
Received message is OK!
DTC CLEARED
B0 F1 11 61 1 0 0 0 0 0 0 0 FA 79 7E 4D 62 B1 8A 12 34 0 0 0 0 0 1E 0 0 0 8D 27 0 0 1A 80 12 71 0 FF 7E 0 0 0 84 8 27 34 0 0 0 88
Received message is OK!
Receive DATA
MAP=1.02 Battery=12.10 Air=18 Temp=93 EngLoad=7 Throtle=0 RPM=0 Speed=0 Inj=12.05 IdleAir=39 O2sens=114 O2int=128 FuelRatio=12.60 STFT=0
......
Received message is OK!
Receive DATA
MAP=1.02 Battery=12.10 Air=18 Temp=93 EngLoad=7 Throtle=0 RPM=0 Speed=0 Inj=12.05 IdleAir=39 O2sens=128 O2int=128 FuelRatio=12.60 STFT=0
B0 F1 11 61 1 0 0 0 0 0 0 0 FA 79 7C 4E 62 B1 8A 12 34 0 0 0 0 0 1E 0 0 0 8D 27 0 0 1D 80 0 0 8 0 8A FF FF FF B0 F1 11 61 1 0 0 0
CRC fail!!!
FA 79 B1 8A 8D 27 80 12 84 8 8A Otpravil zapros DTC read
82 F1 11 58 0 DC
Received message is OK!
NO DTC
B0 F1 11 FA B1 8A 8D 27 80 12 84 8 8A B0 F1 11 FA B1 8A 8D 27 80 12 84 8A B0 F1 11 FA 79 B1 8A 8D 27 80 84 8A FF B0 F1 11 61 1 0 0 0 0 0 0 0 FA 79 7C 4E 62 B1 8A 12 34 0 0 0 0 0 1E 0 0 0 8D 27 0 0 1D 80 12 71 0 FF 7E 0 0 0 84 8 27 34 0 0 0 8A
Received message is OK!
В конечном скече нужно будет делать проверку и fastinit(); повторять если, например, после пяти секунд отправки запроса Init ничего не меняется. Мало ли из-за чего связь прервется. Сейчас, например, если включить Дуню, а потом зажигание, то ничего не добьешья.
Осталось приборку доломать :)
НО! Пушной зверек подкрался незаметно. Попробовал выводить на экран. Скеч компилируется, но изображения нет. Как я понял, библиотека TV-out жестко завязана на прерывания, а у нас их вагон с тележкой. Блин, и ведь убил пару дней пока нашел рабочий вариант библиотеки под последний IDE.... Вот что теперь делать не представляю. Отказываться от аналогово вывода очень не хочется, т.к. потеряю камеру. Да и смысл тогда огород городить - есть стандартный MID. не такой функциональный, но все же.... Ставить вторую Дуню чисто для вывода на экран и слать ей готовые данные? Блин, сразу бы Нано заказал....
Стою на асфальте..... и чет меня прет...
В общем, пошел в машину. Беру скеч из 1250. Заливаю. Побежала инфа. Получил 3 сообщения с ОК, остальные CRC FAIL. Ну ок, думаю, играемся с задержками. И тут начинаются чудеса! Поменял в 87 строке задержку на 15 и получил только успешную инициализацию. Т.е.
Дальше какие бы значения не ставил, все оставалось так же. И даже вернувшись на значение 10 - тоже самое. Более того! Загрузил предыдущий скеч, коим я логи то и получил, из поста 1234. И тут опять такая же ерунда, несмотря на все значения, что ставил раньше, т.е. 150 мс. Опытным путем выяснил, что если Ардуину со скетчем из 1234 раза 4-5 сбросить кнопкой, то получим
А вот если загрузить скетч 1250, то хоть сколько сбрасывай кнопкой, а заветной информации больше не появляется.
Глюки приборки??? Или влияние разряда ноутбука (Ардуина от него питается по шнурку)? Хотя какая там просадка то по USB может быть...
скорее всего гдето беда с задержками . при рестарте ардуины несколько раз одно накладывается на другое с задержкой - в итоге прокатывает. Нужно попробовать еще в #1250 между 048 и 049 delay поставить например 10мс.
накатал эмулятор панели, но так и не смог добиться отображения текущих данных от проги ОПКОМ. Странно программа себя ведёт. Даже страницы и наименование данных можно листать, а в окошках пусто. Нужно попробовать подсунуть этот эмулятор программе ОПКОМ ориг , а также второму вашему сканеру, может заработает.
#include <SoftwareSerial.h> SoftwareSerial Gauge_K_Line(7, 8); // RX, TX byte Init= 0; uint32_t prev = 0; byte initMessage[] = {0x55, 0x52, 0x80}; byte initMessage1[] = {0x20, 0xA0, 0x20, 0x39, 0x30, 0x35, 0x36, 0x39, 0x37, 0x38, 0x35, 0x20, 0x30, 0x36, 0x39 ,0x36, 0x20 ,0x30, 0x36, 0x39, 0x36, 0x20, 0x30, 0x37, 0x39, 0x37, 0x20, 0x30, 0x31, 0x32 ,0x20, 0x33, 0x06, 0x78}; //byte initMessage1[] = { //0x2D, 0xA0, 0x48, 0x54, 0x20, 0x32, 0x34, 0x34 ,0x31 ,0x39 ,0x35, 0x36, 0x30, 0x20, 0x31, 0x34, 0x30, 0x30 ,0x20 ,0x34, 0x31, 0x39 ,0x39 ,0x20 ,0x31, 0x33, 0x30, 0x31, 0x20, //0x30, 0x34, 0x32 ,0x20, 0x31, 0x20 ,0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x8, 0xF0 //}; byte Message6F0[] = {0x06 ,0xF0, 0xAA, 0x10, 0x32, 0x10, 0x01 ,0xF2}; byte answerData[] = {0x21, 0xA1, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x72, 0x33, 0x31, 0xBB, 0x32, 0x17, 0xF5 ,0x24, 0xD2 ,0x05 ,0xB2, 0xC6, 0x3F ,0x01, 0x06, 0x49}; uint32_t prevdata = 0; void setup() { Gauge_K_Line.begin (4800); Serial.begin (9600); //pinMode () } uint32_t nachalo = 0; bool flagimpulse=0; byte head_count = 0; byte head[4] = {0}; byte n = 0; bool dataON = 0 ; bool initNE = 0; bool dataprint = 0; byte bytenumber = 3; bool f=0; void loop() { if (Serial.available()) { byte inbyte=0; inbyte = Serial.read(); delay(2); if (inbyte == '-') {bytenumber --; Serial.print (" bytenumber: "); Serial.println (bytenumber);} if (inbyte == '+') {bytenumber ++; Serial.print (" bytenumber: "); Serial.println (bytenumber);} if (inbyte == '.') {answerData[bytenumber]++;Serial.print ("byte value: "); Serial.println (answerData[bytenumber]); byte CRC = 0; for (byte i=0; i<sizeof(answerData); i++){if (i<=sizeof(answerData)-3) CRC+=answerData[i]; if (i==sizeof(answerData)-1) answerData[i]=CRC;}} if (inbyte == 'm') {if (f)answerData[bytenumber]=255;else answerData[bytenumber]=0; f=!f; Serial.print ("byte value: "); Serial.println (answerData[bytenumber]); byte CRC = 0; for (byte i=0; i<sizeof(answerData); i++){if (i<=sizeof(answerData)-3) CRC+=answerData[i]; if (i==sizeof(answerData)-1) answerData[i]=CRC;}} if (inbyte == ',') {answerData[bytenumber]--;Serial.print ("byte value: "); Serial.println (answerData[bytenumber]); byte CRC = 0; for (byte i=0; i<sizeof(answerData); i++){if (i<=sizeof(answerData)-3) CRC+=answerData[i]; if (i==sizeof(answerData)-1) answerData[i]=CRC;}} Serial.flush(); return;} if (Init!=1){ if (digitalRead(7)==0 && !flagimpulse){ nachalo = millis(); flagimpulse = 1;} if (digitalRead(7)==1 && flagimpulse){ if( millis()- nachalo>1150 && millis()-nachalo<1250) {Init =1; dataON = 0; initNE = 0;flagimpulse = 0; delay(50);}} } if (Init ==1){ Gauge_K_Line.write (0x55); delay (55); Gauge_K_Line.write (0x52); delay (3); Gauge_K_Line.write (0x80); Init =2; Serial.println (" otpravil 55 52 80 ");} if (Init==2 && Gauge_K_Line.available()){ byte inbyte = Gauge_K_Line.read(); if (inbyte==0x7F){ Init =3; delay (77);} Serial.println(inbyte,HEX); } //if (Init>=3 && Init<5 && millis() - prev > 100){ for (byte i=0; i<sizeof(initMessage1); i++) {Gauge_K_Line.write (initMessage1[i]); delay (10); } Serial.println (" Otpravil Ident"); Init++;} if (Init==3 && initNE==0){ Serial.print (" Otpravlyayu Ident: "); for (byte i=0; i<sizeof(initMessage1); i++) {Gauge_K_Line.write (initMessage1[i]); Serial.print (initMessage1[i], HEX); Serial.print(" "); delay (5);} Serial.println(); delay (150); ; } if (Gauge_K_Line.available() && Init==3){ initNE = 1; // ниже ищем шапку кадра byte inbyte = Gauge_K_Line.read(); Serial. print (inbyte, HEX); Serial. print (" "); delay (9); // if (inbyte == 0x02 && head_count == 0) {head_count = 1; head[0] = inbyte; } // else if (inbyte == 0xB0 && head_count == 1) {head_count = 2; head[1] = inbyte; } if (inbyte == 0xB4 ){for (byte i=0; i<sizeof(Message6F0); i++) {Gauge_K_Line.write (Message6F0[i]); delay (10);}Serial.println ("Otpravil 6F0");head_count = 0;} //else {head_count = 0; for (byte i=0; i<sizeof(head); i++) head[i] = 0;} if (inbyte == 0x13 ) {dataON = 1;} // if (inbyte == 0x02 && head_count == 0) {head_count = 4; head[0] = inbyte; } // else if (inbyte == 0x11 && head_count == 1) {head_count = 5; head[1] = inbyte; } // else if (inbyte == 0x00 && head_count == 2) {head_count = 6; head[2] = inbyte; } // else {head_count = 0; for (byte i=0; i<sizeof(head); i++) head[i] = 0;} } if (millis()- prevdata>100 && dataON){ for (byte i=0; i<sizeof(answerData); i++) {Gauge_K_Line.write (answerData[i]); } if (!dataprint) {Serial.println ("Otpravil Data"); dataprint = 1;}head_count = 0; delay (5); prevdata = millis();} }Помгла задержка 10 им между 48 и 49. Теперь так:
Постоянно первые 3 сообщения Ок, потом Фэил. И постоянно после сброса Ардуино он коннектится со второго раза. Может, мы не шлем запрос на закрытие соединения и в первый сброс приборка его закрывает? В любом случае, только три правильных ответа как-то маловато....
Оп-ком с эмулятором выдает всего лишь так:
Опель-сканер то же выдает.
Почему три правильных мало? Хватит за глаза - километраж и остаток топлива считать. Нужно заснифить какая команда идет на закрытие диагностической сессии. После двух например правильных ответов закрываем сессию и связываемся с PCM.
А как километраж тогда считать? По миллис?
В любой случае, эмулятор пока ниале, а без него где там что не понятно.
Пойду попробую увидеть комманду на закрытие. Блин, плохо что ноут всего час работает. Батарея.... :(
Раз в минуту будет к панели цепляться
Без эмуля можно цепануть ардуину и смотреть. Поехал, смотришь что меняется. Заправляешься - смотришь что меняется и т.д.
Сниф Опель-сканер. Машина не заведена. Показания такие:
02 B2 00 B4 - получается на прекращение передачи?
понятно только что первый байт после нулей 0х78 (120DEC/10) это напряжение акб. и пятый байт 0х32 (в dec 50) это температуа ДВС. Остальное зашифровано както
Возможно второй байт это напряжение датчика уровня топлива. 0x2С в DEC 44 делим на 10 получаем 4,4 В
нужно было сбросить trip пробег и опять засниффить
Кажется только температуру и расшифровали :)
Хотя нет, есть трип. В первом случае 03 03 это и есть 771, т.е. без запятой пробег Во втором случае 74 06 это и есть 1652, только байты местами поменяны. 7C FF 24 так же справа на лево это пробег - 2424700
перейду на ты. Видишь, как полезно статистику собрать, сразу все понятно стало.
осталось купить канистру с бензином.... ))
нет, не облить и поджечь,
а снять сниф, залить и ещё раз снять сниф.
Тут изменилась только температура двигателя. (ну трип и одометр не в счет)
И судя по третьему логу, он где-то в первых трех значащих байтах. Причем, первый байт с наполнением бака уменьшился, что позволяет думать, что это вольты. А второй и третий байт увеличился. Значит это литры. Вот теперь как бы это увязать с формулой. 40,5л =0х51 = 81; 22л = 0х2c = 44
Тьфу млин, да банально на два делить. Дискретность измерения бака 0,5 литра.
Интересный вопрос - где ж он напряжение берет. но в принципе оно нас не интересует, как и скорость.
Уфффф..... Кажись все данные есть. Теперь самое сложное - сам БК написать :)
напряжение зажигания скорее всего 5 байт справа. переводим в DEC один слева приписываем, а среднюю цифру не учитываем
СА = 202 , т.е 1202 , убираем ноль, ставим запятую = 12,2
дак бак , литры пополам просто делим ))
да я тоже увидел про деление на 2))
выложи скетч который с задержками выдает хотя бы три раза параметры панели
Скетч 1250 с добавление задержки 10 мс между 48 и 49, все как ты сказал. Так:
#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 int bit_time = 0; #include <SoftwareSerial.h> #define RX_gauge 7 #define TX_gauge 8 SoftwareSerial Gauge_K_line (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 (150); Gauge_K_line.write (0x7F); } 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 (10); 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!!!"); } // конец ифа с правильной CRC else Serial.println(" CRC FAIL!!!"); } } }ща скетч проверочный накатаю
вот проверяй. ту задержку в 150 можно попробовать поуменьшать, вдруг будет работать при меньшей.
#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 7 #define TX_gauge 8 SoftwareSerial Gauge_K_line (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 (150); Gauge_K_line.write (0x7F); } 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); 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!!!"); } } }периодическое обращение к панели
#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 uint32_t Odometer = 0; float FuelLevel = 0,0; byte interval_gaugesession = 1; // периодичность опроса щитка приборов, мин uint32_t prevgauge = 0; byte GAUGE_EndSession []= {0x02, 0xB2, 0x00, 0xB4}; byte GAUGE_DataRequest []= {0x02, 0x11, 0x00, 0x13}; int bit_time = 0; #include <SoftwareSerial.h> #define RX_gauge 7 #define TX_gauge 8 SoftwareSerial Gauge_K_line (RX_gauge, TX_gauge); bool InitGauge = 0; // флаг инита панели void setup() { Serial.begin (9600); //открываем соединение терминала для отладки } byte head_count = 0; byte head[4] = {0}; void loop() { if (millis() - prevgauge > (uint32_t)interval_gaugesession*60000UL){ ZAPROS_GAUGE (); GAUGE_SESSION (); } prevgauge = millis(); } void ZAPROS_GAUGE () { pinMode (TX_gauge, OUTPUT); digitalWrite (TX_gauge, 1); // BUS idle delay (250); // далее посылаем на панель адрес на скорости 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 } void GAUGE_SESSION (){ while (1) { while(!InitGauge){ if (Gauge_K_line.available()) { byte inByte = Gauge_K_line.read(); Serial.print(" "); Serial.print(inByte,HEX); if (inByte==0x80) {delay (150); Gauge_K_line.write (0x7F); } if (inByte==0x78) { delay (10); for (byte i=0; i < sizeof (GAUGE_DataRequest); i++) {Gauge_K_line.write (GAUGE_DataRequest[i]); 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!!!"); Odometer = ((uint32_t) MessageRx[26] << 16 ) | ((uint32_t) MessageRx[25] << 8 ) | MessageRx[24]; Odometer/=10; FuelLevel = MessageRx[21]/2.0 ; Serial. print ("Odometer: "); Serial. print (Odometer); Serial. print (" km, FuelLevel: "); Serial. print (FuelLevel);Serial.println (" l"); for (byte i = 0; i < sizeof (GAUGE_EndSession); i++ ) { Gauge_K_line.write (GAUGE_EndSession [i]); delay (2);} break; } // конец ифа с правильной CRC else Serial.println(" CRC FAIL!!!"); } } } }Скетч из 1272 работает хорошо. Цепляет одно сообщение с CRC Fail, думаю не проблема. Задержку уменьшил до 10 мс, работает. Одометр нужно на 10 делить, отсекая сотые метра. Убрал выбор протокола и адреса, уже ведь не нужны. Глянь, ничего не пропустил?
#include <SoftwareSerial.h> #define RX_gauge 7 #define TX_gauge 8 SoftwareSerial Gauge_K_line (RX_gauge, TX_gauge); bool InitGauge = 0; // флаг инита панели byte EndSession []= {0x02, 0xB2, 0x00, 0xB4}; void setup() { Serial.begin (9600); //открываем соединение терминала для отладки pinMode (TX_gauge, OUTPUT); digitalWrite (TX_gauge, 1); // BUS idle delay (2000); // далее посылаем на панель адрес на скорости 5 baud Serial.print("Delayu zapros na panel. Adress: "); Serial.println("0xE0, 5 baud"); digitalWrite (TX_gauge, 0); delay (5); // старт бит for(byte i = 0; i<8; i++) {digitalWrite (TX_gauge, bitRead(0xE0,i)); delay(5);} digitalWrite (TX_gauge, 1); delay (5); // стоп бит 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) { 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 (" "); } 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!!!"); } } }По периодическому обращению (скетч 1273). Если период так и оставить - 1 минута, то ничего вообще не происходит. Думал, он только через минуту обратиться, но нет. А вот если поставить 1/2, то так:
Т.е. не успев закончить получение, опять начинает запрос, ловит пару последних данных с неверным CRC и на этом виснет.
В принципе, я думаю, это периодическое обращение нужно уже в код готового скетча добавлять, чтоб было видно куда и как. Перед этим запросом нужно ж будет закрывать соединение с ЭБУ.
Кстати, нужно проверить как с ЭБУ данные читаться будут.
Пытаюсь что-то накропать сам. К сожалению, и так не программист, а тут чужой код понять нужно. Для начала постарался вырезать все, что касается LCD, чтоб он мне просто пиды в серийник выводил.
#include <SoftwareSerial.h> SoftwareSerial mySerial (12, 13); //RХ,TХ #define TX 13 unsigned long TimewaitPID, timerwaitPID = 0; bool timerenabledPID = 0; #define TIMEREXPIRED_PID (TimewaitPID - timerwaitPID)> 200 // здесь задержка на ожидание правильного ответа пидов, мс unsigned long TimewaitInit, timerwaitInit = 0; bool timerenabledInit = 0; #define TIMEREXPIRED_Init (TimewaitInit - timerwaitInit)> 500 // здесь задержка на ожидание ответа об удачной инициализации, мс byte messageInit[5] = {0x81, 0x11, 0xF1, 0x81, 0x04}; // запрос инициализации byte messagePids[6] = {0x82,0x11,0xF1,0x21,0x01,0xA6}; // запрос пид 2101 byte messagePresent[5] = {0x81,0x11,0xF1,0x3E,0xC1}; // запрос присутствия unsigned long prevPID = 0; int PIDTime = 120; // задержка ожидания запроса следующего pid 2101, мс unsigned long prevpres = 0; int PresTime = 8000; // задержка между посылками запросов присутствия, мс int waitbyte = 1; // задержка между отправкой байт в сообщении, мс byte MessageRx[55] = {0}; // массив байтов принимаемого сообщения bool Init = 0; int MAP = 0; //13 байт Датчик абсолютного давления float SysVolt = 0; //14 байт Напряжение в сети int TempAir = 0; //16 байт Температура воздуха в градусах int Temp = 0; //18 байт Температура охлаждающей жидкости в градусах int EngLoad = 0; //20 байы нагрузка на двигатель int Throtle = 0; //28 байт Открытие дроссельной заслонки в процентах int RPM = 0; //30 байт Оборогты двигателя int Speed = 0; //29 байт Скорость float InjPulse = 0; //31 байт Время впрыска форсунок int IdleAir = 0; //32 байт Клапан холостого хода, шаги float O2sens = 0; //35 байт Лямбда мВ float O2int = 0; //36 байт Интегратор лямда, шагов float FuelRatio = 0; //41 байт Соотношение воздуха/топлива int STFT = 0; // Краткосрочная коррекция топлива ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //стартовая инициализация 7 пина ОБД //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 mySerial.begin(10400); } // baud rate of the OBD /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //отправка запроса на диагностическое соединение /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void initialization() { Serial.println ("Otpravil zapros Init"); for (int i = 0; i < 5; i++) { mySerial.write(messageInit[i]); delay (5); } delay (55); } /////////////////////////////////////////////////////////////////////////// //VOID PIDs// отправка запроса пид 2101//////////////////////////////////// /////////////////////////////////////////////////////////////////////////// void PIDs() { Serial.println ("Otpravil zapros 21 01"); for (int i = 0; i < 6; i++) { mySerial.write(messagePids[i]); delay (waitbyte); }} /////////////////////////////////////////////////////////////////////////// //BOID PIDsGAUGR//отправка запроса присутствия///////////////////////////// /////////////////////////////////////////////////////////////////////////// void present() { Serial.println ("Otpravil zapros Present"); for (int i = 0; i < 55; i++) { mySerial.write(messagePresent[i]); delay (waitbyte); }} ///////////////////////////////////////////////////////////////////////////////////////////// //получение данных от ЭБУ, разборка входящих сообщений ///////////////////////////////////////////////////////////////////////////////////////////// void receive () { //////////////////////////////////////////////////////////////////// ////////////////// работа с К-Line софт сериал 12-13 (7 контакт ОБД) //////////////////////////////////////////////////////////////////// if (mySerial.available()) { delay(195); int k=0; byte inbyte=0; while( mySerial.available() && k < 55) { inbyte = mySerial.read(); MessageRx[k] = inbyte; k++; } Serial.print ("Receive: "); for (int i = 0; i < k; i++) { Serial.print(MessageRx[i],HEX); Serial.print (" ");} Serial.println (""); if (MessageRx[2]==0x83 && MessageRx[3]==0xF1 && MessageRx[4]==0x11 && MessageRx[5]==0xC1 && MessageRx[6]==0x6B && MessageRx[7]==0x8F && MessageRx[8]==0x40) {Init=1; timerenabledInit=0; Serial.println (" Initialization OK!!!!: "); } /////////////////////////////////////////////////////////////////////////////////////////////////// //Чтение и стирание ошибок /////////////////////////////////////////////////////////////////////////////////////////////////// //при получении этого сообщения выдавать на третий экран "NO ERROR" if (MessageRx[4]==0x82 && MessageRx[5]==0xF1 && MessageRx[6]==0x11 && MessageRx[7]==0x58 && MessageRx[8]==0x00 && MessageRx[9]==0xDC){ Serial.println (" NO DTC "); } //при получении этого сообщения выдавать на третий экран "CLEAR DTC" if (MessageRx[3]==0x83 && MessageRx[4]==0xF1 && MessageRx[5]==0x11 && MessageRx[6]==0x54 && MessageRx[7]==0xFF && MessageRx[8]==0x00 && MessageRx[9]==0xD8){ Serial.println (" DTC CLEARED "); } // при получении сообщения о наличии ошибок DTC разберем сообщение выведем на экран ошибки if (MessageRx[5]==0xF1 && MessageRx[6]==0x11 && MessageRx[7]==0x58 && MessageRx[8]>0){ Serial.println ("DTC is found!"); for (int i=0; i<MessageRx[8]; i++ ) { int y = i*35; bool nolA=0; bool nolB =0; if (!bitRead(MessageRx[11+(i*3)],6) && bitRead(MessageRx[11+(i*3)],7)){ Serial.println(" -Passive-");} // если DTC пасивныый делаем цвет зеленый if (bitRead(MessageRx[11+(i*3)],7) && bitRead(MessageRx[11+(i*3)],6)) { Serial.println(" -Active-");} // если DTC активный, делаем цвет красный Serial.println("ERROR "); Serial.println(i+1); if (!bitRead(MessageRx[9+(i*3)],6) && !bitRead(MessageRx[9+(i*3)],7)) Serial.println(": P"); if (bitRead(MessageRx[9+(i*3)],6) && !bitRead(MessageRx[9+(i*3)],7)) Serial.println(": C"); if (!bitRead(MessageRx[9+(i*3)],6) && bitRead(MessageRx[9+(i*3)],7)) Serial.println(": B"); if (bitRead(MessageRx[9+(i*3)],6) && bitRead(MessageRx[9+(i*3)],7)) Serial.println(": U"); }} /////////////////////////////////////////////////////////////////////////////////////////////////////////// //прописываем формулы к данным /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////////// else if (MessageRx[4]==0xB0 && MessageRx[5]==0xF1 && MessageRx[6]==0x11 && MessageRx[7]==0x61 && MessageRx[8]==0x01) { MAP = (MessageRx[16]*4,97/255); //13 байт Датчик абсолютного давления SysVolt = (MessageRx[17]/10); //14 байт Напряжение в сети TempAir = ((MessageRx[19]*191/255)-40); //16 байт Температура воздуха в градусах Temp = ((MessageRx[21]*191/255)-40); //18 байт Температура охлаждающей жидкости в градусах EngLoad = (MessageRx[23]*100/255); //20 байы нагрузка на двигатель Throtle = (MessageRx[31]*100/255); //28 байт Открытие дроссельной заслонки в процентах RPM = (MessageRx[33]*6375/255); //30 байт Оборогты двигателя Speed = (MessageRx[32]); //29 байт Скорость InjPulse = (MessageRx[34]*21,8/255); //31 байт Время впрыска форсунок IdleAir = (MessageRx[35]); //32 байт Клапан холостого хода, шаги O2sens = (MessageRx[38]*1127/255); //35 байт Лямбда мВ O2int = (MessageRx[39]); //36 байт Интегратор лямда, шагов FuelRatio = (MessageRx[44]/10); //41 байт Соотношение воздуха/топлива int STFT = (MessageRx[39]*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.print(STFT); timerenabledPID=0; } for (int i = 0; i < 55; i++) MessageRx[i]=0; }} // очистка байтов массива ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //SETUP ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void setup() { Serial.begin(115200); mySerial.begin(10400); pinMode(TX, OUTPUT); fastinit(); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //loop ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void loop() { TimewaitPID = millis (); TimewaitInit = millis (); if (!Init) { if (!timerenabledInit){ timerwaitInit=TimewaitInit; timerenabledInit=1; initialization(); } else if (TIMEREXPIRED_Init) timerenabledInit=0;} if (millis() - prevPID > PIDTime) { PIDs(); prevPID = millis(); } else if (millis() - prevpres > PresTime) {present(); prevpres = millis();} receive (); }Но получил только так:
Где чего крутить?
И каким-то чудом один раз все же мне выдало показания, но часть из них почему-то неверны. Я бы понял, если б все, но тут только часть. Вот этого вообще не могу понять. Например температура двигателя почему -162 ? По формуле она максимум -40 может быть. Из-за неверного типа переменных такое возможно?
с панелью нужно до конца разобраться, почему не работает периодический запрос. А с PCM будет время, попробую упрощённый скетч накидать
да такое возможно
Скобки.... Либо их где-то не хватает, либо они не там, где надо.... Если скобка стоит после GAUGE_SESSION (); , то prevgauge на каждом цикле равен millis :)
#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 uint32_t Odometer = 0; float FuelLevel = 0,0; byte interval_gaugesession = 1; // периодичность опроса щитка приборов, мин uint32_t prevgauge = 0; byte GAUGE_EndSession []= {0x02, 0xB2, 0x00, 0xB4}; byte GAUGE_DataRequest []= {0x02, 0x11, 0x00, 0x13}; int bit_time = 0; #include <SoftwareSerial.h> #define RX_gauge 7 #define TX_gauge 8 SoftwareSerial Gauge_K_line (RX_gauge, TX_gauge); bool InitGauge = 0; // флаг инита панели void setup() { Serial.begin (9600); //открываем соединение терминала для отладки } byte head_count = 0; byte head[4] = {0}; void loop() { if (millis() - prevgauge > (uint32_t)interval_gaugesession*60000UL){ ZAPROS_GAUGE (); GAUGE_SESSION (); prevgauge = millis(); } } void ZAPROS_GAUGE () { pinMode (TX_gauge, OUTPUT); digitalWrite (TX_gauge, 1); // BUS idle delay (250); // далее посылаем на панель адрес на скорости 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 } void GAUGE_SESSION (){ while (1) { while(!InitGauge){ if (Gauge_K_line.available()) { byte inByte = Gauge_K_line.read(); Serial.print(" "); Serial.print(inByte,HEX); if (inByte==0x80) {delay (150); Gauge_K_line.write (0x7F); } if (inByte==0x78) { delay (10); for (byte i=0; i < sizeof (GAUGE_DataRequest); i++) {Gauge_K_line.write (GAUGE_DataRequest[i]); 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!!!"); Odometer = ((uint32_t) MessageRx[26] << 16 ) | ((uint32_t) MessageRx[25] << 8 ) | MessageRx[24]; Odometer/=10; FuelLevel = MessageRx[21]/2.0 ; Serial. print ("Odometer: "); Serial. print (Odometer); Serial. print (" km, FuelLevel: "); Serial. print (FuelLevel);Serial.println (" l"); for (byte i = 0; i < sizeof (GAUGE_EndSession); i++ ) { Gauge_K_line.write (GAUGE_EndSession [i]); delay (2);} break; } // конец ифа с правильной CRC else Serial.println(" CRC FAIL!!!"); } } } }Для пробы уменьшил интервал до 10 секунд. Так вот, первый запрос проходит хорошо и данные получает. А вот второй, через десять секунд, получает два сообщения CRC Fail и программа дальше никуда уже не двигается. Кажись, что-то не то шлем на закрытие соединения.....
Чисто мои мысли, исходя из лога:
После инициализации, мы ждем байта 0х80 и шлем 0x7F. Затем ищем 0x78 и сразу шлем запрос пидов. Но ведь IDEN от приборки приходит два раза. Может второй раз нужно подождать ответ...
Потом Опель-сканер отправляет 02 B0 00 B2 и получает дважды ответ (присутствия?) 06 F0 AA 10 32 10 01 F2.... И только потом уже шлет запрос на пиды 02 11 00 13.... Не кроется ли тут причина остальных неверных сообщений?
При прекращении запросов пид он шлет 02 B2 00 B4, но в ответ получает еще один отзыв присутствия. Вот интересно как же он все-таки закрывает соединение? Нет ли в описании протокола каких-то подсказок, типа как с инициализацией на 5 бод?
возможно, действительно нужно реагировать, только получив два раза иденты от приборки . Завтра будет время набросаю скетч.
щас скетч по PCM скину
скетч PCM, формулы корявые конечно, нужно разбираться. UPDATE: почти разобрались
#include <SoftwareSerial.h> SoftwareSerial mySerial (12, 13); //RХ,TХ #define TX 13 #define K_LINE mySerial uint32_t timerwaitInit = 0; bool timerenabledInit = 0; byte messageInit[] = {0x81, 0x11, 0xF1, 0x81, 0x04}; // запрос инициализации byte messagePids[] = {0x82,0x11,0xF1,0x21,0x01,0xA6}; // запрос пид 2101 byte messagePresent[] = {0x81,0x11,0xF1,0x3E,0xC1}; // запрос присутствия unsigned long prevPID = 0; int PIDTime = 90; // задержка ожидания запроса следующего pid 2101, мс int delaybyte = 1; // задержка между отправкой байт в сообщении, мс byte header = 0; // сосояние заголовка byte message_size = 0; // размер тела сообщения byte j = 3; // инкремент const byte bufsize = 100; // размер буфера принятого сообщения byte buf [bufsize] = {0}; // буфер принятого сообщения byte waitbyte_time = 1; // задержка, мс для успевания появления данных в буфере RX (подрегулировать в зависимости от уровня жизнидеятельности на Марсе) uint32_t timerdelay = 0; // таймер ожидания байт (для успевания появления данных в буфере UART) bool Delay = 0; // таймер ожидания байт (для успевания появления данных в буфере UART) #define TIMER_DELAY Delay = 0; timerdelay = curmillis // включение таймера byte crc =0; // байт контрольной суммы bool Init = 0; // флаг выполнен ли инит PCM 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 байт Соотношение воздуха/топлива unsigned int STFT = 0; // Краткосрочная коррекция топлива void setup() { Serial.begin(115200); mySerial.begin(10400); pinMode(TX, OUTPUT); fastinit(); } void loop() { // если инит ещё не выполнен, шлём периодически запрос инит if (!Init) { if (!timerenabledInit){ timerwaitInit=millis(); timerenabledInit=1; Serial.println ("Otpravil zapros Init"); for (byte i = 0; i<sizeof(messageInit); i++) {mySerial.write(messageInit[i]); delay (5);} delay (55); } else if (millis() - timerwaitInit > 500 ) timerenabledInit=0;} //иначе периодически шлём запросы пидов else { if ((millis() - prevPID > PIDTime) && header==0 ) { Serial.println ("Otpravil zapros 21 01"); for (int i = 0; i < sizeof(messagePids); i++) {mySerial.write(messagePids[i]); delay (delaybyte); } prevPID = millis(); } } //разбор входящих сообщений 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 mySerial.begin(10400); } // baud rate of the OBD //получение данных от ЭБУ, разборка входящих сообщений void receive () { uint32_t curmillis = millis(); 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; 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; } // третий старт байт 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]; header = 3; bitWrite (message_size, 7 , 0); if (message_size > bufsize) message_size = bufsize; j=3; crc = 0;} else header = 0; } // пишем тело сообщения if (header == 3 && Delay && j< message_size+4) { buf[j] = K_LINE.read(); if (j<message_size+3) crc+= buf[j]; // подсчёт КС if (j==message_size+3) header = 4; TIMER_DELAY ; Serial.print (buf[j], HEX); Serial.print (" "); j++;} } // сообщение приняли, действуем if (header == 4) {TIMER_DELAY ; Serial.println(); for(byte i = 0; i<3; i++) crc+=buf[i]; // прибавляем к контрольной сумме первые 3 байта // если контрольная сумма верна: if ( crc == buf[message_size+3]) {Serial.println("Received message is OK!" ); // Если КС совпала, тут чёнибудь нужное делаем if (buf[3]==0xC1 && buf[4]==0xEF && buf[5]==0x8F) {Init=1; timerenabledInit=0; Serial.println (" Initialization OK!!!!: "); } else if (buf[3]==0x58 && buf[4]==0x00) Serial.println (" NO DTC "); else if (buf[3]==0x58 && buf[4] >0x00) Serial.println (" DTC is found!"); else if (buf[3]==0x54 && buf[4]==0xFF && buf[5]==0x00) Serial.println (" DTC CLEARED "); else if (buf[3]==0x61 && buf[4]==0x01) { Serial.println (" Receive DATA"); MAP = ((uint16_t)buf[12]*1.04/255.0); //13 байт Датчик абсолютного давления 102mbar SysVolt = ((float)buf[13]/10.00); //14 байт Напряжение в сети 12.1v {double t , cel , drob ; t = (buf[15]*191ul/255.0)-40; //16 байт Температура воздуха в градусах 50 drob = modf(t, &cel); if (drob>=0.5) cel++; TempAir = cel;} {double t , cel , drob ; t = (buf[17]*191ul/255.0)-40; //18 байт Температура охлаждающей жидкости в градусах104 drob = modf(t, &cel); if (drob>=0.5) cel++; Temp = cel;} EngLoad = ((uint16_t)buf[19]*100/255); //20 байы нагрузка на двигатель7% Throtle = ((uint16_t)buf[27]*100/255); //28 байт Открытие дроссельной заслонки в процентах 0 RPM = ((uint32_t)buf[29]*6375ul/255ul); //30 байт Оборогты двигателя 0 Speed = (buf[28]); //29 байт Скорость 0 InjPulse = ((float)buf[30]*21.8/255.0); //31 байт Время впрыска форсунок 11.9 IdleAir = (buf[31]); //32 байт Клапан холостого хода, шаги 38 O2sens =(uint32_t) buf[34]*1127ul/255ul; //35 байт Лямбда мВ 380 O2int = (buf[35]); //36 байт Интегратор лямда, шагов 128 FuelRatio = ((float)buf[40]/10.00); //41 байт Соотношение воздуха/топлива 12.3 int STFT = (((uint16_t)buf[35]-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; j=3; crc = 0; } if (!Delay && curmillis - timerdelay > waitbyte_time) Delay = 1; // таймер ожидания байт (для успевания появления данных в буфере UART) }Ок, завтра запроверю че покажет. Пару вопросов, так сказать для общего развития.
Для чего uint16_t? Это ж, если я правильно понимаю, объявление длины переменной в 16 бит.... Просто до этого было вообще MessageRx[16] и усе. И вкладывалось значение в ранее объявленную переменную float MAP = 0; (кстати МАП с точкой, потому с float)
И второй вопросик, я то ориентировался по снифу, где в логе
первые 3 байта - FF, потому вместо 13 байта брал 16. А тут в скейче наоборот, сдвинуто все в лево на один. Ну, хочется понять. Может повтыкаю в код хорошо, да дойдет.... как до жирафа
Почему формулы корявые? Я проверял на эмуляторе, все сошлось отлично.
Для чего uint16_t? Это ж, если я правильно понимаю, объявление длины переменной в 16 бит.... Просто до этого было вообще MessageRx[16] и усе. И вкладывалось значение в ранее объявленную переменную float MAP = 0; (кстати МАП с точкой, потому с float)
когда пишем формулу, то в ней нужно приводить все переменные к одному типу. например MessageRx[16] это тип byte у которого диапазон от 0 до 255. и если его умножить на 100, например, он выйдет за пределы и возможна ошибка в формуле, поэтому я на всякий привел к двухбатовому числу. числовые константы, на сколько знаю, имеют тип int , поэтому их тоже нужно переводить соответвующе.
FF пробегали потому что мы с ТС очень корявый вариант разбора входящих сообщений сделали. delay там используется. По факту на шине FF скорее всего не пробегают. Щас опыта прибавилось немного. Поэтому пробуем по правильному принимать, без лишних байт. все как положено с Checksum. А влево сдвинуто на один, т.к номера байт в программировании с нулевого начинаются. а в описании разбайтовки мы написали, начиная с первого.
Почему формулы корявые? Я проверял на эмуляторе, все сошлось отлично.
не знаю как ты проверял. Например MAР в mbar чтобы получить , нужна такая формула . (подбирал по эмулятору)
MAP = (buf[12]*100/245);
и т.д.
Так и я по эмулятору. 13 байт ставим равным 0, минимальное значение МАП = 0 Бар, ставим равным 255 - максимальное - 1,04 бар. Вот и получается X*1.04/255=Bar
С остальными параметрами так же. Например, обороты двигателя при 0х00 = 0, а при 0хFF = 6375. Вот и получается X*6375/255
Почему у тебя 245?
У меня формулы вида X*100/255 - выдают проценты. Типа нагрузка на двигатель или процент открытия дроссельной заслонки.
Ладно, собственно, чего думать, пойти и проверить :)
в скетче #1282 исправил формулы
Так не показывает данные, только message ok.
Закомментировал что относится к ошибкам, перенёс пару скобок. Стало показывать, но везде по нулям. Т.е. буфер сообщения пуст.
#include <SoftwareSerial.h> SoftwareSerial mySerial (12, 13); //RХ,TХ #define TX 13 #define K_LINE mySerial unsigned long TimewaitPID, timerwaitPID = 0; bool timerenabledPID = 0; #define TIMEREXPIRED_PID (TimewaitPID - timerwaitPID)> 200 // здесь задержка на ожидание правильного ответа пидов, мс unsigned long TimewaitInit, timerwaitInit = 0; bool timerenabledInit = 0; #define TIMEREXPIRED_Init (TimewaitInit - timerwaitInit)> 500 // здесь задержка на ожидание ответа об удачной инициализации, мс byte messageInit[] = {0x81, 0x11, 0xF1, 0x81, 0x04}; // запрос инициализации byte messagePids[] = {0x82,0x11,0xF1,0x21,0x01,0xA6}; // запрос пид 2101 byte messagePresent[] = {0x81,0x11,0xF1,0x3E,0xC1}; // запрос присутствия unsigned long prevPID = 0; int PIDTime = 120; // задержка ожидания запроса следующего pid 2101, мс unsigned long prevpres = 0; int PresTime = 8000; // задержка между посылками запросов присутствия, мс int waitbyte = 1; // задержка между отправкой байт в сообщении, мс byte header = 0; // сосояние заголовка byte message_size = 0; // размер тела сообщения byte j = 3; // инкремент const byte bufsize = 100; // размер буфера принятого сообщения byte buf [bufsize] = {0}; // буфер принятого сообщения byte waitbyte_time = 1; // задержка, мс для успевания заполнения буфера RX (подрегулировать в зависимости от уровня жизнидеятельности на Марсе) uint32_t timerdelay = 0; // таймер ожидания байт (для успевания заполнения буфера УАРТ) bool Delay = 0; // таймер ожидания байт (для успевания заполнения буфера УАРТ) byte crc =0; // байт контрольной суммы #define TIMER_DELAY Delay = 0; timerdelay = curmillis // включение таймера bool Init = 0; float MAP = 0; //13 байт Датчик абсолютного давления float SysVolt = 0; //14 байт Напряжение в сети int TempAir = 0; //16 байт Температура воздуха в градусах int Temp = 0; //18 байт Температура охлаждающей жидкости в градусах int EngLoad = 0; //20 байы нагрузка на двигатель int Throtle = 0; //28 байт Открытие дроссельной заслонки в процентах unsigned int RPM = 0; //30 байт Оборогты двигателя unsigned int Speed = 0; //29 байт Скорость float InjPulse = 0; //31 байт Время впрыска форсунок unsigned int IdleAir = 0; //32 байт Клапан холостого хода, шаги float O2sens = 0; //35 байт Лямбда мВ float O2int = 0; //36 байт Интегратор лямда, шагов float FuelRatio = 0; //41 байт Соотношение воздуха/топлива int STFT = 0; // Краткосрочная коррекция топлива ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //стартовая инициализация 7 пина ОБД //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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 mySerial.begin(10400); } // baud rate of the OBD /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //отправка запроса на диагностическое соединение /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void initialization() { Serial.println ("Otpravil zapros Init"); for (int i = 0; i < sizeof(messageInit); i++) { mySerial.write(messageInit[i]); delay (5); } delay (55); } /////////////////////////////////////////////////////////////////////////// //VOID PIDs// отправка запроса пид 2101//////////////////////////////////// /////////////////////////////////////////////////////////////////////////// void PIDs() { Serial.println ("Otpravil zapros 21 01"); for (int i = 0; i < sizeof(messagePids); i++) { mySerial.write(messagePids[i]); delay (waitbyte); }} /////////////////////////////////////////////////////////////////////////// //VOID Preent//отправка запроса присутствия///////////////////////////// /////////////////////////////////////////////////////////////////////////// void present() { Serial.println ("Otpravil zapros Present"); for (int i = 0; i < sizeof(messagePresent); i++) { mySerial.write(messagePresent[i]); delay (waitbyte); }} ///////////////////////////////////////////////////////////////////////////////////////////// //получение данных от ЭБУ, разборка входящих сообщений ///////////////////////////////////////////////////////////////////////////////////////////// void receive () { byte curmillis = millis(); if (K_LINE.available() ){ // первый старт байт if (header == 0 && Delay){TIMER_DELAY ; buf[0]=K_LINE.read(); Serial.print (buf[0], HEX); Serial.print (" "); if (bitRead (buf[0],7)){ header = 1; }} // второй старт байт 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; } // третий старт байт 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]; header = 3; bitWrite (message_size, 7 , 0); // message_size+=1; if (message_size > bufsize) message_size = bufsize; j=3; crc = 0;} else header = 0; } // пишем тело сообщения if (header == 3 && Delay && j< message_size+4) { buf[j] = K_LINE.read(); if (j<message_size+3) crc+= buf[j]; // подсчёт КС if (j==message_size+3) header = 4; TIMER_DELAY ; Serial.print (buf[j], HEX); Serial.print (" "); j++;} } // сообщение приняли, действуем if (header == 4) {TIMER_DELAY ; Serial.println(); for(byte i = 0; i<3; i++) crc+=buf[i]; // прибавляем к контрольной сумме первые 3 байта if ( crc == buf[message_size+3]) {Serial.println("Received message is OK!" ); // Если КС совпала, тут чёнибудь нужное делаем // if (buf[3]==0xC1 && buf[4]==0x6B && buf[5]==0x8F) {Init=1; timerenabledInit=0; Serial.println (" Initialization OK!!!!: "); } // else if (buf[3]==0x58 && buf[4]==0x00) Serial.println (" NO DTC "); // else if (buf[3]==0x58 && buf[4] >0x00) Serial.println (" DTC is found!"); // else if (buf[3]==0x54 && buf[4]==0xFF && buf[5]==0x00) Serial.println (" DTC CLEARED "); // else if (buf[3]==0x61 && buf[4]==0x01) { Serial.println (" Receive DATA"); MAP = ((uint16_t)buf[12]*1.04/255); //13 байт Датчик абсолютного давления SysVolt = ((float)buf[13]/10.00); //14 байт Напряжение в сети TempAir = (((uint16_t)buf[15]*191/255)-40); //16 байт Температура воздуха в градусах Temp = (((uint16_t)buf[17]*191/255)-40); //18 байт Температура охлаждающей жидкости в градусах EngLoad = ((uint16_t)buf[19]*100/255); //20 байы нагрузка на двигатель Throtle = ((uint16_t)buf[27]*100/255); //28 байт Открытие дроссельной заслонки в процентах RPM = ((uint16_t)buf[29]*6375/255); //30 байт Оборогты двигателя Speed = (buf[28]); //29 байт Скорость InjPulse = ((uint16_t)buf[30]*21,8/255); //31 байт Время впрыска форсунок IdleAir = (buf[31]); //32 байт Клапан холостого хода, шаги O2sens = ((uint16_t)buf[34]*1127/255); //35 байт Лямбда мВ O2int = (buf[35]); //36 байт Интегратор лямда, шагов FuelRatio = ((float)buf[40]/10); //41 байт Соотношение воздуха/топлива // int STFT = (((uint16_t)buf[35]-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); timerenabledPID=0; } //} else Serial.println("CRC fail!!!" ); message_size = 0; header=0; j=3; crc = 0; } if (!Delay && curmillis - timerdelay > waitbyte_time) Delay = 1; // таймер ожидания байт (для успевания заполнения буфера УАРТ) } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //SETUP ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void setup() { Serial.begin(115200); mySerial.begin(10400); pinMode(TX, OUTPUT); fastinit(); } void loop() { TimewaitPID = millis (); TimewaitInit = TimewaitPID; // если инит ещё не выполнен, шлём периодически запрос инит if (!Init) { if (!timerenabledInit){ timerwaitInit=TimewaitInit; timerenabledInit=1; initialization(); } else if (TIMEREXPIRED_Init) timerenabledInit=0;} //иначе шлём запросы пидов else { if (millis() - prevPID > PIDTime ) {PIDs(); prevPID = millis(); } } //разбор входящих сообщений receive (); }И получаем так:
Хм.... получается, он вместо запроса 21 01 постоянно шлет запрос инит. Тут где-то собака порылась...
постоянно шлёт инит, т.к. после отправки запроса инита не получаем правильного сообщения от PCM. А это, в свою очередь, происходит из-за того, что keyword при разборе входящего сообщения перепутали.
исправил данный косяк в #1282
ну а скобки ты конечно убрал... Это похоже как студенты на лабораторных работах измерения под результат подгоняют....
Скобки.... Либо их где-то не хватает, либо они не там, где надо.... Если скобка стоит после GAUGE_SESSION (); , то prevgauge на каждом цикле равен millis :)
Для пробы уменьшил интервал до 10 секунд. Так вот, первый запрос проходит хорошо и данные получает. А вот второй, через десять секунд, получает два сообщения CRC Fail и программа дальше никуда уже не двигается. Кажись, что-то не то шлем на закрытие соединения.....
Всё там нормально со скобками. prevgauge присваивается значение millis не каждый проход луп, а только когда выполняется условие if a.
вот сделал интервал можно изменять в секундах, добавил двойное ожидание идентов от панели.
#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 uint32_t Odometer = 0; float FuelLevel = 0; byte interval_gaugesession = 10; // периодичность опроса щитка приборов, сек uint32_t prevgauge = 0-(interval_gaugesession*1000UL); uint32_t prevsec=0; byte GAUGE_EndSession []= {0x02, 0xB2, 0x00, 0xB4}; byte GAUGE_DataRequest []= {0x02, 0x11, 0x00, 0x13}; int bit_time = 0; #include <SoftwareSerial.h> #define RX_gauge 7 #define TX_gauge 8 SoftwareSerial Gauge_K_line (RX_gauge, TX_gauge); byte InitGauge = 0; // флаг инита панели void setup() { Serial.begin (9600); //открываем соединение терминала для отладки delay(10); } byte head_count = 0; byte head[4] = {0}; void loop() { if (millis()-prevsec>1000){ Serial.println ((millis()-prevgauge)/1000+1); prevsec = millis();} if (millis() - prevgauge > (uint32_t)interval_gaugesession*1000UL){ Serial.println ("Prohod cylce loop"); Serial.println(); // для контроля как часто пробегает цикл луп ZAPROS_GAUGE (); GAUGE_SESSION (); prevgauge = millis(); } } void ZAPROS_GAUGE () { pinMode (TX_gauge, OUTPUT); digitalWrite (TX_gauge, 1); // BUS idle delay (250); // далее посылаем на панель адрес на скорости 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 } void GAUGE_SESSION (){ Serial.println ("function Gauge Session"); uint16_t p = 0; while (p<2000) { uint16_t v = 0; while(InitGauge<2 && v<2000){ 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); } if (inByte==0x78) { delay (10); for (byte i=0; i < sizeof (GAUGE_DataRequest); i++) {Gauge_K_line.write (GAUGE_DataRequest[i]); delay (2);} InitGauge++; Serial.print(" Receive Panel ID "); Serial.println (InitGauge);}}v++;} 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!!!"); Odometer = ((uint32_t) MessageRx[26] << 16 ) | ((uint32_t) MessageRx[25] << 8 ) | MessageRx[24]; Odometer/=10; FuelLevel = MessageRx[21]/2.0 ; Serial. print ("Odometer: "); Serial. print (Odometer); Serial. print (" km, FuelLevel: "); Serial. print (FuelLevel);Serial.println (" l"); for (byte i = 0; i < sizeof (GAUGE_EndSession); i++ ) { Gauge_K_line.write (GAUGE_EndSession [i]); delay (2);} break; } // конец ифа с правильной CRC else Serial.println(" CRC FAIL!!!"); } } p++; } Serial.println("Gauge_session is end"); }Лог РСМ с моей формулой МАП, т.е. Х*1,04/255, а так же поправил формулу для коррекции, не верно ее написал. Вот так надо: int STFT = (((uint16_t)buf[35]-128)*100/128);
Initialization OK!!!!: Otpravil zapros 21 01 B0 F1 11 61 1 1 1 70 22 0 0 0 4B 8B 4E 64 6B AB 86 17 34 A 1 0 0 0 1E 0 0 22 25 1B C 44 47 80 12 6F 0 0 92 0 0 4 CC A 7 34 0 0 0 E1 Received message is OK! Receive DATA MAP=0.32 Battery=13.90 Air=34 Temp=88 EngLoad=9 Throtle=0 RPM=850 Speed=0 Inj=3.16 IdleAir=27 O2sens=313 O2int=128 FuelRatio=14.60 STFT=0 Otpravil zapros 21 01 B0 F1 11 61 1 1 1 70 22 0 0 0 4B 8B 4E 64 6B AB 86 17 34 A 1 0 0 0 1E 0 0 22 25 1B C 44 47 80 12 6F 0 0 92 0 0 4 CC A 7 34 0 0 0 E1 Received message is OK! Receive DATA MAP=0.32 Battery=13.90 Air=34 Temp=88 EngLoad=9 Throtle=0 RPM=850 Speed=0 Inj=3.16 IdleAir=27 O2sens=313 O2int=128 FuelRatio=14.60 STFT=0 Otpravil zapros 21 01 B0 F1 11 61 1 1 1 70 22 0 0 0 4A 8B 4E 64 6B AB 82 17 34 A 1 0 0 0 1E 0 0 23 24 1B C 44 47 80 12 6F 0 0 92 0 0 4 CC A 7 34 0 0 0 DC Received message is OK!Все показывает отлично. Осталось с ошибками разобраться как глядеть/расшифорвывать и стирать. Прикрутить кнопку к Дуне для перехода в режим ошибок и стирания?
А вот с приборкой так происходит:
После включения идет до:
Стоит секунд 30 и дальше:
Т.е. так происходит каждый второй раз.
"Всё там нормально со скобками. prevgauge присваивается значение millis не каждый проход луп, а только когда выполняется условие if a"
А ты в свой глянь, из 1273 строка 39 ;) Там как раз prevgauge был вынесен за условие
да, твоя правда, почему то не заметил сразу. Смотри ка по панели , ведь после первого идента начинает нормально сыпать сообщениями с данными. поправлю позже код может, нормально заработает
добавил в #1282 округление температур, теперь температуры достоверно показывают. И формулу MAP как у тебя сделал. Не понятно почему в твоём логе показывает мап 0.32 когда должно по эмулю 0,31. С моей формулой как положено 0,31 показывает.
Сыпать он начинает, но почему то инициализация только каждый второй раз проходит.
Округление разное, по ходу. Ну для сравнить завтра захвачу Опель-сканер, посмотрим как он покажет.
STFT кстати, должно быть int, т.к. коррекция идет от -100% до +100%.
добавил
- в разбор входящих сообщений дополнительный байт длины при его наличии
- чтение ошибок - короткое нажатие на кнопку (подключена пин 4)
- удаление ошибок - длительное нажатие на кнопку (подключена пин 4)
Логика такая - коротко нажимаем на кнопку - запросы 2101 перестают подаваться, а подаются запросы чтения ошибок, пока не получим ответ с ошибками, если ответ получили - далее опять долбим запросами 2101
длительно нажимаем на кнопку - запросы 2101 перестают подаваться, а подаются запросы удаления ошибок, пока не получим отчёт что DTC удалены , если отчёт получили - далее опять долбим запросами 2101
библиотека взаимодейтсвия с тактовыми кнопками
#include <Button.h> Button test; #include <SoftwareSerial.h> SoftwareSerial mySerial (12, 13); //RХ,TХ #define TX 13 #define K_LINE mySerial #define PID 1 #define DTCREAD 2 #define DTCERASE 3 uint32_t timerwaitInit = 0; bool timerenabledInit = 0; 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 prevPID = 0; uint32_t prevRESETheader=0; int PIDTime = 100; // задержка ожидания следующего запроса , мс bool timerPID_ON; // таймер сброса заголовка если в момент приёма заголовка данные оборвались int delaybyte = 1; // задержка между отправкой байт в сообщении, мс byte request =PID; // переменная, показывающая запрос чего будем делать byte header = 0; // сосояние заголовка byte message_size = 0; // размер тела сообщения byte j = 3; // инкремент byte n = 3; // количество старт байт const byte bufsize = 100; // размер буфера принятого сообщения byte buf [bufsize] = {0}; // буфер принятого сообщения byte waitbyte_time = 1; // задержка, мс для успевания появления данных в буфере RX (подрегулировать в зависимости от уровня жизнидеятельности на Марсе) uint32_t timerdelay = 0; // таймер ожидания байт (для успевания появления данных в буфере UART) bool Delay = 0; // таймер ожидания байт (для успевания появления данных в буфере UART) #define TIMER_DELAY Delay = 0; timerdelay = curmillis // включение таймера byte crc =0; // байт контрольной суммы bool Init = 0; // флаг выполнен ли инит PCM 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; // Краткосрочная коррекция топлива #define BUTTON_PIN 4 // пин подключения тактовой кнопки #define BUTTON 0 // программный номер кнопки 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); test.button(BUTTON_PIN); Serial.begin(115200); mySerial.begin(10400); pinMode(TX, OUTPUT); fastinit(); } void loop() { test.read(); if (test.event_click_Dn (BUTTON)) {request = DTCREAD; PIDTime = 1000;} // если было короткое нажатие на тактовую кнопку запросим DTC if (test.event_press_long (BUTTON)){request = DTCERASE; PIDTime = 1000; } // если было длительное нажатие на тактовую кнопку удалим DTC // если инит ещё не выполнен, шлём периодически запрос инит if (!Init) { if (!timerenabledInit){ timerwaitInit=millis(); timerenabledInit=1; Serial.println ("Otpravil zapros Init"); for (byte i = 0; i<sizeof(messageInit); i++) {mySerial.write(messageInit[i]); delay (5);} delay (55); } else if (millis() - timerwaitInit > 500 ) timerenabledInit=0;} //иначе периодически шлём запросы else { if (millis() - prevPID > PIDTime && header == 0) { if (request == PID){ // Serial.println ("Otpravil zapros 21 01"); for (int i = 0; i < sizeof(messagePids); i++) {mySerial.write(messagePids[i]); delay (delaybyte); }} else if (request == DTCREAD) {Serial.println ("Otpravil zapros DTC read"); for (int i = 0; i < sizeof(messageRead_DTC); i++) {mySerial.write(messageRead_DTC[i]); delay (delaybyte); }} else if (request == DTCERASE) {Serial.println ("Otpravil zapros DTC clear"); for (int i = 0; i < sizeof(messageErase_DTC); i++) {mySerial.write(messageErase_DTC[i]); delay (delaybyte); }} prevPID = millis(); } } //разбор входящих сообщений 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 mySerial.begin(10400); } // baud rate of the OBD //получение данных от ЭБУ, разборка входящих сообщений void receive () { uint32_t curmillis = millis(); 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; timerPID_ON =1; prevRESETheader = millis(); 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; timerPID_ON = 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; timerPID_ON = 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(); for(byte i = 0; i<n; i++) crc+=buf[i]; // прибавляем к контрольной сумме старт байты // если контрольная сумма верна: if ( crc == buf[message_size+n]) {Serial.println("Received message is OK!" ); // Если КС совпала, тут чёнибудь нужное делаем if (buf[n]==0xC1 && buf[n+1]==0xEF && buf[n+2]==0x8F) {Init=1; timerenabledInit=0; Serial.println (" Initialization OK!!!!: "); } else if (buf[n]==0x58 && buf[n+1]==0x00) { Serial.println (" NO DTC "); request = PID; PIDTime = 100;} else if (buf[n]==0x58 && buf[n+1] >0x00) { Serial.println (" DTC is found!"); request = PID; PIDTime = 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; PIDTime = 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; timerPID_ON = 0; j=3; crc = 0; } if (!Delay && curmillis - timerdelay > waitbyte_time) Delay = 1; // таймер ожидания байт (для успевания появления данных в буфере UART) if (timerPID_ON && curmillis - prevRESETheader > 500) {timerPID_ON = 0; header = 0;} // таймер сброса заголовка если данные оборвались во время приёма заголока }Чем эта библиотека для работы с кнопками хороша? Вроде Дуня и так у меент ими пользоваться.
Кстати, включена внутренняя подтяжка?
Библиотека огонь. Подтяжка включена
Ну может быть, спорить не буду :) Часы делал без нее.
В общем, отлично все работает, читает и сбрасывает ошибки. Правда, как отличить присутсвует или просто в памяти? Иногда проскакивают какие-то длинные сообщения, но на работу не влияют, да и редко.
Received message is OK! Receive DATA MAP=1.02 Battery=12.10 Air=15 Temp=93 EngLoad=7 Throtle=0 RPM=0 Speed=0 Inj=12.14 IdleAir=39 O2sens=83 O2int=128 FuelRatio=12.60 STFT=0 Otpravil zapros DTC read 85 F1 11 58 1 1 70 22 73 Received message is OK! DTC is found! ERROR 1: P0170 B0 F1 11 61 1 1 1 70 22 0 0 0 FA 79 85 4A 62 B1 8A 12 34 0 0 0 0 0 1E 0 0 0 8E 27 0 0 13 80 12 71 0 FF 7E 0 0 0 84 8 27 34 0 0 0 1A Received message is OK! Receive DATA MAP=1.02 Battery=12.10 Air=15 Temp=93 EngLoad=7 Throtle=0 RPM=0 Speed=0 Inj=12.14 IdleAir=39 O2sens=83 O2int=128 FuelRatio=12.60 STFT=0 B0 F1 11 FA 85 B1 8A 12 8E 27 80 12 84 8 B0 F1 11 FA 85 4A B1 8A 8E 27 80 12 84 B0 F1 11 FA 79 85 4A B1 8A 8E 80 84 B0 F1 11 61 1 1 1 70 22 0 0 0 FA 79 84 4A 62 B1 8A 12 34 0 0 0 0 0 1E 0 0 0 8E 27 0 0 13 80 12 71 0 FF 7E 0 0 0 84 8 27 34 0 0 0 19 Received message is OK! Receive DATA MAP=1.02 Battery=12.10 Air=15 Temp=93 EngLoad=7 Throtle=0 RPM=0 Speed=0 Inj=12.14 IdleAir=39 O2sens=83 O2int=128 FuelRatio=12.60 STFT=0 ..... Otpravil zapros DTC clear 83 F1 11 54 FF 0 D8 Received message is OK! DTC CLEARED B0 F1 11 61 1 0 0 0 0 0 0 0 FA 79 7E 4D 62 B1 8A 12 34 0 0 0 0 0 1E 0 0 0 8D 27 0 0 1A 80 12 71 0 FF 7E 0 0 0 84 8 27 34 0 0 0 88 Received message is OK! Receive DATA MAP=1.02 Battery=12.10 Air=18 Temp=93 EngLoad=7 Throtle=0 RPM=0 Speed=0 Inj=12.05 IdleAir=39 O2sens=114 O2int=128 FuelRatio=12.60 STFT=0 ...... Received message is OK! Receive DATA MAP=1.02 Battery=12.10 Air=18 Temp=93 EngLoad=7 Throtle=0 RPM=0 Speed=0 Inj=12.05 IdleAir=39 O2sens=128 O2int=128 FuelRatio=12.60 STFT=0 B0 F1 11 61 1 0 0 0 0 0 0 0 FA 79 7C 4E 62 B1 8A 12 34 0 0 0 0 0 1E 0 0 0 8D 27 0 0 1D 80 0 0 8 0 8A FF FF FF B0 F1 11 61 1 0 0 0 CRC fail!!! FA 79 B1 8A 8D 27 80 12 84 8 8A Otpravil zapros DTC read 82 F1 11 58 0 DC Received message is OK! NO DTC B0 F1 11 FA B1 8A 8D 27 80 12 84 8 8A B0 F1 11 FA B1 8A 8D 27 80 12 84 8A B0 F1 11 FA 79 B1 8A 8D 27 80 84 8A FF B0 F1 11 61 1 0 0 0 0 0 0 0 FA 79 7C 4E 62 B1 8A 12 34 0 0 0 0 0 1E 0 0 0 8D 27 0 0 1D 80 12 71 0 FF 7E 0 0 0 84 8 27 34 0 0 0 8A Received message is OK!В конечном скече нужно будет делать проверку и fastinit(); повторять если, например, после пяти секунд отправки запроса Init ничего не меняется. Мало ли из-за чего связь прервется. Сейчас, например, если включить Дуню, а потом зажигание, то ничего не добьешья.
Осталось приборку доломать :)
НО! Пушной зверек подкрался незаметно. Попробовал выводить на экран. Скеч компилируется, но изображения нет. Как я понял, библиотека TV-out жестко завязана на прерывания, а у нас их вагон с тележкой. Блин, и ведь убил пару дней пока нашел рабочий вариант библиотеки под последний IDE.... Вот что теперь делать не представляю. Отказываться от аналогово вывода очень не хочется, т.к. потеряю камеру. Да и смысл тогда огород городить - есть стандартный MID. не такой функциональный, но все же.... Ставить вторую Дуню чисто для вывода на экран и слать ей готовые данные? Блин, сразу бы Нано заказал....