проснифьте обмен с помощью той программы, которую я вам давал, если ещё демка не закончилась. Интересно обмен данными будет посмотреть. и прочитайте сообщение #68 в вашей теме про ебер на кархелп.
Так как нагнетатель сейчас не работает, то проснифить в целом всю работу не получиться. Или вам интересно что там за обмен между прогами и котлом, то без вопросов могу заделать. Ну а потом и в полностью рабочем состоянии. Как думаете, два провода к-линии можно между собой соединить и потом данные читать?? Или на Эбер отдельную дуню повесить??
Линии к-лайн котла и основную автомобиля соединять нельзя! Если конечно это изначально не одна K-линия, что очень врядли. Если у вас будет ардуино мега, то нужно будет только два адаптера к-лайн (оба будут подсоединены в аппаратным Serial портам дуни). Если нано, то и ардуины две (каждый к-лайн адаптер к своей дуне).
Насчет сниффа, ну будет время снимите (пока демо версия программы сниффера не кончилась). Хочется посмотреть как идёт обмен и сравнить с тем постом из кархелп, если совпадёт - задача ещё упрощается. Опять всё сделали за нас)
По поводу нагнетателя меняйте щётки на моторчике, продувайте и смазывайте подшипники, бывает плюсом ещё и силовые ключи в блоке управления горят, теже симптомы будут.
Разобрался я с моторчиком нагнетателя. Разобрал пересмотрел всё, ничего существенного показывающего что он не рабочий-нет(счетки и подшипники в норме).
Единственное что могло быть причиной не нормальной работы - это чуть цеплявшееся пластмаса которая нагоняет воздух. приподнял её чуть выше, что бы вообще не цепляла и все. Эбер заработал ))) даю ссылки на диагностику двумя прогами. Забегая вперед скажу, что тест исполнителей эдитом не смог сделать, просит оригинальный шнур... общая получилась.
по обеим ссылкам никакого обмена толком нет, либо по какой то причине не просниффилось корректно. Там только повторяющиеся одни и те же байты. (справа то смотрите - там байты представлены в символах ASCII, сразу видно, что всё без конца повторяется).
Я когда выложил, то только тогда заметил, что там дублируется всё. Эх((((
Попробую ещё поколдовать над эдитом... вдруг, что получиться. В нете везде штудируют что для дигностики котлов нужен резистр подтяжки другой(560 Ом). Может мне в дуню залить тот самый первый скетч и посмотреть что выведет в терминал. Может все таки с подтяжкой надо поиграться. Есть какие мысли по этому поводу ??
Начал вот тестить дисплей и попробовал вывестиь стандартные примеры. Потом попытаюсь привезать к рабочему скетчу. Неудобство этого дисплея в том, что когда происходит затирание экрана(для того что бы вывести новую инфу) сопровождается морганием. старая инфа-дисплей моргнул-появилась новая. Буду еще искать примеры, так видел что выводят время и секунды не моргают.... надо менять только изменившееся данные.делать проверку.
#include <SPI.h> // Подключаем библиотеку для работы с устройством по интерфейсу SPI
#include <Adafruit_GFX.h> // Подключаем библиотеку для работы с текстом и графикой
#include <TFT_ILI9163C.h> // Подключаем библиотеку программных драйверов для работы с дисплеем 1.44 128x128 SPI
// В следующих 8-и строках опеределяем названия и соответствующие им RGB обозначения цветов, которые будем выводить на дисплей
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#define __CS 10 // Определяем пин к которому подключен разъем CS дисплея
#define __DC 9 // Определяем пин к которому подключен разъем A0 дисплея
#define __RES 8 // Определяем пин к которому подключен разъем RESET дисплея
TFT_ILI9163C display = TFT_ILI9163C(__CS, __DC, __RES); // Связываем объект display с библиотекой TFT_ILI9163C и сообщаем библиотеке определенные для работы с дисплеем пины
// Начало функции обработки кириллических символов
String utf8rus(String source) // Функция для конвертации русских символов из кодировки CP1251 в UTF8
{
int i,k;
String target;
unsigned char n;
char m[2] = { '0', '\0' };
k = source.length(); i = 0;
while (i < k) {
n = source[i]; i++;
if (n >= 0xBF){
switch (n) {
case 0xD0: {
n = source[i]; i++;
if (n == 0x81) { n = 0xA8; break; }
if (n >= 0x90 && n <= 0xBF) n = n + 0x2F;
break;
}
case 0xD1: {
n = source[i]; i++;
if (n == 0x91) { n = 0xB7; break; }
if (n >= 0x80 && n <= 0x8F) n = n + 0x6F;
break;
}
}
}
m[0] = n; target = target + String(m);
}
return target;
}
// Конец функции обработки кириллических симоволов
void setup() {
display.begin(); // Иницализируем дисплей
}
void loop() {
for (int i=0; i <= 255; i++){
display.fillScreen(); // Очищаем дисплей перед выводом
display.setTextSize(2); // Определяем размер шрифта
display.setCursor(2,5); // Устанавливаем курсор в левый верхний угол области вывода
//display.setTextColor(GREEN); // Определяем цвет вывода на дисплей
display.print(utf8rus("ПР0:"));
display.setCursor(50,5);
display.print(i);
display.setTextSize(2);
display.setCursor(2,25); // Устанавливаем курсор в левый верхний угол области вывода
display.print(utf8rus("ПР1:")); // Выводим строку на русском
display.setCursor(50,25);
display.print(i*3);
display.setCursor(2,45); // Устанавливаем курсор в левый верхний угол области вывода
display.print(utf8rus("ПР2:")); // Выводим строку на русском
display.setCursor(50,45);
display.print(i+74);
delay(1000);
}
/*display.setCursor(2,65); // Устанавливаем курсор в левый верхний угол области вывода
display.print(utf8rus("ПР3:")); // Выводим строку на русском
display.setCursor(50,65);
display.print(utf8rus("3333"));
display.setCursor(2,85); // Устанавливаем курсор в левый верхний угол области вывода
display.print(utf8rus("ПР4:")); // Выводим строку на русском
display.setCursor(50,85);
display.print(utf8rus("4444"));
display.setCursor(2,105); // Устанавливаем курсор в левый верхний угол области вывода
display.print(utf8rus("ПР5:")); // Выводим строку на русском
display.setCursor(50,105);
display.print(utf8rus("5555"));
delay(1000); */ // Задержка 3 секунды
}
Если прямоугольником затирать все равно будет мерцать, т.к. периодичность вывода на экран для БК нужна очень частая для плавности показаний. В библиотеках на tft экраны обычно это уже отработано специальной функцией. Типа при печати переменной задаешь также сколько символов она будет занимать и библиотека сама затирает старые символы.
P.s. читайте тему про опель, там все это проходили.
Я вот не пользуюся стандартными библиотеками, поэтому не очень представляю их возможности.
Но нормальная библиотека должне поддерживать управление "стилем" вывода символа, т.е. выводить его с "прозрачным" фоном либо заливать фон при выводе определенным цветом. Т.е в настройках указывается два цвета: которым собственно рисуется сам символ и которым заливаектся все знакоместо под ним.
Вообще-то это стандартная практика.
Боле того, в Windows, например, именно режим с "непрозрачным" фоном является режимом по умолчанию.
Ну, что на Ардуино режимио по умолчанию является "прозрачный" фон, я уже понял. А вот тема мерцания всплывает настолько часто, что возникает естественный вопрос: действительно ли стандартные библиотеки Ардуино настолько кривы, что не поддерживают наиболее востребованные режимы, или просто люди не умеют пользоваться библиотеками?
PS. На случай кривости библиотек можно, естественно, самому написать нужную функцию вывода символа. Но если это не по зубам, можно чистить не все поле вывода целиком, а посимвольно: почистил знакоместо - вывел очередной символ, почистил следующее знакоместо - вывел следующий.
Ардуино настолько кривы, что не поддерживают наиболее востребованные режимы, или просто люди не умеют пользоваться библиотеками?
скорее последнее. Вот, например, выдержка из одной библиотеки:
//printNumI – выводит на дисплей целое число или содержимое целочисленной переменной. В качестве параметров передаются выводимое значение и координаты верхнего левого угла области печати. Опциональные параметры позволяют управлять форматом вывода.
//Выводимое на печать значение может быть передано в виде целого числа:
myGLCD.printNumI(1250,0,0);
//Дополнительные опциональные параметры этой команды позволяют задать формат вывода чисел. Параметр length определяет минимальное количество знакомест (включая знак числа), занимаемых выводимым числом на дисплее. Если количество разрядов числа меньше, чем заданное значение length – недостающее количество знакомест дополняется слева нужным количеством символов. Параметр filler позволяет задать символ (по умолчанию — пробел), которым будет дополняться число. Комбинация этих символов позволяет, в частности, организовать вывод чисел, выровненных по правой границе или дополнять незначащими нулями значения при выводе времени или даты. Т. е. вместо привычной конструкции:
byte Day = 2;
byte Month = 9;
int Year = 2013;
if (Day<10){
myGLCD.print("0",0,0);
myGLCD.printNumI(Day,16,0);
}else{
myGLCD.printNumI(Day,0,0);}
myGLCD.print(".", 32,0);
if (Month<10){
myGLCD.print("0",48,0);
myGLCD.printNumI(Month,64,0);
}else{
myGLCD.printNumI(Month,48,0,2,'0');}
myGLCD.print(".", 80,0);
myGLCD.printNumI(Year,96,0);
//можно просто написать:
byte Day = 2;
byte Month = 9;
int Year = 2013;
myGLCD.printNumI(Day,0,0,2,'0');
myGLCD.print(".", 32,0);
myGLCD.printNumI(Month,48,0,2,'0');
myGLCD.print(".", 80,0);
myGLCD.printNumI(Year,96,0);
не правда ли так гораздо лучше?
нормальная библиотека должна поддерживать управление "стилем" вывода символа, т.е. выводить его с "прозрачным" фоном либо заливать фон при выводе определенным цветом. Т.е в настройках указывается два цвета: которым собственно рисуется сам символ и которым заливаектся все знакоместо под ним.
Вообще-то это стандартная практика......
.....можно чистить не все поле вывода целиком, а посимвольно: почистил знакоместо - вывел очередной символ, почистил следующее знакоместо - вывел следующий.
Я думаю речь была не про фон, а про "старые" нули. Если было например число 1000, а потом стало 100, один ноль уже протух, его бы надо удалить.
что-то я совсем запутался с подключением и инициализации с этой (UTFT.h) библиотекой. Везде всё по разному. Даже пример не могу проверить. У меня дисплей ST7735.
Пытался руководствоваться http://wiki.iarduino.ru/page/rabota-s-cvetnym-graficheskim-displууь.
и файлом UTFT.cpp из библиотеки
На библиотеке <TFT_ILI9163C.h> , подключал как на красной картинке справа
myGLCD.printNumI(1250,0,0); - действительно то что надо )))
Буду скоро проверять в боевых условиях))
Вот простой примерчик, который получился:
#include <UTFT.h> // подключаем библиотеку UTFT
extern uint8_t SmallFont[]; // подключаем маленький шрифт
extern uint8_t BigFont[]; // подключаем большой шрифт
extern uint8_t SevenSegNumFont[]; // подключаем цифровой шрифт
UTFT myGLCD(ST7735, 11, 13, 10, 8, 9);
void setup()
{
myGLCD.InitLCD(); // инициируем дисплей (в качестве параметра данной функции можно указать ориентацию дисплея: PORTRAIT или LANDSCAPE), по умолчанию LANDSCAPE - горизонтальная ориентация
}
void loop()
{
//Стираем все с экрана
myGLCD.clrScr(); // стираем всю информацию с дисплея
myGLCD.setFont(SmallFont); // устанавливаем маленький шрифт
myGLCD.setColor(VGA_WHITE); // устанавливаем цвет текста
myGLCD.print("iarduino.ru", CENTER, 25); // выводим текст на дисплей
myGLCD.setFont(SmallFont); // устанавливаем большой шрифт
myGLCD.setColor(VGA_BLUE); // устанавливаем цвет текста
myGLCD.print("BigFont", CENTER, 50); // выводим текст на дисплей
myGLCD.print("iarduino.ru", CENTER, 60); // выводим текст на дисплей
myGLCD.setFont(SmallFont); // устанавливаем цифровой шрифт
myGLCD.setColor(VGA_FUCHSIA); // устанавливаем цвет текста
myGLCD.print("1234567890", CENTER, 75); // выводим текст на дисплей
for (int i=100; i <= 3500; i++)
{
myGLCD.printNumI(i,75,90);
}
delay(20000);
}
Вот уже получилось вывести кое-какие данные на дисплей. Еще один шаг сперед) ))) "Снег" на экране от того, что закоментирована функция стирания всей информации с дисплея myGLCD.clrScr(); Потом надо будет запустить её один раз при включении, а то получаются опять "как бы мерцания". MaksVV, прошу вас помощи в оптимизации скетча и допиливанию других возможностей. Код еле-еле влез в UNO. То, что закоментировано с несколькими звездочками(***)-коментировал я сам (мож, что и лишнее)))).. остальные коментарии кода Ваши и Александра. Надо бы всё исключить, что связано с прошлым дисплеем, который от изначально проекта. И еще... лень было тащить ноут в машину, запитал дуни от зарядки телефона через прикуриватель, дуня повисала на 7-10 секунде. Перезапуск помогал, но не решил я рисковать больше 3-х раз... дабы не спалить её.
/*
Arduino Nano OBD reader (OBD protocol KW1281, Audi A4 B5 etc.)
wiring:
D2 --- OBD level shifter input (RX) (e.g. LM339)
D3 --- OBD level shifter output (TX) (e.g. LM339)
A5 --- Arduino 20x4 LCD display SCL
A4 --- Arduino 20x4 LCD display SDA
NOTE: For the level shifting, I used a 'AutoDia K409 Profi USB adapter', disassembled it,
and connected the Arduino to the level shifter chip (LM339) - the original FTDI chip TX line
was removed (so it does not influence the communication)
*/
#include <UTFT.h> // подключаем библиотеку UTFT
extern uint8_t SmallFont[]; // подключаем маленький шрифт
extern uint8_t BigFont[]; // подключаем большой шрифт
extern uint8_t SevenSegNumFont[]; // подключаем цифровой шрифт
UTFT myGLCD(ST7735, 11, 13, 10, 8, 9);
#include <Wire.h>
//******#include "LiquidCrystal_I2C.h"
#include "NewSoftwareSerial.h"
#define pinKLineRX 5
#define pinKLineTX 6
#define pinLED 2
#define pinBuzzer 3
#define pinButton 4
// <a href="https://www.blafusel.de/obd/obd2_kw1281.html" rel="nofollow">https://www.blafusel.de/obd/obd2_kw1281.html</a>
#define ADR_Engine 0x01
#define ADR_Gears 0x02
#define ADR_ABS_Brakes 0x03
#define ADR_Airbag 0x15
#define ADR_Dashboard 0x17
#define ADR_Immobilizer 0x25
#define ADR_Central_locking 0x35
//#define DEBUG 1
//*******LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x20 for a 16 chars and 2 line display
NewSoftwareSerial obd(pinKLineRX, pinKLineTX, false); // RX, TX, inverse logic
uint8_t currAddr = 0;
uint8_t blockCounter = 0;
uint8_t errorTimeout = 0;
uint8_t errorData = 0;
bool connected = false;
int sensorCounter = 0;
int pageUpdateCounter = 0;
int alarmCounter = 0;
uint8_t currPage = 2;
int8_t coolantTemp = 0;
int8_t oilTemp = 0;
int8_t intakeAirTemp = 0;
int8_t oilPressure = 0;
float engineLoad = 0;
int engineSpeed = 0;
float throttleValve = 0;
float supplyVoltage = 0;
uint8_t vehicleSpeed = 0;
uint8_t fuelConsumption = 0;
uint8_t fuelLevel = 0;
unsigned long odometer = 0;
// наши параметры
int TurboPressure = 0;
int TurboPressure_target = 0;
uint8_t Turbocharger_valve = 0;
uint8_t EGR_duty = 0;
int EGR_Consumption = 0;
int EGR_Consumption_target = 0;
String floatToString(float v){
String res;
char buf[16];
dtostrf(v,4, 2, buf);
res=String(buf);
return res;
}
void disconnect(){
connected = false;
currAddr = 0;
}
/***********void lcdPrint(int x, int y, String s, int width = 0){
lcd.setCursor(x,y);
while (s.length() < width) s += " ";
lcd.print(s);
}*/
void obdWrite(uint8_t data){
#ifdef DEBUG
Serial.print("uC:");
Serial.println(data, HEX);
#endif
obd.write(data);
}
uint8_t obdRead(){
unsigned long timeout = millis() + 1000;
while (!obd.available()){
if (millis() >= timeout) {
Serial.println(F("ERROR: obdRead timeout"));
disconnect();
errorTimeout++;
return 0;
}
}
uint8_t data = obd.read();
#ifdef DEBUG
Serial.print("ECU:");
Serial.println(data, HEX);
#endif
return data;
}
// 5Bd, 7O1
void send5baud(uint8_t data){
// // 1 start bit, 7 data bits, 1 parity, 1 stop bit
#define bitcount 10
byte bits[bitcount];
byte even=1;
byte bit;
for (int i=0; i < bitcount; i++){
bit=0;
if (i == 0) bit = 0;
else if (i == 8) bit = even; // computes parity bit
else if (i == 9) bit = 1;
else {
bit = (byte) ((data & (1 << (i-1))) != 0);
even = even ^ bit;
}
Serial.print(F("bit"));
Serial.print(i);
Serial.print(F("="));
Serial.print(bit);
if (i == 0) Serial.print(F(" startbit"));
else if (i == 8) Serial.print(F(" parity"));
else if (i == 9) Serial.print(F(" stopbit"));
Serial.println();
bits[i]=bit;
}
// now send bit stream
for (int i=0; i < bitcount+1; i++){
if (i != 0){
// wait 200 ms (=5 baud), adjusted by latency correction
delay(200);
if (i == bitcount) break;
}
if (bits[i] == 1){
// high
digitalWrite(pinKLineTX, HIGH);
} else {
// low
digitalWrite(pinKLineTX, LOW);
}
}
obd.flush();
}
bool KWP5BaudInit(uint8_t addr){
Serial.println(F("---KWP 5 baud init"));
//delay(3000);
send5baud(addr);
return true;
}
bool KWPSendBlock(char *s, int size){
Serial.print(F("---KWPSend sz="));
Serial.print(size);
Serial.print(F(" blockCounter="));
Serial.println(blockCounter);
// show data
Serial.print(F("OUT:"));
for (int i=0; i < size; i++){
uint8_t data = s[i];
Serial.print(data, HEX);
Serial.print(" ");
}
Serial.println();
for (int i=0; i < size; i++){
uint8_t data = s[i];
obdWrite(data);
/*uint8_t echo = obdRead();
if (data != echo){
Serial.println(F("ERROR: invalid echo"));
disconnect();
errorData++;
return false;
}*/
if (i < size-1){
uint8_t complement = obdRead();
if (complement != (data ^ 0xFF)){
Serial.println(F("ERROR: invalid complement"));
disconnect();
errorData++;
return false;
}
}
}
blockCounter++;
return true;
}
// count: if zero given, first received byte contains block length
// 4800, 9600 oder 10400 Baud, 8N1
bool KWPReceiveBlock(char s[], int maxsize, int &size){
bool ackeachbyte = false;
uint8_t data = 0;
int recvcount = 0;
if (size == 0) ackeachbyte = true;
Serial.print(F("---KWPReceive sz="));
Serial.print(size);
Serial.print(F(" blockCounter="));
Serial.println(blockCounter);
if (size > maxsize) {
Serial.println("ERROR: invalid maxsize");
return false;
}
unsigned long timeout = millis() + 1000;
while ((recvcount == 0) || (recvcount != size)) {
while (obd.available()){
data = obdRead();
s[recvcount] = data;
recvcount++;
if ((size == 0) && (recvcount == 1)) {
size = data + 1;
if (size > maxsize) {
Serial.println("ERROR: invalid maxsize");
return false;
}
}
if ((ackeachbyte) && (recvcount == 2)) {
if (data != blockCounter){
Serial.println(F("ERROR: invalid blockCounter"));
disconnect();
errorData++;
return false;
}
}
if ( ((!ackeachbyte) && (recvcount == size)) || ((ackeachbyte) && (recvcount < size)) ){
obdWrite(data ^ 0xFF); // send complement ack
/*uint8_t echo = obdRead();
if (echo != (data ^ 0xFF)){
Serial.print(F("ERROR: invalid echo "));
Serial.println(echo, HEX);
disconnect();
errorData++;
return false;
}*/
}
timeout = millis() + 1000;
}
if (millis() >= timeout){
Serial.println(F("ERROR: timeout"));
disconnect();
errorTimeout++;
return false;
}
}
// show data
Serial.print(F("IN: sz="));
Serial.print(size);
Serial.print(F(" data="));
for (int i=0; i < size; i++){
uint8_t data = s[i];
Serial.print(data, HEX);
Serial.print(F(" "));
}
Serial.println();
blockCounter++;
return true;
}
bool KWPSendAckBlock(){
Serial.print(F("---KWPSendAckBlock blockCounter="));
Serial.println(blockCounter);
char buf[32];
sprintf(buf, "\x03%c\x09\x03", blockCounter);
return (KWPSendBlock(buf, 4));
}
bool connect(uint8_t addr, int baudrate){
Serial.print(F("------connect addr="));
Serial.print(addr);
Serial.print(F(" baud="));
Serial.println(baudrate);
tone(pinBuzzer, 1200);
delay(100);
noTone(pinBuzzer);
//lcd.clear();
/******lcdPrint(0,0, F("KW1281 wakeup"), 20);
lcdPrint(0,1, "", 20);
lcdPrint(0,2, "", 20); *///
blockCounter = 0;
currAddr = 0;
obd.begin(baudrate);
KWP5BaudInit(addr);
// answer: 0x55, 0x01, 0x8A
char s[3];
//****lcdPrint(0,0, F("KW1281 recv"), 20);
int size = 3;
if (!KWPReceiveBlock(s, 3, size)) return false;
if ( (((uint8_t)s[0]) != 0x55)
|| (((uint8_t)s[1]) != 0x01)
|| (((uint8_t)s[2]) != 0x8A) ){
Serial.println(F("ERROR: invalid magic"));
disconnect();
errorData++;
return false;
}
currAddr = addr;
connected = true;
if (!readConnectBlocks()) return false;
return true;
}
bool readConnectBlocks(){
// read connect blocks
Serial.println(F("------readconnectblocks"));
//****lcdPrint(0,0, F("KW1281 label"), 20);
String info;
while (true){
int size = 0;
char s[64];
if (!(KWPReceiveBlock(s, 64, size))) return false;
if (size == 0) return false;
if (s[2] == '\x09') break;
if (s[2] != '\xF6') {
Serial.println(F("ERROR: unexpected answer"));
disconnect();
errorData++;
return false;
}
String text = String(s);
info += text.substring(3, size-2);
if (!KWPSendAckBlock()) return false;
}
Serial.print("label=");
Serial.println(info);
//lcd.setCursor(0, 1);
//lcd.print(info);
return true;
}
bool readSensors(int group){
Serial.print(F("------readSensors "));
Serial.println(group);
//****lcdPrint(0,0, F("KW1281 sensor"), 20);
char s[64];
sprintf(s, "\x04%c\x29%c\x03", blockCounter, group);
if (!KWPSendBlock(s, 5)) return false;
int size = 0;
KWPReceiveBlock(s, 64, size);
if (s[2] != '\xe7') {
Serial.println(F("ERROR: invalid answer"));
disconnect();
errorData++;
return false;
}
int count = (size-4) / 3;
Serial.print(F("count="));
Serial.println(count);
for (int idx=0; idx < count; idx++){
byte k=s[3 + idx*3];
byte a=s[3 + idx*3+1];
byte b=s[3 + idx*3+2];
String n;
float v = 0;
Serial.print(F("type="));
Serial.print(k);
Serial.print(F(" a="));
Serial.print(a);
Serial.print(F(" b="));
Serial.print(b);
Serial.print(F(" text="));
String t = "";
String units = "";
char buf[32];
switch (k){
case 0x01: v=0.2*a*b; units=F("rpm"); break;
case 0x02: v=a*0.002*b; units=F("%%"); break;
case 0x03: v=0.002*a*b; units=F("Deg"); break;
case 0x04: v=abs(b-127)*0.01*a; units=F("ATDC"); break;
case 0x05: v=a*(b-100)*0.1; units=F("°C");break;
case 0x06: v=0.001*a*b; units=F("V");break;
case 0x07: v=0.01*a*b; units=F("km/h");break;
case 0x08: v=0.1*a*b; units=F(" ");break;
case 0x09: v=(b-127)*0.02*a; units=F("Deg");break;
case 0x0A: if (b == 0) t=F("COLD"); else t=F("WARM");break;
case 0x0B: v=0.0001*a*(b-128)+1; units = F(" ");break;
case 0x0C: v=0.001*a*b; units =F("Ohm");break;
case 0x0D: v=(b-127)*0.001*a; units =F("mm");break;
case 0x0E: v=0.005*a*b; units=F("bar");break;
case 0x0F: v=0.01*a*b; units=F("ms");break;
case 0x12: v=0.04*a*b; units=F("mbar");break;
case 0x13: v=a*b*0.01; units=F("l");break;
case 0x14: v=a*(b-128)/128; units=F("%%");break;
case 0x15: v=0.001*a*b; units=F("V");break;
case 0x16: v=0.001*a*b; units=F("ms");break;
case 0x17: v=(b*a)/256; units=F("%%");break;
case 0x18: v=0.001*a*b; units=F("A");break;
case 0x19: v=(b*1.421)+(a/182); units=F("g/s");break;
case 0x1A: v=float(b-a); units=F("C");break;
case 0x1B: v=abs(b-128)*0.01*a; units=F("°");break;
case 0x1C: v=float(b-a); units=F(" ");break;
case 0x1E: v=b/12*a; units=F("Deg k/w");break;
case 0x1F: v=b/2560*a; units=F("°C");break;
case 0x21: v=100*b/a; units=F("%%");break;
case 0x22: v=(b-128)*0.01*a; units=F("kW");break;
case 0x23: v=0.01*a*b; units=F("l/h");break;
case 0x24: v=((unsigned long)a)*2560+((unsigned long)b)*10; units=F("km");break;
case 0x25: v=b; break; // oil pressure ?!
// ADP: FIXME!
/*case 37: switch(b){
case 0: sprintf(buf, F("ADP OK (%d,%d)"), a,b); t=String(buf); break;
case 1: sprintf(buf, F("ADP RUN (%d,%d)"), a,b); t=String(buf); break;
case 0x10: sprintf(buf, F("ADP ERR (%d,%d)"), a,b); t=String(buf); break;
default: sprintf(buf, F("ADP (%d,%d)"), a,b); t=String(buf); break;
}*/
case 0x26: v=(b-128)*0.001*a; units=F("Deg k/w"); break;
case 0x27: v=b/256*a; units=F("mg/h"); break;
case 0x28: v=b*0.1+(25.5*a)-400; units=F("A"); break;
case 0x29: v=b+a*255; units=F("Ah"); break;
case 0x2A: v=b*0.1+(25.5*a)-400; units=F("Kw"); break;
case 0x2B: v=b*0.1+(25.5*a); units=F("V"); break;
case 0x2C: sprintf(buf, "%2d:%2d", a,b); t=String(buf); break;
case 0x2D: v=0.1*a*b/100; units=F(" "); break;
case 0x2E: v=(a*b-3200)*0.0027; units=F("Deg k/w"); break;
case 0x2F: v=(b-128)*a; units=F("ms"); break;
case 0x30: v=b+a*255; units=F(" "); break;
case 0x31: v=(b/4)*a*0.1; units=F("mg/h"); break;
case 0x32: v=(b-128)/(0.01*a); units=F("mbar"); break;
case 0x33: v=((b-128)/255)*a; units=F("mg/h"); break;
case 0x34: v=b*0.02*a-a; units=F("Nm"); break;
case 0x35: v=(b-128)*1.4222+0.006*a; units=F("g/s"); break;
case 0x36: v=a*256+b; units=F("count"); break;
case 0x37: v=a*b/200; units=F("s"); break;
case 0x38: v=a*256+b; units=F("WSC"); break;
case 0x39: v=a*256+b+65536; units=F("WSC"); break;
case 0x3B: v=(a*256+b)/32768; units=F("g/s"); break;
case 0x3C: v=(a*256+b)*0.01; units=F("sec"); break;
case 0x3E: v=0.256*a*b; units=F("S"); break;
case 0x40: v=float(a+b); units=F("Ohm"); break;
case 0x41: v=0.01*a*(b-127); units=F("mm"); break;
case 0x42: v=(a*b)/511.12; units=F("V"); break;
case 0x43: v=(640*a)+b*2.5; units=F("Deg"); break;
case 0x44: v=(256*a+b)/7.365; units=F("deg/s");break;
case 0x45: v=(256*a +b)*0.3254; units=F("Bar");break;
case 0x46: v=(256*a +b)*0.192; units=F("m/s^2");break;
default: sprintf(buf, "%2x, %2x ", a, b); break;
}
switch (currAddr){
case ADR_Engine:
switch(group){
case 3:
switch (idx){
case 0: engineSpeed = v; break;
case 1: EGR_Consumption_target =v; break;
case 2: EGR_Consumption=v; break;
case 3: EGR_duty=v; break;
}
break;
case 11:
switch (idx){
case 0: engineSpeed = v; break;
case 1: TurboPressure_target =v; break;
case 2: TurboPressure =v; break;
case 3: Turbocharger_valve=v; break;
}
break;
}
break;
case ADR_Dashboard:
switch (group){
case 1:
switch (idx){
case 0: vehicleSpeed = v; break;
case 1: engineSpeed = v; break;
case 2: oilPressure = v; break;
}
break;
case 2:
switch (idx){
case 0: odometer = v; break;
case 1: fuelLevel = v; break;
}
break;
case 50:
switch (idx){
case 1: engineSpeed = v; break;
case 2: oilTemp = v; break;
case 3: coolantTemp = v; break;
}
break;
}
break;
}
if (units.length() != 0){
dtostrf(v,4, 2, buf);
t=String(buf) + " " + units;
}
Serial.println(t);
//lcd.setCursor(0, idx);
//while (t.length() < 20) t += " ";
//lcd.print(t);
}
sensorCounter++;
return true;
}
void alarm(){
if (alarmCounter > 10) return;
tone(pinBuzzer, 1200);
delay(100);
noTone(pinBuzzer);
alarmCounter++;
}
/*********void updateDisplay(){
if (!connected){
if ( (errorTimeout != 0) || (errorData != 0) ){
lcdPrint(0,3, F("err to="));
lcdPrint(7,3, String(errorTimeout), 3);
lcdPrint(10,3, F(" da="));
lcdPrint(14,3, String(errorData), 6);
}
} else {
switch (currPage){
case 1:
if (coolantTemp > 99){
lcdPrint(0,1, F("COOL"));
alarm();
} else lcdPrint(0,1, F("cool"));
lcdPrint(6,1,String(coolantTemp),3);
if ( (oilTemp > 99) || ((oilPressure != 30) && (oilPressure != 31)) ){
lcdPrint(10,1,F("OIL "));
alarm();
} else lcdPrint(10,1,F("oil "));
lcdPrint(14,1,String(oilPressure),3);
lcdPrint(0,2, F("rpm "));
lcdPrint(4,2, String(engineSpeed),4);
lcdPrint(10,2, F("km/h "));
lcdPrint(15,2, String(vehicleSpeed, 3));
lcdPrint(0,3, F("fuel "));
lcdPrint(5,3, String(fuelLevel),3);
lcdPrint(10,3, F("odo "));
lcdPrint(14,3, String(odometer),6);
break;
case 2:
if (coolantTemp > 99){
lcdPrint(0,1, F("COOL"));
alarm();
} else lcdPrint(0,1, F("cool"));
lcdPrint(6,1,String(coolantTemp),3);
lcdPrint(10,1, F("air "));
lcdPrint(14,1, String(intakeAirTemp), 3);
lcdPrint(0,2, F("rpm "));
lcdPrint(4,2, String(engineSpeed),4);
lcdPrint(10,2, F("km/h "));
lcdPrint(15,2, String(vehicleSpeed, 3));
lcdPrint(0,3, F("fuel "));
lcdPrint(5,3, String(fuelConsumption),3);
lcdPrint(10,3, F("volt "));
lcdPrint(15,3, String(supplyVoltage),5);
break;
}
}
pageUpdateCounter++;
}*/
void setup(){
//***** lcd.init();
//**** lcd.backlight();
//**** lcd.init();
myGLCD.InitLCD(PORTRAIT); // инициируем дисплей (в качестве параметра данной функции можно указать ориентацию дисплея: PORTRAIT или LANDSCAPE), по умолчанию LANDSCAPE - горизонтальная ориентация
pinMode(pinKLineTX, OUTPUT);
digitalWrite(pinKLineTX, HIGH);
pinMode(pinButton, INPUT);
pinMode(pinButton, INPUT_PULLUP);
pinMode(pinBuzzer, OUTPUT);
/*tone(pinBuzzer, 1200);
delay(100);
noTone(pinBuzzer);*/
Serial.begin(19200);
Serial.println(F("SETUP"));
Serial.println(F("START"));
}
void loop(){
if (digitalRead(pinButton) == LOW){
currPage++;
if (currPage > 2) currPage = 1;
//** lcd.clear();
//** lcd.setCursor(0,0);
//**lcd.print(F("page "));
//**lcd.print(currPage);
errorTimeout = 0;
errorData = 0;
while (digitalRead(pinButton) == LOW);
}
switch (currPage){
case 1:
if (currAddr != ADR_Dashboard){
connect(ADR_Dashboard, 9600);
} else {
readSensors(1);
readSensors(2);
readSensors(50);
}
break;
case 2:
if (currAddr != ADR_Engine) {
connect(ADR_Engine, 9600);
} else {
readSensors(3);
readSensors(11);
}
break;
}
//*** updateDisplay();
// myGLCD.clrScr(); // стираем всю информацию с дисплея
myGLCD.setFont(BigFont); // устанавливаем большой шрифт
myGLCD.setColor(VGA_WHITE); // устанавливаем цвет текста
myGLCD.print("PR1:",LEFT, 3);
myGLCD.print("PR2:",LEFT, 25); // выводим текст на дисплей
myGLCD.print("PR3:", LEFT, 50); // выводим текст на дисплей
myGLCD.print("PR4:", LEFT, 75); // выводим текст на дисплей
myGLCD.print("PR5:", LEFT, 100); // выводим текст на дисплей
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(engineSpeed,60,3);
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(TurboPressure,60,25);
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(Turbocharger_valve,60,50);
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(EGR_duty,60,75);
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(EGR_Consumption,60,100);
/*Serial.println();
Serial.print ("engineSpeed: "); Serial.println(engineSpeed);
Serial.print ("EGR valve : "); Serial.println(EGR_duty);
Serial.print ("EGR rashod "); Serial.println(EGR_Consumption);
Serial.print ("EGR rashod zadan: "); Serial.println(EGR_Consumption_target);
Serial.print ("Pressure Turbo: "); Serial.println(TurboPressure);
Serial.print ("Pressure Turbo zadan: "); Serial.println(TurboPressure_target);
Serial.print ("Turbo Actuator: "); Serial.println(Turbocharger_valve);
Serial.println();*/
}
Начал вот разбираться с параметрами. Что-то я совсем запутался.....
пробовал менять переменную (во втором скетче)uint8_t currPage = 1; на значение 2. выводит одни параметры, когда верну 1 -другие. Добавил пару строчек в
switch (currPage){
case 1:
if (currAddr != ADR_Dashboard){
connect(ADR_Dashboard, 9600);
} else {
readSensors(1);
readSensors(2);
readSensors(50);
}
break;
case 2:
if (currAddr != ADR_Engine) {
connect(ADR_Engine, 9600);
} else {
readSensors(3);
readSensors(11);
readSensors(15);
readSensors(16);
}
break;
}
В итоге имею два скетча, вроде как одинаковых, но с разными результатами.
#include <UTFT.h> // подключаем библиотеку UTFT
extern uint8_t SmallFont[]; // подключаем маленький шрифт
extern uint8_t BigFont[]; // подключаем большой шрифт
extern uint8_t SevenSegNumFont[]; // подключаем цифровой шрифт
UTFT myGLCD(ST7735, 11, 13, 10, 8, 9);
#include <Wire.h>
//******#include "LiquidCrystal_I2C.h"
#include "NewSoftwareSerial.h"
#define pinKLineRX 5
#define pinKLineTX 6
#define pinLED 2
#define pinBuzzer 3
#define pinButton 4
#define ADR_Engine 0x01 //Двигатель
#define ADR_Gears 0x02 //КПП ---
#define ADR_ABS_Brakes 0x03
#define ADR_Airbag 0x15
#define ADR_Dashboard 0x17 //Панель приборов
#define ADR_Immobilizer 0x25
#define ADR_Central_locking 0x35
//#define DEBUG 1
//*******LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x20 for a 16 chars and 2 line display
NewSoftwareSerial obd(pinKLineRX, pinKLineTX, false); // RX, TX, inverse logic
uint8_t currAddr = 0;
uint8_t blockCounter = 0;
uint8_t errorTimeout = 0;
uint8_t errorData = 0;
bool connected = false;
int sensorCounter = 0;
int pageUpdateCounter = 0;
int alarmCounter = 0;
uint8_t currPage = 2;
int8_t coolantTemp = 0; //Температурв ОЖ 1-1-3 /////0-1-2-3
int8_t oilTemp = 0; //Температура Масла 17-50-2
int8_t intakeAirTemp = 0; //Температура вохдуха
int8_t oilPressure = 0; //Давление масла
float engineLoad = 0; //
int engineSpeed = 0; //Обороты двигателя 1-1-0
float throttleValve = 0; //Дрорссельная заслонка(клапан)
float supplyVoltage = 0; //Напряжение питания (аккума) 1-16-3
uint8_t vehicleSpeed = 0; //Скорость автомобиля
uint8_t fuelConsumption = 0;//Потребление топлива 1-15-2 л/ч
uint8_t fuelLevel = 0; //Уровень топлива 17-3-0
unsigned long odometer = 0; // Одометр 17-2-0
// наши параметры
int TurboPressure = 0;
int TurboPressure_target = 0;
uint8_t Turbocharger_valve = 0;
uint8_t EGR_duty = 0;
int EGR_Consumption = 0;
int EGR_Consumption_target = 0;
String floatToString(float v){
String res;
char buf[16];
dtostrf(v,4, 2, buf);
res=String(buf);
return res;
}
void disconnect(){
connected = false;
currAddr = 0;
}
/***********void lcdPrint(int x, int y, String s, int width = 0){
lcd.setCursor(x,y);
while (s.length() < width) s += " ";
lcd.print(s);
}*/
void obdWrite(uint8_t data){
#ifdef DEBUG
Serial.print("uC:");
Serial.println(data, HEX);
#endif
obd.write(data);
}
uint8_t obdRead(){
unsigned long timeout = millis() + 1000;
while (!obd.available()){
if (millis() >= timeout) {
Serial.println(F("ERROR: obdRead timeout"));
disconnect();
errorTimeout++;
return 0;
}
}
uint8_t data = obd.read();
#ifdef DEBUG
Serial.print("ECU:");
Serial.println(data, HEX);
#endif
return data;
}
// 5Bd, 7O1
void send5baud(uint8_t data){
// // 1 start bit, 7 data bits, 1 parity, 1 stop bit
#define bitcount 10
byte bits[bitcount];
byte even=1;
byte bit;
for (int i=0; i < bitcount; i++){
bit=0;
if (i == 0) bit = 0;
else if (i == 8) bit = even; // computes parity bit
else if (i == 9) bit = 1;
else {
bit = (byte) ((data & (1 << (i-1))) != 0);
even = even ^ bit;
}
Serial.print(F("bit"));
Serial.print(i);
Serial.print(F("="));
Serial.print(bit);
if (i == 0) Serial.print(F(" startbit"));
else if (i == 8) Serial.print(F(" parity"));
else if (i == 9) Serial.print(F(" stopbit"));
Serial.println();
bits[i]=bit;
}
// now send bit stream
for (int i=0; i < bitcount+1; i++){
if (i != 0){
// wait 200 ms (=5 baud), adjusted by latency correction
delay(200);
if (i == bitcount) break;
}
if (bits[i] == 1){
// high
digitalWrite(pinKLineTX, HIGH);
} else {
// low
digitalWrite(pinKLineTX, LOW);
}
}
obd.flush();
}
bool KWP5BaudInit(uint8_t addr){
Serial.println(F("---KWP 5 baud init"));
//delay(3000);
send5baud(addr);
return true;
}
bool KWPSendBlock(char *s, int size){
Serial.print(F("---KWPSend sz="));
Serial.print(size);
Serial.print(F(" blockCounter="));
Serial.println(blockCounter);
// show data
Serial.print(F("OUT:"));
for (int i=0; i < size; i++){
uint8_t data = s[i];
Serial.print(data, HEX);
Serial.print(" ");
}
Serial.println();
for (int i=0; i < size; i++){
uint8_t data = s[i];
obdWrite(data);
if (i < size-1){
uint8_t complement = obdRead();
if (complement != (data ^ 0xFF)){
Serial.println(F("ERROR: invalid complement"));
disconnect();
errorData++;
return false;
}
}
}
blockCounter++;
return true;
}
// count: if zero given, first received byte contains block length
// 4800, 9600 oder 10400 Baud, 8N1
bool KWPReceiveBlock(char s[], int maxsize, int &size){
bool ackeachbyte = false;
uint8_t data = 0;
int recvcount = 0;
if (size == 0) ackeachbyte = true;
Serial.print(F("---KWPReceive sz="));
Serial.print(size);
Serial.print(F(" blockCounter="));
Serial.println(blockCounter);
if (size > maxsize) {
Serial.println("ERROR: invalid maxsize");
return false;
}
unsigned long timeout = millis() + 1000;
while ((recvcount == 0) || (recvcount != size)) {
while (obd.available()){
data = obdRead();
s[recvcount] = data;
recvcount++;
if ((size == 0) && (recvcount == 1)) {
size = data + 1;
if (size > maxsize) {
Serial.println("ERROR: invalid maxsize");
return false;
}
}
if ((ackeachbyte) && (recvcount == 2)) {
if (data != blockCounter){
Serial.println(F("ERROR: invalid blockCounter"));
disconnect();
errorData++;
return false;
}
}
if ( ((!ackeachbyte) && (recvcount == size)) || ((ackeachbyte) && (recvcount < size)) ){
obdWrite(data ^ 0xFF); // send complement ack
/*uint8_t echo = obdRead();
if (echo != (data ^ 0xFF)){
Serial.print(F("ERROR: invalid echo "));
Serial.println(echo, HEX);
disconnect();
errorData++;
return false;
}*/
}
timeout = millis() + 1000;
}
if (millis() >= timeout){
Serial.println(F("ERROR: timeout"));
disconnect();
errorTimeout++;
return false;
}
}
// show data
Serial.print(F("IN: sz="));
Serial.print(size);
Serial.print(F(" data="));
for (int i=0; i < size; i++){
uint8_t data = s[i];
Serial.print(data, HEX);
Serial.print(F(" "));
}
Serial.println();
blockCounter++;
return true;
}
bool KWPSendAckBlock(){
Serial.print(F("---KWPSendAckBlock blockCounter="));
Serial.println(blockCounter);
char buf[32];
sprintf(buf, "\x03%c\x09\x03", blockCounter);
return (KWPSendBlock(buf, 4));
}
bool connect(uint8_t addr, int baudrate){
Serial.print(F("------connect addr="));
Serial.print(addr);
Serial.print(F(" baud="));
Serial.println(baudrate);
tone(pinBuzzer, 1200);
delay(100);
noTone(pinBuzzer);
//lcd.clear();
/******lcdPrint(0,0, F("KW1281 wakeup"), 20);
lcdPrint(0,1, "", 20);
lcdPrint(0,2, "", 20); *///
blockCounter = 0;
currAddr = 0;
obd.begin(baudrate);
KWP5BaudInit(addr);
// answer: 0x55, 0x01, 0x8A
char s[3];
//****lcdPrint(0,0, F("KW1281 recv"), 20);
int size = 3;
if (!KWPReceiveBlock(s, 3, size)) return false;
if ( (((uint8_t)s[0]) != 0x55)
|| (((uint8_t)s[1]) != 0x01)
|| (((uint8_t)s[2]) != 0x8A) ){
Serial.println(F("ERROR: invalid magic"));
disconnect();
errorData++;
return false;
}
currAddr = addr;
connected = true;
if (!readConnectBlocks()) return false;
return true;
}
bool readConnectBlocks(){
// read connect blocks
Serial.println(F("------readconnectblocks"));
//****lcdPrint(0,0, F("KW1281 label"), 20);
String info;
while (true){
int size = 0;
char s[64];
if (!(KWPReceiveBlock(s, 64, size))) return false;
if (size == 0) return false;
if (s[2] == '\x09') break;
if (s[2] != '\xF6') {
Serial.println(F("ERROR: unexpected answer"));
disconnect();
errorData++;
return false;
}
String text = String(s);
info += text.substring(3, size-2);
if (!KWPSendAckBlock()) return false;
}
Serial.print("label=");
Serial.println(info);
//lcd.setCursor(0, 1);
//lcd.print(info);
return true;
}
bool readSensors(int group){
Serial.print(F("------readSensors "));
Serial.println(group);
//****lcdPrint(0,0, F("KW1281 sensor"), 20);
char s[64];
sprintf(s, "\x04%c\x29%c\x03", blockCounter, group);
if (!KWPSendBlock(s, 5)) return false;
int size = 0;
KWPReceiveBlock(s, 64, size);
if (s[2] != '\xe7') {
Serial.println(F("ERROR: invalid answer"));
disconnect();
errorData++;
return false;
}
int count = (size-4) / 3;
Serial.print(F("count="));
Serial.println(count);
for (int idx=0; idx < count; idx++){
byte k=s[3 + idx*3];
byte a=s[3 + idx*3+1];
byte b=s[3 + idx*3+2];
String n;
float v = 0;
Serial.print(F("type="));
Serial.print(k);
Serial.print(F(" a="));
Serial.print(a);
Serial.print(F(" b="));
Serial.print(b);
Serial.print(F(" text="));
String t = "";
String units = "";
char buf[32];
switch (k){
case 0x01: v=0.2*a*b; units=F("rpm"); break;
case 0x02: v=a*0.002*b; units=F("%%"); break;
case 0x03: v=0.002*a*b; units=F("Deg"); break;
case 0x04: v=abs(b-127)*0.01*a; units=F("ATDC"); break;
case 0x05: v=a*(b-100)*0.1; units=F("°C");break;
case 0x06: v=0.001*a*b; units=F("V");break;
case 0x07: v=0.01*a*b; units=F("km/h");break;
case 0x08: v=0.1*a*b; units=F(" ");break;
case 0x09: v=(b-127)*0.02*a; units=F("Deg");break;
case 0x0A: if (b == 0) t=F("COLD"); else t=F("WARM");break;
case 0x0B: v=0.0001*a*(b-128)+1; units = F(" ");break;
case 0x0C: v=0.001*a*b; units =F("Ohm");break;
case 0x0D: v=(b-127)*0.001*a; units =F("mm");break;
case 0x0E: v=0.005*a*b; units=F("bar");break;
case 0x0F: v=0.01*a*b; units=F("ms");break;
case 0x12: v=0.04*a*b; units=F("mbar");break;
case 0x13: v=a*b*0.01; units=F("l");break;
case 0x14: v=a*(b-128)/128; units=F("%%");break;
case 0x15: v=0.001*a*b; units=F("V");break;
case 0x16: v=0.001*a*b; units=F("ms");break;
case 0x17: v=(b*a)/256; units=F("%%");break;
case 0x18: v=0.001*a*b; units=F("A");break;
case 0x19: v=(b*1.421)+(a/182); units=F("g/s");break;
case 0x1A: v=float(b-a); units=F("C");break;
case 0x1B: v=abs(b-128)*0.01*a; units=F("°");break;
case 0x1C: v=float(b-a); units=F(" ");break;
case 0x1E: v=b/12*a; units=F("Deg k/w");break;
case 0x1F: v=b/2560*a; units=F("°C");break;
case 0x21: v=100*b/a; units=F("%%");break;
case 0x22: v=(b-128)*0.01*a; units=F("kW");break;
case 0x23: v=0.01*a*b; units=F("l/h");break;
case 0x24: v=((unsigned long)a)*2560+((unsigned long)b)*10; units=F("km");break;
case 0x25: v=b; break; // oil pressure ?!
// ADP: FIXME!
/*case 37: switch(b){
case 0: sprintf(buf, F("ADP OK (%d,%d)"), a,b); t=String(buf); break;
case 1: sprintf(buf, F("ADP RUN (%d,%d)"), a,b); t=String(buf); break;
case 0x10: sprintf(buf, F("ADP ERR (%d,%d)"), a,b); t=String(buf); break;
default: sprintf(buf, F("ADP (%d,%d)"), a,b); t=String(buf); break;
}*/
case 0x26: v=(b-128)*0.001*a; units=F("Deg k/w"); break;
case 0x27: v=b/256*a; units=F("mg/h"); break;
case 0x28: v=b*0.1+(25.5*a)-400; units=F("A"); break;
case 0x29: v=b+a*255; units=F("Ah"); break;
case 0x2A: v=b*0.1+(25.5*a)-400; units=F("Kw"); break;
case 0x2B: v=b*0.1+(25.5*a); units=F("V"); break;
case 0x2C: sprintf(buf, "%2d:%2d", a,b); t=String(buf); break;
case 0x2D: v=0.1*a*b/100; units=F(" "); break;
case 0x2E: v=(a*b-3200)*0.0027; units=F("Deg k/w"); break;
case 0x2F: v=(b-128)*a; units=F("ms"); break;
case 0x30: v=b+a*255; units=F(" "); break;
case 0x31: v=(b/4)*a*0.1; units=F("mg/h"); break;
case 0x32: v=(b-128)/(0.01*a); units=F("mbar"); break;
case 0x33: v=((b-128)/255)*a; units=F("mg/h"); break;
case 0x34: v=b*0.02*a-a; units=F("Nm"); break;
case 0x35: v=(b-128)*1.4222+0.006*a; units=F("g/s"); break;
case 0x36: v=a*256+b; units=F("count"); break;
case 0x37: v=a*b/200; units=F("s"); break;
case 0x38: v=a*256+b; units=F("WSC"); break;
case 0x39: v=a*256+b+65536; units=F("WSC"); break;
case 0x3B: v=(a*256+b)/32768; units=F("g/s"); break;
case 0x3C: v=(a*256+b)*0.01; units=F("sec"); break;
case 0x3E: v=0.256*a*b; units=F("S"); break;
case 0x40: v=float(a+b); units=F("Ohm"); break;
case 0x41: v=0.01*a*(b-127); units=F("mm"); break;
case 0x42: v=(a*b)/511.12; units=F("V"); break;
case 0x43: v=(640*a)+b*2.5; units=F("Deg"); break;
case 0x44: v=(256*a+b)/7.365; units=F("deg/s");break;
case 0x45: v=(256*a +b)*0.3254; units=F("Bar");break;
case 0x46: v=(256*a +b)*0.192; units=F("m/s^2");break;
default: sprintf(buf, "%2x, %2x ", a, b); break;
}
switch (currAddr){
case ADR_Engine:
switch(group){
case 1:
switch (idx){
case 0: engineSpeed = v; break;
case 2: coolantTemp; break;
}
break; ////********------------------
case 3:
switch (idx){
//case 0: engineSpeed = v; break;
case 1: EGR_Consumption_target =v; break;
case 2: EGR_Consumption=v; break;
case 3: EGR_duty=v; break;
}
break;
case 11:
switch (idx){
//case 0: engineSpeed = v; break;
case 1: TurboPressure_target =v; break;
case 2: TurboPressure =v; break;
case 3: Turbocharger_valve=v; break;
}
break;
case 15:
switch (idx){
case 2: fuelConsumption =v; break;
}
break;
case 16:
switch (idx){
case 3: supplyVoltage =v; break;
}
break;
}
break;
case ADR_Dashboard:
switch (group){
case 1:
switch (idx){
case 0: vehicleSpeed = v; break;
//case 1: engineSpeed = v; break;
case 2: oilPressure = v; break;
}
break;
case 2:
switch (idx){
case 0: odometer = v; break;
case 1: fuelLevel = v; break;
}
break;
case 3:
switch (idx){
case 0: fuelLevel = v; break;
}
break;
case 50:
switch (idx){
//case 1: engineSpeed = v; break;
case 2: oilTemp = v; break;
case 3: coolantTemp = v; break;
}
break;
}
break;
}
if (units.length() != 0){
dtostrf(v,4, 2, buf);
t=String(buf) + " " + units;
}
Serial.println(t);
//lcd.setCursor(0, idx);
//while (t.length() < 20) t += " ";
//lcd.print(t);
}
sensorCounter++;
return true;
}
void alarm(){
if (alarmCounter > 10) return;
tone(pinBuzzer, 1200);
delay(100);
noTone(pinBuzzer);
alarmCounter++;
}
void setup(){
myGLCD.InitLCD(PORTRAIT); // инициируем дисплей (в качестве параметра данной функции можно указать ориентацию дисплея: PORTRAIT или LANDSCAPE), по умолчанию LANDSCAPE - горизонтальная ориентация
//myGLCD.clrScr(); // стираем всю информацию с дисплея
pinMode(pinKLineTX, OUTPUT);
digitalWrite(pinKLineTX, HIGH);
pinMode(pinButton, INPUT);
pinMode(pinButton, INPUT_PULLUP);
pinMode(pinBuzzer, OUTPUT);
/*tone(pinBuzzer, 1200);
delay(100);
noTone(pinBuzzer);*/
Serial.begin(19200);
Serial.println(F("SETUP"));
Serial.println(F("START"));
}
void loop(){
if (digitalRead(pinButton) == LOW){
currPage++;
if (currPage > 2) currPage = 1;
//** lcd.clear();
//** lcd.setCursor(0,0);
//**lcd.print(F("page "));
//**lcd.print(currPage);
errorTimeout = 0;
errorData = 0;
while (digitalRead(pinButton) == LOW);
}
switch (currPage){
case 1:
if (currAddr != ADR_Dashboard){
connect(ADR_Dashboard, 9600);
} else {
readSensors(1);
readSensors(2);
readSensors(50);
}
break;
case 2:
if (currAddr != ADR_Engine) {
connect(ADR_Engine, 9600);
} else {
readSensors(3);
readSensors(11);
readSensors(15);////**************------------
readSensors(16);////*************---------------
}
break;
}
//*** updateDisplay();
/*
myGLCD.setFont(BigFont); // устанавливаем большой шрифт
myGLCD.setColor(VGA_WHITE); // устанавливаем цвет текста
myGLCD.print("PR1:",LEFT, 3);
myGLCD.print("PR2:",LEFT, 25); // выводим текст на дисплей
myGLCD.print("PR3:", LEFT, 50); // выводим текст на дисплей
myGLCD.print("PR4:", LEFT, 75); // выводим текст на дисплей
myGLCD.print("PR5:", LEFT, 100); // выводим текст на дисплей
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(engineSpeed,60,3);
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(TurboPressure,60,25);
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(Turbocharger_valve,60,50);
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(EGR_duty,60,75);
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(EGR_Consumption,60,100);
*/
myGLCD.setFont(SmallFont); // устанавливаем большой шрифт
myGLCD.setColor(VGA_WHITE); // устанавливаем цвет текста
myGLCD.print(" PR1:",LEFT, 3);
myGLCD.print(" PR2:",LEFT, 13);
myGLCD.print(" PR3:", LEFT, 23); // выводим текст на дисплей
myGLCD.print(" PR4:", LEFT, 33); // выводим текст на дисплей
myGLCD.print(" PR5:", LEFT, 43); // выводим текст на дисплей
myGLCD.print(" PR6:", LEFT, 53); // выводим текст на дисплей
myGLCD.print(" PR7:", LEFT, 63);
myGLCD.print(" PR8:", LEFT, 73);
myGLCD.print(" PR9:", LEFT, 83);
myGLCD.print("PR10:", LEFT, 93);
myGLCD.print("PR11:", LEFT, 103);
myGLCD.print("PR12:", LEFT, 113);
myGLCD.printNumI(engineSpeed,60,5);
myGLCD.printNumI(coolantTemp,60,15);
myGLCD.printNumI(oilTemp,60,25);
myGLCD.printNumI(supplyVoltage,60,35);
myGLCD.printNumI(fuelConsumption,60,45);
myGLCD.printNumI(odometer,60,55);
myGLCD.printNumI(TurboPressure,60,65);
myGLCD.printNumI(Turbocharger_valve,60,75);
myGLCD.printNumI(EGR_duty,60,85);
myGLCD.printNumI(EGR_Consumption,60,95);
myGLCD.printNumI(EGR_Consumption_target,60,105);
myGLCD.printNumI(7420,60,115);
Serial.println();
Serial.print ("engineSpeed: "); Serial.println(engineSpeed);
Serial.print ("coolantTemp : "); Serial.println(coolantTemp);
Serial.print ("oilTemp : "); Serial.println(oilTemp);
Serial.print ("supplyVoltage : "); Serial.println(supplyVoltage);
Serial.print ("fuelConsumption : "); Serial.println(fuelConsumption);
Serial.print ("odometer : "); Serial.println(odometer);
Serial.print ("TurboPressure : "); Serial.println(TurboPressure);
Serial.print ("Turbocharger_valve "); Serial.println(Turbocharger_valve);
Serial.print ("EGR_duty: "); Serial.println(EGR_duty);
Serial.print ("EGR_Consumption: "); Serial.println(TurboPressure);
Serial.print ("EGR_Consumption_target: "); Serial.println(TurboPressure_target);
Serial.println();
}
#include <UTFT.h> // подключаем библиотеку UTFT
extern uint8_t SmallFont[]; // подключаем маленький шрифт
extern uint8_t BigFont[]; // подключаем большой шрифт
extern uint8_t SevenSegNumFont[]; // подключаем цифровой шрифт
UTFT myGLCD(ST7735, 11, 13, 10, 8, 9);
#include <Wire.h>
#include "NewSoftwareSerial.h"
#define pinKLineRX 5
#define pinKLineTX 6
#define pinLED 2
#define pinBuzzer 3
#define pinButton 4
#define ADR_Engine 0x01
#define ADR_Gears 0x02
#define ADR_ABS_Brakes 0x03
#define ADR_Airbag 0x15
#define ADR_Dashboard 0x17
#define ADR_Immobilizer 0x25
#define ADR_Central_locking 0x35
//#define DEBUG 1
//LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x20 for a 16 chars and 2 line display
NewSoftwareSerial obd(pinKLineRX, pinKLineTX, false); // RX, TX, inverse logic
uint8_t currAddr = 0;
uint8_t blockCounter = 0;
uint8_t errorTimeout = 0;
uint8_t errorData = 0;
bool connected = false;
int sensorCounter = 0;
int pageUpdateCounter = 0;
int alarmCounter = 0;
uint8_t currPage = 1; //************************
int8_t coolantTemp = 0; //Температурв ОЖ 1-1-3 /////0-1-2-3
int8_t oilTemp = 0; //Температура Масла 17-50-2
int8_t intakeAirTemp = 0; //Температура вохдуха
int8_t oilPressure = 0; //Давление масла
float engineLoad = 0; //
int engineSpeed = 0; //Обороты двигателя 1-1-0
float throttleValve = 0; //Дрорссельная заслонка(клапан)
float supplyVoltage = 0; //Напряжение питания (аккума) 1-16-3
uint8_t vehicleSpeed = 0; //Скорость автомобиля
uint8_t fuelConsumption = 0;//Потребление топлива 1-15-2 л/ч
uint8_t fuelLevel = 0; //Уровень топлива 17-3-0
unsigned long odometer = 0; // Одометр 17-2-0
// наши параметры
int TurboPressure = 0;
int TurboPressure_target = 0;
uint8_t Turbocharger_valve = 0;
uint8_t EGR_duty = 0;
int EGR_Consumption = 0;
int EGR_Consumption_target = 0;
String floatToString(float v){
String res;
char buf[16];
dtostrf(v,4, 2, buf);
res=String(buf);
return res;
}
void disconnect(){
connected = false;
currAddr = 0;
}
void obdWrite(uint8_t data){
#ifdef DEBUG
Serial.print("uC:");
Serial.println(data, HEX);
#endif
obd.write(data);
}
uint8_t obdRead(){
unsigned long timeout = millis() + 1000;
while (!obd.available()){
if (millis() >= timeout) {
Serial.println(F("ERROR: obdRead timeout"));
disconnect();
errorTimeout++;
return 0;
}
}
uint8_t data = obd.read();
#ifdef DEBUG
Serial.print("ECU:");
Serial.println(data, HEX);
#endif
return data;
}
// 5Bd, 7O1
void send5baud(uint8_t data){
// // 1 start bit, 7 data bits, 1 parity, 1 stop bit
#define bitcount 10
byte bits[bitcount];
byte even=1;
byte bit;
for (int i=0; i < bitcount; i++){
bit=0;
if (i == 0) bit = 0;
else if (i == 8) bit = even; // computes parity bit
else if (i == 9) bit = 1;
else {
bit = (byte) ((data & (1 << (i-1))) != 0);
even = even ^ bit;
}
Serial.print(F("bit"));
Serial.print(i);
Serial.print(F("="));
Serial.print(bit);
if (i == 0) Serial.print(F(" startbit"));
else if (i == 8) Serial.print(F(" parity"));
else if (i == 9) Serial.print(F(" stopbit"));
Serial.println();
bits[i]=bit;
}
// now send bit stream
for (int i=0; i < bitcount+1; i++){
if (i != 0){
// wait 200 ms (=5 baud), adjusted by latency correction
delay(200);
if (i == bitcount) break;
}
if (bits[i] == 1){
// high
digitalWrite(pinKLineTX, HIGH);
} else {
// low
digitalWrite(pinKLineTX, LOW);
}
}
obd.flush();
}
bool KWP5BaudInit(uint8_t addr){
Serial.println(F("---KWP 5 baud init"));
//delay(3000);
send5baud(addr);
return true;
}
bool KWPSendBlock(char *s, int size){
Serial.print(F("---KWPSend sz="));
Serial.print(size);
Serial.print(F(" blockCounter="));
Serial.println(blockCounter);
// show data
Serial.print(F("OUT:"));
for (int i=0; i < size; i++){
uint8_t data = s[i];
Serial.print(data, HEX);
Serial.print(" ");
}
Serial.println();
for (int i=0; i < size; i++){
uint8_t data = s[i];
obdWrite(data);
if (i < size-1){
uint8_t complement = obdRead();
if (complement != (data ^ 0xFF)){
Serial.println(F("ERROR: invalid complement"));
disconnect();
errorData++;
return false;
}
}
}
blockCounter++;
return true;
}
bool KWPReceiveBlock(char s[], int maxsize, int &size){
bool ackeachbyte = false;
uint8_t data = 0;
int recvcount = 0;
if (size == 0) ackeachbyte = true;
Serial.print(F("---KWPReceive sz="));
Serial.print(size);
Serial.print(F(" blockCounter="));
Serial.println(blockCounter);
if (size > maxsize) {
Serial.println("ERROR: invalid maxsize");
return false;
}
unsigned long timeout = millis() + 1000;
while ((recvcount == 0) || (recvcount != size)) {
while (obd.available()){
data = obdRead();
s[recvcount] = data;
recvcount++;
if ((size == 0) && (recvcount == 1)) {
size = data + 1;
if (size > maxsize) {
Serial.println("ERROR: invalid maxsize");
return false;
}
}
if ((ackeachbyte) && (recvcount == 2)) {
if (data != blockCounter){
Serial.println(F("ERROR: invalid blockCounter"));
disconnect();
errorData++;
return false;
}
}
if ( ((!ackeachbyte) && (recvcount == size)) || ((ackeachbyte) && (recvcount < size)) ){
obdWrite(data ^ 0xFF); // send complement ack
}
timeout = millis() + 1000;
}
if (millis() >= timeout){
Serial.println(F("ERROR: timeout"));
disconnect();
errorTimeout++;
return false;
}
}
// show data
Serial.print(F("IN: sz="));
Serial.print(size);
Serial.print(F(" data="));
for (int i=0; i < size; i++){
uint8_t data = s[i];
Serial.print(data, HEX);
Serial.print(F(" "));
}
Serial.println();
blockCounter++;
return true;
}
bool KWPSendAckBlock(){
Serial.print(F("---KWPSendAckBlock blockCounter="));
Serial.println(blockCounter);
char buf[32];
sprintf(buf, "\x03%c\x09\x03", blockCounter);
return (KWPSendBlock(buf, 4));
}
bool connect(uint8_t addr, int baudrate){
Serial.print(F("------connect addr="));
Serial.print(addr);
Serial.print(F(" baud="));
Serial.println(baudrate);
tone(pinBuzzer, 1200);
delay(100);
noTone(pinBuzzer);
blockCounter = 0;
currAddr = 0;
obd.begin(baudrate);
KWP5BaudInit(addr);
char s[3];
int size = 3;
if (!KWPReceiveBlock(s, 3, size)) return false;
if ( (((uint8_t)s[0]) != 0x55)
|| (((uint8_t)s[1]) != 0x01)
|| (((uint8_t)s[2]) != 0x8A) ){
Serial.println(F("ERROR: invalid magic"));
disconnect();
errorData++;
return false;
}
currAddr = addr;
connected = true;
if (!readConnectBlocks()) return false;
return true;
}
bool readConnectBlocks(){
// read connect blocks
Serial.println(F("------readconnectblocks"));
String info;
while (true){
int size = 0;
char s[64];
if (!(KWPReceiveBlock(s, 64, size))) return false;
if (size == 0) return false;
if (s[2] == '\x09') break;
if (s[2] != '\xF6') {
Serial.println(F("ERROR: unexpected answer"));
disconnect();
errorData++;
return false;
}
String text = String(s);
info += text.substring(3, size-2);
if (!KWPSendAckBlock()) return false;
}
Serial.print("label=");
Serial.println(info);
return true;
}
bool readSensors(int group){
Serial.print(F("------readSensors "));
Serial.println(group);
// lcdPrint(0,0, F("KW1281 sensor"), 20);
char s[64];
sprintf(s, "\x04%c\x29%c\x03", blockCounter, group);
if (!KWPSendBlock(s, 5)) return false;
int size = 0;
KWPReceiveBlock(s, 64, size);
if (s[2] != '\xe7') {
Serial.println(F("ERROR: invalid answer"));
disconnect();
errorData++;
return false;
}
int count = (size-4) / 3;
Serial.print(F("count="));
Serial.println(count);
for (int idx=0; idx < count; idx++){
byte k=s[3 + idx*3];
byte a=s[3 + idx*3+1];
byte b=s[3 + idx*3+2];
String n;
float v = 0;
Serial.print(F("type="));
Serial.print(k);
Serial.print(F(" a="));
Serial.print(a);
Serial.print(F(" b="));
Serial.print(b);
Serial.print(F(" text="));
String t = "";
String units = "";
char buf[32];
switch (k){
case 1: v=0.2*a*b; units=F("rpm"); break;
case 2: v=a*0.002*b; units=F("%%"); break;
case 3: v=0.002*a*b; units=F("Deg"); break;
case 4: v=abs(b-127)*0.01*a; units=F("ATDC"); break;
case 5: v=a*(b-100)*0.1; units=F("°C");break;
case 6: v=0.001*a*b; units=F("V");break;
case 7: v=0.01*a*b; units=F("km/h");break;
case 8: v=0.1*a*b; units=F(" ");break;
case 9: v=(b-127)*0.02*a; units=F("Deg");break;
case 10: if (b == 0) t=F("COLD"); else t=F("WARM");break;
case 11: v=0.0001*a*(b-128)+1; units = F(" ");break;
case 12: v=0.001*a*b; units =F("Ohm");break;
case 13: v=(b-127)*0.001*a; units =F("mm");break;
case 14: v=0.005*a*b; units=F("bar");break;
case 15: v=0.01*a*b; units=F("ms");break;
case 18: v=0.04*a*b; units=F("mbar");break;
case 19: v=a*b*0.01; units=F("l");break;
case 20: v=a*(b-128)/128; units=F("%%");break;
case 21: v=0.001*a*b; units=F("V");break;
case 22: v=0.001*a*b; units=F("ms");break;
case 23: v=b/256*a; units=F("%%");break;
case 24: v=0.001*a*b; units=F("A");break;
case 25: v=(b*1.421)+(a/182); units=F("g/s");break;
case 26: v=float(b-a); units=F("C");break;
case 27: v=abs(b-128)*0.01*a; units=F("°");break;
case 28: v=float(b-a); units=F(" ");break;
case 30: v=b/12*a; units=F("Deg k/w");break;
case 31: v=b/2560*a; units=F("°C");break;
case 33: v=100*b/a; units=F("%%");break;
case 34: v=(b-128)*0.01*a; units=F("kW");break;
case 35: v=0.01*a*b; units=F("l/h");break;
case 36: v=((unsigned long)a)*2560+((unsigned long)b)*10; units=F("km");break;
case 37: v=b; break; // oil pressure ?!
// ADP: FIXME!
/*case 37: switch(b){
case 0: sprintf(buf, F("ADP OK (%d,%d)"), a,b); t=String(buf); break;
case 1: sprintf(buf, F("ADP RUN (%d,%d)"), a,b); t=String(buf); break;
case 0x10: sprintf(buf, F("ADP ERR (%d,%d)"), a,b); t=String(buf); break;
default: sprintf(buf, F("ADP (%d,%d)"), a,b); t=String(buf); break;
}*/
case 38: v=(b-128)*0.001*a; units=F("Deg k/w"); break;
case 39: v=b/256*a; units=F("mg/h"); break;
case 40: v=b*0.1+(25.5*a)-400; units=F("A"); break;
case 41: v=b+a*255; units=F("Ah"); break;
case 42: v=b*0.1+(25.5*a)-400; units=F("Kw"); break;
case 43: v=b*0.1+(25.5*a); units=F("V"); break;
case 44: sprintf(buf, "%2d:%2d", a,b); t=String(buf); break;
case 45: v=0.1*a*b/100; units=F(" "); break;
case 46: v=(a*b-3200)*0.0027; units=F("Deg k/w"); break;
case 47: v=(b-128)*a; units=F("ms"); break;
case 48: v=b+a*255; units=F(" "); break;
case 49: v=(b/4)*a*0.1; units=F("mg/h"); break;
case 50: v=(b-128)/(0.01*a); units=F("mbar"); break;
case 51: v=((b-128)/255)*a; units=F("mg/h"); break;
case 52: v=b*0.02*a-a; units=F("Nm"); break;
case 53: v=(b-128)*1.4222+0.006*a; units=F("g/s"); break;
case 54: v=a*256+b; units=F("count"); break;
case 55: v=a*b/200; units=F("s"); break;
case 56: v=a*256+b; units=F("WSC"); break;
case 57: v=a*256+b+65536; units=F("WSC"); break;
case 59: v=(a*256+b)/32768; units=F("g/s"); break;
case 60: v=(a*256+b)*0.01; units=F("sec"); break;
case 62: v=0.256*a*b; units=F("S"); break;
case 64: v=float(a+b); units=F("Ohm"); break;
case 65: v=0.01*a*(b-127); units=F("mm"); break;
case 66: v=(a*b)/511.12; units=F("V"); break;
case 67: v=(640*a)+b*2.5; units=F("Deg"); break;
case 68: v=(256*a+b)/7.365; units=F("deg/s");break;
case 69: v=(256*a +b)*0.3254; units=F("Bar");break;
case 70: v=(256*a +b)*0.192; units=F("m/s^2");break;
default: sprintf(buf, "%2x, %2x ", a, b); break;
}
switch (currAddr){
case ADR_Engine:
switch(group){
case 3:
switch (idx){
/*case 0: engineSpeed = v; break;
case 1: supplyVoltage=v; break;
case 2: coolantTemp =v; break;
case 3: intakeAirTemp=v; break;*/
case 0: engineSpeed = v; break;
case 1: EGR_Consumption_target =v; break;
case 2: EGR_Consumption=v; break;
case 3: EGR_duty=v; break;
}
break;
case 11:
switch (idx){
/*case 1: engineLoad=v; break;
case 2: vehicleSpeed =v; break;
case 3: fuelConsumption=v; break;*/
case 0: engineSpeed = v; break;
case 1: TurboPressure_target =v; break;
case 2: TurboPressure =v; break;
case 3: Turbocharger_valve=v; break;
}
break;
case 15:
switch (idx){
case 2: fuelConsumption =v; break;
}
break;
case 16:
switch (idx){
case 3: supplyVoltage =v; break;
}
break;
}
break;
case ADR_Dashboard:
switch (group){
case 1:
switch (idx){
case 0: vehicleSpeed = v; break;
case 1: engineSpeed = v; break;
case 2: oilPressure = v; break;
}
break;
case 2:
switch (idx){
case 0: odometer = v; break;
case 1: fuelLevel = v; break;
}
break;
case 3:
switch (idx){
case 0: fuelLevel = v; break;
}
break;
case 50:
switch (idx){
case 1: engineSpeed = v; break;
case 2: oilTemp = v; break;
case 3: coolantTemp = v; break;
}
break;
}
break;
}
if (units.length() != 0){
dtostrf(v,4, 2, buf);
t=String(buf) + " " + units;
}
Serial.println(t);
//lcd.setCursor(0, idx);
//while (t.length() < 20) t += " ";
//lcd.print(t);
}
sensorCounter++;
return true;
}
void alarm(){
if (alarmCounter > 10) return;
tone(pinBuzzer, 1200);
delay(100);
noTone(pinBuzzer);
alarmCounter++;
}
void setup(){
myGLCD.InitLCD(PORTRAIT); // инициируем дисплей (в качестве параметра данной функции можно указать ориентацию дисплея: PORTRAIT или LANDSCAPE), по умолчанию LANDSCAPE - горизонтальная ориентация
//myGLCD.clrScr();
pinMode(pinKLineTX, OUTPUT);
digitalWrite(pinKLineTX, HIGH);
pinMode(pinButton, INPUT);
pinMode(pinButton, INPUT_PULLUP);
pinMode(pinBuzzer, OUTPUT);
/*tone(pinBuzzer, 1200);
delay(100);
noTone(pinBuzzer);*/
Serial.begin(19200);
Serial.println(F("SETUP"));
Serial.println(F("START"));
}
void loop(){
if (digitalRead(pinButton) == LOW){
currPage++;
if (currPage > 2) currPage = 1;
errorTimeout = 0;
errorData = 0;
while (digitalRead(pinButton) == LOW);
}
switch (currPage){
case 1:
if (currAddr != ADR_Dashboard){
connect(ADR_Dashboard, 9600);
} else {
readSensors(1);
readSensors(2);
readSensors(50);
}
break;
case 2:
if (currAddr != ADR_Engine) {
connect(ADR_Engine, 9600);
} else {
readSensors(3);
readSensors(11);
readSensors(15);
readSensors(16);
}
break;
}
/*
myGLCD.setFont(BigFont); // устанавливаем большой шрифт
myGLCD.setColor(VGA_WHITE); // устанавливаем цвет текста
myGLCD.print("PR1:",LEFT, 3);
myGLCD.print("PR2:",LEFT, 25); // выводим текст на дисплей
myGLCD.print("PR3:", LEFT, 50); // выводим текст на дисплей
myGLCD.print("PR4:", LEFT, 75); // выводим текст на дисплей
myGLCD.print("PR5:", LEFT, 100); // выводим текст на дисплей
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(engineSpeed,60,3);
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(TurboPressure,60,25);
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(Turbocharger_valve,60,50);
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(EGR_duty,60,75);
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(EGR_Consumption,60,100);
*/
myGLCD.setFont(SmallFont); // устанавливаем большой шрифт
myGLCD.setColor(VGA_WHITE); // устанавливаем цвет текста
myGLCD.print(" PR1:",LEFT, 3);
myGLCD.print(" PR2:",LEFT, 13);
myGLCD.print(" PR3:", LEFT, 23); // выводим текст на дисплей
myGLCD.print(" PR4:", LEFT, 33); // выводим текст на дисплей
myGLCD.print(" PR5:", LEFT, 43); // выводим текст на дисплей
myGLCD.print(" PR6:", LEFT, 53); // выводим текст на дисплей
myGLCD.print(" PR7:", LEFT, 63);
myGLCD.print(" PR8:", LEFT, 73);
myGLCD.print(" PR9:", LEFT, 83);
myGLCD.print("PR10:", LEFT, 93);
myGLCD.print("PR11:", LEFT, 103);
myGLCD.print("PR12:", LEFT, 113);
myGLCD.printNumI(engineSpeed,60,5);
myGLCD.printNumI(coolantTemp,60,15);
myGLCD.printNumI(oilTemp,60,25);
myGLCD.printNumI(supplyVoltage,60,35);
myGLCD.printNumI(fuelConsumption,60,45);
myGLCD.printNumI(odometer,60,55);
myGLCD.printNumI(TurboPressure,60,65);
myGLCD.printNumI(Turbocharger_valve,60,75);
myGLCD.printNumI(EGR_duty,60,85);
myGLCD.printNumI(EGR_Consumption,60,95);
myGLCD.printNumI(EGR_Consumption_target,60,105);
myGLCD.printNumI(7420,60,115);
/*Serial.println();
Serial.print ("engineSpeed: "); Serial.println(engineSpeed);
Serial.print ("coolantTemp : "); Serial.println(coolantTemp);
Serial.print ("oilTemp : "); Serial.println(oilTemp);
Serial.print ("supplyVoltage : "); Serial.println(supplyVoltage);
Serial.print ("fuelConsumption : "); Serial.println(fuelConsumption);
Serial.print ("odometer : "); Serial.println(odometer);
Serial.print ("TurboPressure : "); Serial.println(TurboPressure);
Serial.print ("Turbocharger_valve "); Serial.println(Turbocharger_valve);
Serial.print ("EGR_duty: "); Serial.println(EGR_duty);
Serial.print ("EGR_Consumption: "); Serial.println(TurboPressure);
Serial.print ("EGR_Consumption_target: "); Serial.println(TurboPressure_target);
Serial.println(); */
}
А что конкретно не понятно то? Когда currPage=1 идет подключение к щитку приборов и вытягивается 3 переменных, когда currPage=2, соответственно подключение к ECM , вытягивается 4 переменные, все по скетчу, все работает.
переменная по нажатию кнопки переключает экраны, ну и естественно переключается между блоками. Действительно, всё просто. Это ж надо так затупить )))) Мне порой нравится ваш подход в помощи, где посложнеее сами код подправите, где есть повод поразмышлять, то направите в нужную сторону)) Спасибо ))
посмотрите в вагкоме какие параметры вам нужны из приборки. Желательно выбрать те, которые медленно меняются. Алгоритм будет такой - основная связь будет идти с блоком двигателя, и иногда, периодически, будет прерываться на связь с приборкой. Например раз в 5 сек или ещё реже (в этот момент отображение параметров от блока ДВС на экране будет ненадолго замирать)
на опеле, когда мы БК делали было проще - приборка висела на отдельной к-линии (отдельный контакт в обд разъеме). Мы взяли второй к-лайн адаптер и связь сделали одновременно и с приборкой и с ECM.
Разобрался с приборкой, получил некоторые данные. l/h -величина не меняемая. Температура масла всегда на 78, наверное не работает датчик.Посещает мысль сделать тоже кнопку для переключения между блоками..будет тип 3-ри экрана. 1-Движок 2-Приборка 3-Общий (как вы и предлогали, делать запросы по несколько секунд к одному, потом к второму блоку). Ну в принципе мне бы хватило того, что есть в приборке, но еще хочется контролировать напругу аккума(а она только в блоке двигателе) или может какой вариант есть узнать напругу через дуню. Всё так же нуждаюсь в вашей помощи с расчетом расхода топлива и остатка хода.
#include <UTFT.h> // подключаем библиотеку UTFT
extern uint8_t SmallFont[]; // подключаем маленький шрифт
extern uint8_t BigFont[]; // подключаем большой шрифт
extern uint8_t SevenSegNumFont[]; // подключаем цифровой шрифт
UTFT myGLCD(ST7735, 11, 13, 10, 8, 9);
#include <Wire.h>
#include "NewSoftwareSerial.h"
#define pinKLineRX 5
#define pinKLineTX 6
#define pinLED 2
#define pinBuzzer 3
#define pinButton 4
#define ADR_Engine 0x01
#define ADR_Gears 0x02
#define ADR_ABS_Brakes 0x03
#define ADR_Airbag 0x15
#define ADR_Dashboard 0x17
#define ADR_Immobilizer 0x25
#define ADR_Central_locking 0x35
//#define DEBUG 1
//LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x20 for a 16 chars and 2 line display
NewSoftwareSerial obd(pinKLineRX, pinKLineTX, false); // RX, TX, inverse logic
uint8_t currAddr = 0;
uint8_t blockCounter = 0;
uint8_t errorTimeout = 0;
uint8_t errorData = 0;
bool connected = false;
int sensorCounter = 0;
int pageUpdateCounter = 0;
int alarmCounter = 0;
uint8_t currPage = 1; //************************
int8_t coolantTemp = 0; //Температурв ОЖ 1-1-3 /////0-1-2-3
int8_t oilTemp = 0; //Температура Масла 17-50-2
int8_t intakeAirTemp = 0; //Температура вохдуха
int8_t oilPressure = 0; //Давление масла
float engineLoad = 0; //
int engineSpeed = 0; //Обороты двигателя 1-1-0
float throttleValve = 0; //Дрорссельная заслонка(клапан)
float supplyVoltage = 0; //Напряжение питания (аккума) 1-16-3
uint8_t vehicleSpeed = 0; //Скорость автомобиля
uint8_t fuelConsumption = 0;//Потребление топлива 1-15-2 л/ч
uint8_t fuelLevel = 0; //Уровень топлива 17-3-0
unsigned long odometer = 0; // Одометр 17-2-0
// наши параметры
int TurboPressure = 0;
int TurboPressure_target = 0;
uint8_t Turbocharger_valve = 0;
uint8_t EGR_duty = 0;
int EGR_Consumption = 0;
int EGR_Consumption_target = 0;
String floatToString(float v){
String res;
char buf[16];
dtostrf(v,4, 2, buf);
res=String(buf);
return res;
}
void disconnect(){
connected = false;
currAddr = 0;
}
void obdWrite(uint8_t data){
#ifdef DEBUG
Serial.print("uC:");
Serial.println(data, HEX);
#endif
obd.write(data);
}
uint8_t obdRead(){
unsigned long timeout = millis() + 1000;
while (!obd.available()){
if (millis() >= timeout) {
Serial.println(F("ERROR: obdRead timeout"));
disconnect();
errorTimeout++;
return 0;
}
}
uint8_t data = obd.read();
#ifdef DEBUG
Serial.print("ECU:");
Serial.println(data, HEX);
#endif
return data;
}
// 5Bd, 7O1
void send5baud(uint8_t data){
// // 1 start bit, 7 data bits, 1 parity, 1 stop bit
#define bitcount 10
byte bits[bitcount];
byte even=1;
byte bit;
for (int i=0; i < bitcount; i++){
bit=0;
if (i == 0) bit = 0;
else if (i == 8) bit = even; // computes parity bit
else if (i == 9) bit = 1;
else {
bit = (byte) ((data & (1 << (i-1))) != 0);
even = even ^ bit;
}
Serial.print(F("bit"));
Serial.print(i);
Serial.print(F("="));
Serial.print(bit);
if (i == 0) Serial.print(F(" startbit"));
else if (i == 8) Serial.print(F(" parity"));
else if (i == 9) Serial.print(F(" stopbit"));
Serial.println();
bits[i]=bit;
}
// now send bit stream
for (int i=0; i < bitcount+1; i++){
if (i != 0){
// wait 200 ms (=5 baud), adjusted by latency correction
delay(200);
if (i == bitcount) break;
}
if (bits[i] == 1){
// high
digitalWrite(pinKLineTX, HIGH);
} else {
// low
digitalWrite(pinKLineTX, LOW);
}
}
obd.flush();
}
bool KWP5BaudInit(uint8_t addr){
Serial.println(F("---KWP 5 baud init"));
//delay(3000);
send5baud(addr);
return true;
}
bool KWPSendBlock(char *s, int size){
Serial.print(F("---KWPSend sz="));
Serial.print(size);
Serial.print(F(" blockCounter="));
Serial.println(blockCounter);
// show data
Serial.print(F("OUT:"));
for (int i=0; i < size; i++){
uint8_t data = s[i];
Serial.print(data, HEX);
Serial.print(" ");
}
Serial.println();
for (int i=0; i < size; i++){
uint8_t data = s[i];
obdWrite(data);
if (i < size-1){
uint8_t complement = obdRead();
if (complement != (data ^ 0xFF)){
Serial.println(F("ERROR: invalid complement"));
disconnect();
errorData++;
return false;
}
}
}
blockCounter++;
return true;
}
bool KWPReceiveBlock(char s[], int maxsize, int &size){
bool ackeachbyte = false;
uint8_t data = 0;
int recvcount = 0;
if (size == 0) ackeachbyte = true;
Serial.print(F("---KWPReceive sz="));
Serial.print(size);
Serial.print(F(" blockCounter="));
Serial.println(blockCounter);
if (size > maxsize) {
Serial.println("ERROR: invalid maxsize");
return false;
}
unsigned long timeout = millis() + 1000;
while ((recvcount == 0) || (recvcount != size)) {
while (obd.available()){
data = obdRead();
s[recvcount] = data;
recvcount++;
if ((size == 0) && (recvcount == 1)) {
size = data + 1;
if (size > maxsize) {
Serial.println("ERROR: invalid maxsize");
return false;
}
}
if ((ackeachbyte) && (recvcount == 2)) {
if (data != blockCounter){
Serial.println(F("ERROR: invalid blockCounter"));
disconnect();
errorData++;
return false;
}
}
if ( ((!ackeachbyte) && (recvcount == size)) || ((ackeachbyte) && (recvcount < size)) ){
obdWrite(data ^ 0xFF); // send complement ack
}
timeout = millis() + 1000;
}
if (millis() >= timeout){
Serial.println(F("ERROR: timeout"));
disconnect();
errorTimeout++;
return false;
}
}
// show data
Serial.print(F("IN: sz="));
Serial.print(size);
Serial.print(F(" data="));
for (int i=0; i < size; i++){
uint8_t data = s[i];
Serial.print(data, HEX);
Serial.print(F(" "));
}
Serial.println();
blockCounter++;
return true;
}
bool KWPSendAckBlock(){
Serial.print(F("---KWPSendAckBlock blockCounter="));
Serial.println(blockCounter);
char buf[32];
sprintf(buf, "\x03%c\x09\x03", blockCounter);
return (KWPSendBlock(buf, 4));
}
bool connect(uint8_t addr, int baudrate){
Serial.print(F("------connect addr="));
Serial.print(addr);
Serial.print(F(" baud="));
Serial.println(baudrate);
tone(pinBuzzer, 1200);
delay(100);
noTone(pinBuzzer);
blockCounter = 0;
currAddr = 0;
obd.begin(baudrate);
KWP5BaudInit(addr);
char s[3];
int size = 3;
if (!KWPReceiveBlock(s, 3, size)) return false;
if ( (((uint8_t)s[0]) != 0x55)
|| (((uint8_t)s[1]) != 0x01)
|| (((uint8_t)s[2]) != 0x8A) ){
Serial.println(F("ERROR: invalid magic"));
disconnect();
errorData++;
return false;
}
currAddr = addr;
connected = true;
if (!readConnectBlocks()) return false;
return true;
}
bool readConnectBlocks(){
// read connect blocks
Serial.println(F("------readconnectblocks"));
String info;
while (true){
int size = 0;
char s[64];
if (!(KWPReceiveBlock(s, 64, size))) return false;
if (size == 0) return false;
if (s[2] == '\x09') break;
if (s[2] != '\xF6') {
Serial.println(F("ERROR: unexpected answer"));
disconnect();
errorData++;
return false;
}
String text = String(s);
info += text.substring(3, size-2);
if (!KWPSendAckBlock()) return false;
}
Serial.print("label=");
Serial.println(info);
return true;
}
bool readSensors(int group){
Serial.print(F("------readSensors "));
Serial.println(group);
// lcdPrint(0,0, F("KW1281 sensor"), 20);
char s[64];
sprintf(s, "\x04%c\x29%c\x03", blockCounter, group);
if (!KWPSendBlock(s, 5)) return false;
int size = 0;
KWPReceiveBlock(s, 64, size);
if (s[2] != '\xe7') {
Serial.println(F("ERROR: invalid answer"));
disconnect();
errorData++;
return false;
}
int count = (size-4) / 3;
Serial.print(F("count="));
Serial.println(count);
for (int idx=0; idx < count; idx++){
byte k=s[3 + idx*3];
byte a=s[3 + idx*3+1];
byte b=s[3 + idx*3+2];
String n;
float v = 0;
Serial.print(F("type="));
Serial.print(k);
Serial.print(F(" a="));
Serial.print(a);
Serial.print(F(" b="));
Serial.print(b);
Serial.print(F(" text="));
String t = "";
String units = "";
char buf[32];
switch (k){
case 1: v=0.2*a*b; units=F("rpm"); break;
case 2: v=a*0.002*b; units=F("%%"); break;
case 3: v=0.002*a*b; units=F("Deg"); break;
case 4: v=abs(b-127)*0.01*a; units=F("ATDC"); break;
case 5: v=a*(b-100)*0.1; units=F("°C");break;
case 6: v=0.001*a*b; units=F("V");break;
case 7: v=0.01*a*b; units=F("km/h");break;
case 8: v=0.1*a*b; units=F(" ");break;
case 9: v=(b-127)*0.02*a; units=F("Deg");break;
case 10: if (b == 0) t=F("COLD"); else t=F("WARM");break;
case 11: v=0.0001*a*(b-128)+1; units = F(" ");break;
case 12: v=0.001*a*b; units =F("Ohm");break;
case 13: v=(b-127)*0.001*a; units =F("mm");break;
case 14: v=0.005*a*b; units=F("bar");break;
case 15: v=0.01*a*b; units=F("ms");break;
case 18: v=0.04*a*b; units=F("mbar");break;
case 19: v=a*b*0.01; units=F("l");break;
case 20: v=a*(b-128)/128; units=F("%%");break;
case 21: v=0.001*a*b; units=F("V");break;
case 22: v=0.001*a*b; units=F("ms");break;
case 23: v=b/256*a; units=F("%%");break;
case 24: v=0.001*a*b; units=F("A");break;
case 25: v=(b*1.421)+(a/182); units=F("g/s");break;
case 26: v=float(b-a); units=F("C");break;
case 27: v=abs(b-128)*0.01*a; units=F("°");break;
case 28: v=float(b-a); units=F(" ");break;
case 30: v=b/12*a; units=F("Deg k/w");break;
case 31: v=b/2560*a; units=F("°C");break;
case 33: v=100*b/a; units=F("%%");break;
case 34: v=(b-128)*0.01*a; units=F("kW");break;
case 35: v=0.01*a*b; units=F("l/h");break;
case 36: v=((unsigned long)a)*2560+((unsigned long)b)*10; units=F("km");break;
case 37: v=b; break; // oil pressure ?!
// ADP: FIXME!
/*case 37: switch(b){
case 0: sprintf(buf, F("ADP OK (%d,%d)"), a,b); t=String(buf); break;
case 1: sprintf(buf, F("ADP RUN (%d,%d)"), a,b); t=String(buf); break;
case 0x10: sprintf(buf, F("ADP ERR (%d,%d)"), a,b); t=String(buf); break;
default: sprintf(buf, F("ADP (%d,%d)"), a,b); t=String(buf); break;
}*/
case 38: v=(b-128)*0.001*a; units=F("Deg k/w"); break;
case 39: v=b/256*a; units=F("mg/h"); break;
case 40: v=b*0.1+(25.5*a)-400; units=F("A"); break;
case 41: v=b+a*255; units=F("Ah"); break;
case 42: v=b*0.1+(25.5*a)-400; units=F("Kw"); break;
case 43: v=b*0.1+(25.5*a); units=F("V"); break;
case 44: sprintf(buf, "%2d:%2d", a,b); t=String(buf); break;
case 45: v=0.1*a*b/100; units=F(" "); break;
case 46: v=(a*b-3200)*0.0027; units=F("Deg k/w"); break;
case 47: v=(b-128)*a; units=F("ms"); break;
case 48: v=b+a*255; units=F(" "); break;
case 49: v=(b/4)*a*0.1; units=F("mg/h"); break;
case 50: v=(b-128)/(0.01*a); units=F("mbar"); break;
case 51: v=((b-128)/255)*a; units=F("mg/h"); break;
case 52: v=b*0.02*a-a; units=F("Nm"); break;
case 53: v=(b-128)*1.4222+0.006*a; units=F("g/s"); break;
case 54: v=a*256+b; units=F("count"); break;
case 55: v=a*b/200; units=F("s"); break;
case 56: v=a*256+b; units=F("WSC"); break;
case 57: v=a*256+b+65536; units=F("WSC"); break;
case 59: v=(a*256+b)/32768; units=F("g/s"); break;
case 60: v=(a*256+b)*0.01; units=F("sec"); break;
case 62: v=0.256*a*b; units=F("S"); break;
case 64: v=float(a+b); units=F("Ohm"); break;
case 65: v=0.01*a*(b-127); units=F("mm"); break;
case 66: v=(a*b)/511.12; units=F("V"); break;
case 67: v=(640*a)+b*2.5; units=F("Deg"); break;
case 68: v=(256*a+b)/7.365; units=F("deg/s");break;
case 69: v=(256*a +b)*0.3254; units=F("Bar");break;
case 70: v=(256*a +b)*0.192; units=F("m/s^2");break;
default: sprintf(buf, "%2x, %2x ", a, b); break;
}
switch (currAddr){
case ADR_Engine:
switch(group){
case 3:
switch (idx){
case 0: engineSpeed = v; break;
case 1: EGR_Consumption_target =v; break;
case 2: EGR_Consumption=v; break;
case 3: EGR_duty=v; break;
}
break;
case 11:
switch (idx){
case 0: engineSpeed = v; break;
case 1: TurboPressure_target =v; break;
case 2: TurboPressure =v; break;
case 3: Turbocharger_valve=v; break;
}
break;
case 15:
switch (idx){
case 2: fuelConsumption =v; break; //Расход топлива л/ч
}
break;
case 16:
switch (idx){
case 3: supplyVoltage =v; break; //Аккум
}
break;
}
break;
case ADR_Dashboard:
switch (group){
case 1:
switch (idx){
case 1: vehicleSpeed = v; break; //Скорость
case 2: engineSpeed = v; break; //Обороты двигателя
// case 3: fuelConsumption =v; break; //Расход топлива л/ч !!! в приборке не меняется
}
break;
case 2:
switch (idx){
case 0: odometer = v; break; //Пробег
//case 1: = v; break; // ????? Температура топлива
}
break;
case 3:
switch (idx){
case 0: fuelLevel = v; break; // Топлива в баку (литр)
}
break;
case 50:
switch (idx){
// case 0: odometer = v; break; //Пробег
// case 1: engineSpeed = v; break; //Обороты двигателя
case 2: oilTemp = v; break; // Температура масла // по ходу не работает датчик всегда показывает 78
}
break;
}
break;
}
if (units.length() != 0){
dtostrf(v,4, 2, buf);
t=String(buf) + " " + units;
}
Serial.println(t);
//lcd.setCursor(0, idx);
//while (t.length() < 20) t += " ";
//lcd.print(t);//
}
sensorCounter++;
return true;
}
void alarm(){
if (alarmCounter > 10) return;
tone(pinBuzzer, 1200);
delay(100);
noTone(pinBuzzer);
alarmCounter++;
}
void setup(){
myGLCD.InitLCD(PORTRAIT); // инициируем дисплей (в качестве параметра данной функции можно указать ориентацию дисплея: PORTRAIT или LANDSCAPE), по умолчанию LANDSCAPE - горизонтальная ориентация
myGLCD.clrScr();
pinMode(pinKLineTX, OUTPUT);
digitalWrite(pinKLineTX, HIGH);
pinMode(pinButton, INPUT);
pinMode(pinButton, INPUT_PULLUP);
pinMode(pinBuzzer, OUTPUT);
/*tone(pinBuzzer, 1200);
delay(100);
noTone(pinBuzzer);*/
Serial.begin(19200);
Serial.println(F("SETUP"));
Serial.println(F("START"));
}
void loop(){
if (digitalRead(pinButton) == LOW){
currPage++;
if (currPage > 2) currPage = 1;
errorTimeout = 0;
errorData = 0;
while (digitalRead(pinButton) == LOW);
}
switch (currPage){
case 1:
if (currAddr != ADR_Dashboard){
connect(ADR_Dashboard, 9600);
} else {
readSensors(1);
readSensors(2);
readSensors(3);
readSensors(50);
}
break;
case 2:
if (currAddr != ADR_Engine) {
connect(ADR_Engine, 9600);
} else {
readSensors(3);
readSensors(11);
readSensors(15);
readSensors(16);
}
break;
}
/*
myGLCD.setFont(BigFont); // устанавливаем большой шрифт
myGLCD.setColor(VGA_WHITE); // устанавливаем цвет текста
myGLCD.print("PR1:",LEFT, 3);
myGLCD.print("PR2:",LEFT, 25); // выводим текст на дисплей
myGLCD.print("PR3:", LEFT, 50); // выводим текст на дисплей
myGLCD.print("PR4:", LEFT, 75); // выводим текст на дисплей
myGLCD.print("PR5:", LEFT, 100); // выводим текст на дисплей
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(engineSpeed,60,3);
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(TurboPressure,60,25);
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(Turbocharger_valve,60,50);
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(EGR_duty,60,75);
myGLCD.setColor(VGA_WHITE);
myGLCD.setFont(BigFont);
myGLCD.printNumI(EGR_Consumption,60,100);
*/
myGLCD.setFont(SmallFont); // устанавливаем большой шрифт
myGLCD.setColor(VGA_WHITE); // устанавливаем цвет текста
myGLCD.print(" PR1:",LEFT, 3);
myGLCD.print(" PR2:",LEFT, 13);
myGLCD.print(" PR3:", LEFT, 23); // выводим текст на дисплей
myGLCD.print(" PR4:", LEFT, 33);
myGLCD.print(" PR5:", LEFT, 43);
myGLCD.print(" PR6:", LEFT, 53);
myGLCD.print(" PR7:", LEFT, 63);
myGLCD.print(" PR8:", LEFT, 73);
myGLCD.print(" PR9:", LEFT, 83);
myGLCD.print(" R10:", LEFT, 93);
myGLCD.print(" R11:", LEFT, 103);
myGLCD.print(" R12:", LEFT, 113);
myGLCD.printNumI(engineSpeed,40,5); myGLCD.print("rpm",95,5);
myGLCD.printNumI(coolantTemp,40,15); myGLCD.print("C",95,15);
myGLCD.printNumI(oilTemp,40,25); myGLCD.print("oilC",95,25);
myGLCD.printNumI(supplyVoltage,40,35); myGLCD.print("Volt",95,35);
myGLCD.printNumI(fuelConsumption,40,45); myGLCD.print("l/h",95,45);
myGLCD.printNumI(odometer,40,55); myGLCD.print("km",95,55);
myGLCD.printNumI(TurboPressure,40,65);
myGLCD.printNumI(Turbocharger_valve,40,75);
myGLCD.printNumI(EGR_duty,40,85);
myGLCD.printNumI(EGR_Consumption,40,95);
//myGLCD.printNumI(EGR_Consumption_target,40,105);
myGLCD.printNumI(fuelLevel,40,105); myGLCD.print("litr",95,105);
myGLCD.printNumI(vehicleSpeed,40,115); myGLCD.print("km/h",95,115);
/*Serial.println();
Serial.print ("engineSpeed: "); Serial.println(engineSpeed);
Serial.print ("coolantTemp : "); Serial.println(coolantTemp);
Serial.print ("oilTemp : "); Serial.println(oilTemp);
Serial.print ("supplyVoltage : "); Serial.println(supplyVoltage);
Serial.print ("fuelConsumption : "); Serial.println(fuelConsumption);
Serial.print ("odometer : "); Serial.println(odometer);
Serial.print ("TurboPressure : "); Serial.println(TurboPressure);
Serial.print ("Turbocharger_valve "); Serial.println(Turbocharger_valve);
Serial.print ("EGR_duty: "); Serial.println(EGR_duty);
Serial.print ("EGR_Consumption: "); Serial.println(TurboPressure);
Serial.print ("EGR_Consumption_target: "); Serial.println(TurboPressure_target);
Serial.println(); */
}
если будет известно цикловое наполнение топливом (ну или часовой расход) - эти параметры только в ECM, то можно рассчитать, кроме средего, также и мгновенный расход топлива в час и на 100км. а также расход за поездку.
Ок, понял. Значит идем дальше... беру всё что мне нужно(переменные, функции) и темы БК Опель Зафира и подгоняю под свой скетч??? Ну вы потом чуть-что подправите или напраите в нужню сторону ???
Ну и в целом, могу ли я сразу использовать ваши готовые блоки кода в текущем БК.
Две переменные подправил на свои( fuelConsumption=LHor и odometer=kmAge) еще надо переменную о колличесве топлива в баку исправить. Только kmAge(пробег) в вашем скетче типа float. Скетч скомпилился даже
float L100M = 0; //расход на 100 км измеренный за поездку
float L100 = 0; //мгновенный расход литров на 100км
/// fuelConsumption ////float LHor = 0; //мгновенный расход топлива литров в час
float L100SR = 0; //расход литров на 100км измеренный раз в интервал kmL
float L100SR_TFT = 0; // самый средний из расходов на 100км, он выводится на экран
int L100_Eeprom[11]= {10,10,10,10,10,10,10,10,10,10,10};
int FuelZamer[10]= {0}; // массив для измерения уровня (количества) топлива
int ZamerNumber = 0; // номер замера уровня (количества) топлива
int n_eeprom = 0; // текущий адрес ячейки еепром для записи расхода
//все что касается топлива
float Fuel = 0; //остаток топлива
float Fuel2 = 0; //остаток мгновенного топлива байт 16 , датчика в баке
int FuelIGN = 0; // количество топлвива в баке на момент включения зажигания
int Fuel_last = 0; // для формул
bool flagFuelIGN = 0; // флаг записан ли остаток топлива в момент вкл. зажигания
float FuelTrip = 0; // количество литров топлива, израсходованное за один цикл включения зажигания
//все что касается километража
// odometer //float kmAge = 0; //пробег, полученный со щитка приборов
int kmAgeIGN = 0; //пробег который был в момент включения зажигания
int kmAge_last = 0; // для формул
bool flagkmAgeIGN = 0; //флаг записан ли пробег в момент вкл. зажигания
float kmTrip = 0; //пробег за один цикл включения зажигания
int kmL = 10; // интервал, через который будет происходить обновление среднего расхода на 100км
int km = 0; // переменная для расчетов
int kmeeprom = 10; // интервал, через который будет происходить подсчет среднеарифмитического расхода L100SR_TFT
int kmTFT = 0; // переменная для расчетов периодического подсчета среднеарифмитического расхода топлива L100SR_TFT
int kmREFUELING = 0; // пробег до заправки на остатке топлива
setup():
//подсчет среднеарифметического усредненного расхода
for (int i = 0; i < 11; i++) L100_Eeprom [i]= EEPROM.read(i);
for (int i = 0; i < 11; i++) L100SR_TFT = L100SR_TFT + L100_Eeprom [i];
L100SR_TFT = (float)L100SR_TFT/110.0;
if (L100SR_TFT<0) L100SR_TFT = 0;
if (L100SR_TFT>99) L100SR_TFT = 99;
Ну и готовая функция Trip():
void Trip()
{
if (flagkmAgeIGN){
FuelTrip = FuelIGN - Fuel;
if (odometer>kmAgeIGN) kmTrip = odometer - kmAgeIGN;
if (odometer<kmAgeIGN) kmTrip = 2000 - (kmAgeIGN - odometer); // 2000 это через сколько км у тебя суточный пробег сбрасывается на ноль, поменяй если другое число
if (odometer==kmAgeIGN) kmTrip = 0;
//подсчет расхода на 100км за поездку
L100M = ((float)FuelTrip*100.00)/(float)kmTrip;
if (L100M<0) L100M = 0;
if (L100M>99) L100M = 99;
// ниже цикл считает среднеарифметический расход из еепром раз в пробег, указанный в переменной kmeeprom
if (kmTrip-kmTFT>kmeeprom) {kmTFT = kmTrip;
// тут считаем среднеарифметический усредненного расход из ячеек еепром
for (int i = 0; i < 11; i++) L100_Eeprom [i]= EEPROM.read(i);
for (int i = 0; i < 11; i++) L100SR_TFT = L100SR_TFT + L100_Eeprom [i];
L100SR_TFT = (float)L100SR_TFT/110.00;
if (L100SR_TFT<0) L100SR_TFT = 0;
if (L100SR_TFT>99) L100SR_TFT = 99;}
// ниже цикл считает расход топлива за пробег, указанный в переменной kmL, здесь же запись в ячейки еепром
if (kmTrip-km>kmL) {km=kmTrip;
L100SR = ((float)(Fuel_last-Fuel)*100.00)/(float)kmL; // расход/100км - обновляется раз в 10км, меняется км в int kmL = 10;
Fuel_last = Fuel; // сохранение параметров с последнего измерениея
if (L100SR<0) L100SR = 0;
if (L100SR>99) L100SR = 99;
//расчет остатка километров в баке, постоянно подстраеваемый под ваш стиль вождения
if (L100SR>0) kmREFUELING=((float)Fuel*100.0)/(float)L100SR; //если средний расход больше нуля, то расчитывать км в баке из него
else kmREFUELING=((float)Fuel*100.00)/(float)L100SR_TFT; //если ноль или меньше то расчитывать км в баке с устредненного расхода
//еще вариант расчета киломеров в баке от устредненного расхода L100SR_TFT, если он у вас уже вышел на стабильную цифру
//kmREFUELING=((float)Fuel*100.0)/(float)L100SR_TFT;
//еще вариант если вы знаете примерный средний расход за весь бак.
//kmREFUELING=((float)Fuel*100.0)/(float)6.7; //где 6.7 вош средний расход за бак
// тут записываем L100SR последовательно в одну из 11 ячеек еепром
//EEPROM.write (12,n_eeprom); // ЗДЕСЬ ВНИМАТЕЛЬНО. ЗАГРУЗИТЬ ПРОШИВКУ С ЭТОЙ СТРОКОЙ ОДИН РАЗ, ПОТОМ ЗАКОМЕНТИРОВАТЬ И ЕЩЁ РАЗ ЗАГРУЗИТЬ
n_eeprom = EEPROM.read (12); // в ячейке 12 хранится № текущей ячейки для записи расхода, чтобы где остановился при выкл питания, от туда и продолжил
EEPROM.write(n_eeprom, L100SR*10);
n_eeprom++; if (n_eeprom>10) n_eeprom=0;
EEPROM.write (12,n_eeprom); }}}
Приветствую единомышленники, тоже ковыряю скетч немца Александра, выше на меня уже давалась ссылка на Drive 2, добиться коннекта и получить от ЭБУ идентификационные данные я смог, но вот при запросе чтения информации с групп, у меня остановка, так как в ответе должно содержаться Е7 – ответ на запрос параметров группы датчиков, а у меня на этом месте ЭБУ выдаёт 0x02 и дальше блок неприменимых к формулам расчёта байтов. вообще всё как в этой теме https://www.blafusel.de/phpbb/viewtopic.php?f=15&t=2415, есть какие идеи по этому поводу?
Приветствую единомышленники, тоже ковыряю скетч немца Александра, выше на меня уже давалась ссылка на Drive 2, добиться коннекта и получить от ЭБУ идентификационные данные я смог, но вот при запросе чтения информации с групп, у меня остановка, так как в ответе должно содержаться Е7 – ответ на запрос параметров группы датчиков, а у меня на этом месте ЭБУ выдаёт 0x02 и дальше блок неприменимых к формулам расчёта байтов. вообще всё как в этой теме https://www.blafusel.de/phpbb/viewtopic.php?f=15&t=2415, есть какие идеи по этому поводу?
З.Ы.ЭБУ коннектится только на скорости 1200.
а диагностика типа VAGCOM или ВАСЯ диагност как себя ведёт? Если её нет, ответ дать будет непросто. Купите ваг ком адаптер на али, стоит недорого
Диагностику я приобрёл лет 10 назад, VAGCom читает группы как надо, тоже на скорости 1200. Лежит куча мозгов на столе, те что посвежее от AUDI A4B5, коннектится на ура на 9600, а также читает группы.
Возможно проблема в библиотеке NEWSofrwareSerial, сами разработчики предупреждают
** Будьте осторожны в использовании 300 и 1200 бод. Обработчик прерываний с такой скоростью становится настолько длинным, что прерывания таймера могут быть истощены, в результате чего millis () перестает работать во время приема.
int FuelIGN = 0; // количество топлива в баке на момент включения зажигания
эта переменная записывается один раз при старте ардуины (включении зажигания), далее ставится флаг, что она уже записана и при следующих итерациях цикла программы эта переменная больше уже не трогается.
Тем самым мы можем, считая разницу между этой переменной и остатком в баке, знать сколько на данный момент времени потреблено топлива. Это нужно для расчета среднего расхода топлива, расхода в литрах за поездку.
Также поступается и с километражом. Записывается на момент вкл зажигания и далее сравнивается с одометром, тем самым выясняется сколько проехали с момента включения зажигания.
Начинаю разбираться в логах, получается что VAG COM, что ардуино получают правильные параметры, но вот алгоритм не такой. Мой ЭБУ выдаёт 7 байт ,а не 15 и не разбивает группу на 4 параметра и результат по 4 параметрам группы считается как- то иначе. Запрсы правильные и там и там
Идём дальше выделил 4 группы, но как соотнести их с реальными данными? Думаю ответ кроется в 49-ти байтном блоке (его видно в логах), который выдаёт ЭБУ перед чтением групп??????????????
проснифьте обмен с помощью той программы, которую я вам давал, если ещё демка не закончилась. Интересно обмен данными будет посмотреть. и прочитайте сообщение #68 в вашей теме про ебер на кархелп.
Так как нагнетатель сейчас не работает, то проснифить в целом всю работу не получиться. Или вам интересно что там за обмен между прогами и котлом, то без вопросов могу заделать. Ну а потом и в полностью рабочем состоянии. Как думаете, два провода к-линии можно между собой соединить и потом данные читать?? Или на Эбер отдельную дуню повесить??
Линии к-лайн котла и основную автомобиля соединять нельзя! Если конечно это изначально не одна K-линия, что очень врядли. Если у вас будет ардуино мега, то нужно будет только два адаптера к-лайн (оба будут подсоединены в аппаратным Serial портам дуни). Если нано, то и ардуины две (каждый к-лайн адаптер к своей дуне).
Насчет сниффа, ну будет время снимите (пока демо версия программы сниффера не кончилась). Хочется посмотреть как идёт обмен и сравнить с тем постом из кархелп, если совпадёт - задача ещё упрощается. Опять всё сделали за нас)
По поводу нагнетателя меняйте щётки на моторчике, продувайте и смазывайте подшипники, бывает плюсом ещё и силовые ключи в блоке управления горят, теже симптомы будут.
Разобрался я с моторчиком нагнетателя. Разобрал пересмотрел всё, ничего существенного показывающего что он не рабочий-нет(счетки и подшипники в норме).
Единственное что могло быть причиной не нормальной работы - это чуть цеплявшееся пластмаса которая нагоняет воздух. приподнял её чуть выше, что бы вообще не цепляла и все. Эбер заработал ))) даю ссылки на диагностику двумя прогами. Забегая вперед скажу, что тест исполнителей эдитом не смог сделать, просит оригинальный шнур... общая получилась.
https://drive.google.com/open?id=1oFgPNkMWlUhq8XEZtPwQ2OPA0fSNYgY0
https://drive.google.com/open?id=1EaQ2ONQidD3ZRn0SCRIs5fMNbm30KrF9
Посмотрите, может что возможно тут подсмотреть
по обеим ссылкам никакого обмена толком нет, либо по какой то причине не просниффилось корректно. Там только повторяющиеся одни и те же байты. (справа то смотрите - там байты представлены в символах ASCII, сразу видно, что всё без конца повторяется).
Я когда выложил, то только тогда заметил, что там дублируется всё. Эх((((
Попробую ещё поколдовать над эдитом... вдруг, что получиться. В нете везде штудируют что для дигностики котлов нужен резистр подтяжки другой(560 Ом). Может мне в дуню залить тот самый первый скетч и посмотреть что выведет в терминал. Может все таки с подтяжкой надо поиграться. Есть какие мысли по этому поводу ??
Начал вот тестить дисплей и попробовал вывестиь стандартные примеры. Потом попытаюсь привезать к рабочему скетчу. Неудобство этого дисплея в том, что когда происходит затирание экрана(для того что бы вывести новую инфу) сопровождается морганием. старая инфа-дисплей моргнул-появилась новая. Буду еще искать примеры, так видел что выводят время и секунды не моргают.... надо менять только изменившееся данные.делать проверку.
Совет: чисти не весь ыкран, а только прямоугольник вывода
Если прямоугольником затирать все равно будет мерцать, т.к. периодичность вывода на экран для БК нужна очень частая для плавности показаний. В библиотеках на tft экраны обычно это уже отработано специальной функцией. Типа при печати переменной задаешь также сколько символов она будет занимать и библиотека сама затирает старые символы.
P.s. читайте тему про опель, там все это проходили.
Я вот не пользуюся стандартными библиотеками, поэтому не очень представляю их возможности.
Но нормальная библиотека должне поддерживать управление "стилем" вывода символа, т.е. выводить его с "прозрачным" фоном либо заливать фон при выводе определенным цветом. Т.е в настройках указывается два цвета: которым собственно рисуется сам символ и которым заливаектся все знакоместо под ним.
Вообще-то это стандартная практика.
Боле того, в Windows, например, именно режим с "непрозрачным" фоном является режимом по умолчанию.
Ну, что на Ардуино режимио по умолчанию является "прозрачный" фон, я уже понял. А вот тема мерцания всплывает настолько часто, что возникает естественный вопрос: действительно ли стандартные библиотеки Ардуино настолько кривы, что не поддерживают наиболее востребованные режимы, или просто люди не умеют пользоваться библиотеками?
PS. На случай кривости библиотек можно, естественно, самому написать нужную функцию вывода символа. Но если это не по зубам, можно чистить не все поле вывода целиком, а посимвольно: почистил знакоместо - вывел очередной символ, почистил следующее знакоместо - вывел следующий.
скорее последнее. Вот, например, выдержка из одной библиотеки:
Вообще-то это стандартная практика......
.....можно чистить не все поле вывода целиком, а посимвольно: почистил знакоместо - вывел очередной символ, почистил следующее знакоместо - вывел следующий.
Я думаю речь была не про фон, а про "старые" нули. Если было например число 1000, а потом стало 100, один ноль уже протух, его бы надо удалить.
Попробовал пока затирать фон, действительно осталось маленькое мерцание, но уже не всего дисплея, а той только части где идет вывод.
пробуй как #161 не будет мерцания
что-то я совсем запутался с подключением и инициализации с этой (UTFT.h) библиотекой. Везде всё по разному. Даже пример не могу проверить. У меня дисплей ST7735.
Пытался руководствоваться
http://wiki.iarduino.ru/page/rabota-s-cvetnym-graficheskim-displууь.
и файлом UTFT.cpp из библиотеки
На библиотеке <TFT_ILI9163C.h> , подключал как на красной картинке справа
Получилось вот так:
UTFT myGLCD(ST7735, 11, 13, 10, 8,9);
myGLCD.printNumI(1250,0,0); - действительно то что надо )))
Буду скоро проверять в боевых условиях))
Вот простой примерчик, который получился:
Вот уже получилось вывести кое-какие данные на дисплей. Еще один шаг сперед) ))) "Снег" на экране от того, что закоментирована функция стирания всей информации с дисплея myGLCD.clrScr(); Потом надо будет запустить её один раз при включении, а то получаются опять "как бы мерцания". MaksVV, прошу вас помощи в оптимизации скетча и допиливанию других возможностей. Код еле-еле влез в UNO. То, что закоментировано с несколькими звездочками(***)-коментировал я сам (мож, что и лишнее)))).. остальные коментарии кода Ваши и Александра. Надо бы всё исключить, что связано с прошлым дисплеем, который от изначально проекта. И еще... лень было тащить ноут в машину, запитал дуни от зарядки телефона через прикуриватель, дуня повисала на 7-10 секунде. Перезапуск помогал, но не решил я рисковать больше 3-х раз... дабы не спалить её.
предлагаю сначала получить нормально все переменные от эбу., которые вам нужно,а уже потом заморачиваться с экраном.
myGLCD.clrScr(); в setup() вставить
Начал вот разбираться с параметрами. Что-то я совсем запутался.....
пробовал менять переменную (во втором скетче)uint8_t currPage = 1; на значение 2. выводит одни параметры, когда верну 1 -другие. Добавил пару строчек в
А что конкретно не понятно то? Когда currPage=1 идет подключение к щитку приборов и вытягивается 3 переменных, когда currPage=2, соответственно подключение к ECM , вытягивается 4 переменные, все по скетчу, все работает.
переменная по нажатию кнопки переключает экраны, ну и естественно переключается между блоками. Действительно, всё просто. Это ж надо так затупить )))) Мне порой нравится ваш подход в помощи, где посложнеее сами код подправите, где есть повод поразмышлять, то направите в нужную сторону)) Спасибо ))
С двух блоков одновременно не даёт читать инфу ((
Пробовал вывести все в currPage, ничего не помогло.
Потом пробовал вот так(добавил currAddr2, currPage2):
Результат тот же - вообще глухо
Если это действительно так, то дела идут не очень хорошо(( скорее всего придется все тянуть только с приборки....
посмотрите в вагкоме какие параметры вам нужны из приборки. Желательно выбрать те, которые медленно меняются. Алгоритм будет такой - основная связь будет идти с блоком двигателя, и иногда, периодически, будет прерываться на связь с приборкой. Например раз в 5 сек или ещё реже (в этот момент отображение параметров от блока ДВС на экране будет ненадолго замирать)
на опеле, когда мы БК делали было проще - приборка висела на отдельной к-линии (отдельный контакт в обд разъеме). Мы взяли второй к-лайн адаптер и связь сделали одновременно и с приборкой и с ECM.
Так может попробовать тоже так сделать. Надо только в фишке приборки найти нужный провод. Теоретически должна приборка опрашиваться и сама.
ну как вариант, да, откусить приборку от к-линии обд разъема и подключиться к ней локально другим к-лайн адаптером.
Разобрался с приборкой, получил некоторые данные. l/h -величина не меняемая. Температура масла всегда на 78, наверное не работает датчик.Посещает мысль сделать тоже кнопку для переключения между блоками..будет тип 3-ри экрана. 1-Движок 2-Приборка 3-Общий (как вы и предлогали, делать запросы по несколько секунд к одному, потом к второму блоку). Ну в принципе мне бы хватило того, что есть в приборке, но еще хочется контролировать напругу аккума(а она только в блоке двигателе) или может какой вариант есть узнать напругу через дуню. Всё так же нуждаюсь в вашей помощи с расчетом расхода топлива и остатка хода.
если будет известно цикловое наполнение топливом (ну или часовой расход) - эти параметры только в ECM, то можно рассчитать, кроме средего, также и мгновенный расход топлива в час и на 100км. а также расход за поездку.
Все переменные готовы. В том числе и расход л/ч. Может целесообразно его сделать типом float, для дальнейшего более точно расчета ?
да, можно float
Ок, понял. Значит идем дальше... беру всё что мне нужно(переменные, функции) и темы БК Опель Зафира и подгоняю под свой скетч??? Ну вы потом чуть-что подправите или напраите в нужню сторону ???
Ну и в целом, могу ли я сразу использовать ваши готовые блоки кода в текущем БК.
Две переменные подправил на свои( fuelConsumption=LHor и odometer=kmAge) еще надо переменную о колличесве топлива в баку исправить. Только kmAge(пробег) в вашем скетче типа float. Скетч скомпилился даже
setup():
Ну и готовая функция Trip():
Приветствую единомышленники, тоже ковыряю скетч немца Александра, выше на меня уже давалась ссылка на Drive 2, добиться коннекта и получить от ЭБУ идентификационные данные я смог, но вот при запросе чтения информации с групп, у меня остановка, так как в ответе должно содержаться Е7 – ответ на запрос параметров группы датчиков, а у меня на этом месте ЭБУ выдаёт 0x02 и дальше блок неприменимых к формулам расчёта байтов. вообще всё как в этой теме https://www.blafusel.de/phpbb/viewtopic.php?f=15&t=2415, есть какие идеи по этому поводу?
З.Ы.ЭБУ коннектится только на скорости 1200.
День добрый. Вам надо дождаться ответа MaksVV. У его опыт большой и шарит в этой тематике больше )))
Приветствую единомышленники, тоже ковыряю скетч немца Александра, выше на меня уже давалась ссылка на Drive 2, добиться коннекта и получить от ЭБУ идентификационные данные я смог, но вот при запросе чтения информации с групп, у меня остановка, так как в ответе должно содержаться Е7 – ответ на запрос параметров группы датчиков, а у меня на этом месте ЭБУ выдаёт 0x02 и дальше блок неприменимых к формулам расчёта байтов. вообще всё как в этой теме https://www.blafusel.de/phpbb/viewtopic.php?f=15&t=2415, есть какие идеи по этому поводу?
З.Ы.ЭБУ коннектится только на скорости 1200.
а диагностика типа VAGCOM или ВАСЯ диагност как себя ведёт? Если её нет, ответ дать будет непросто. Купите ваг ком адаптер на али, стоит недорого
taha17 , вы научились данные с блока нормально получать? Нужен пробег, остаток топлива, для функции Trip().
Диагностику я приобрёл лет 10 назад, VAGCom читает группы как надо, тоже на скорости 1200. Лежит куча мозгов на столе, те что посвежее от AUDI A4B5, коннектится на ура на 9600, а также читает группы.
Возможно проблема в библиотеке NEWSofrwareSerial, сами разработчики предупреждают
** Будьте осторожны в использовании 300 и 1200 бод. Обработчик прерываний с такой скоростью становится настолько длинным, что прерывания таймера могут быть истощены, в результате чего millis () перестает работать во время приема.
http://arduiniana.org/libraries/newsoftserial/
сделайте сниф обмена как в этой теме. посмотрим. Дак повесьте на хард
Хорошо, после выходных сделаю
В реализации поочеродного обращения к двум блокам нужна ваша помощь. Есть еще вопрос по переменным связанных с топливом:
float Fuel2 = 0; //остаток мгновенного топлива байт 16 , датчика в баке.
наверное не нужна вовсе. т.к. не используется
int FuelIGN = 0; // количество топлива в баке на момент включения зажигания
этот момент не совсем понятен. Запись в переменную идет как только подалось питание на ардуино и установилась связь с приборкой ???
По переменным - всё готово. Все данные получены. Пробег(odometer),остаток топлива(fuelLevel), Потребление топлива л\ч (fuelConsumption)
Переменные в функции Trip(), заменил на свои.
эта переменная записывается один раз при старте ардуины (включении зажигания), далее ставится флаг, что она уже записана и при следующих итерациях цикла программы эта переменная больше уже не трогается.
Тем самым мы можем, считая разницу между этой переменной и остатком в баке, знать сколько на данный момент времени потреблено топлива. Это нужно для расчета среднего расхода топлива, расхода в литрах за поездку.
Также поступается и с километражом. Записывается на момент вкл зажигания и далее сравнивается с одометром, тем самым выясняется сколько проехали с момента включения зажигания.
Вот логи с ардуины
А вот логи с программы Monoscan отлично читает группы измерений
https://cloud.mail.ru/public/DtCW/kv6K6Rc5X тут он читаем (подсвечиваются ключевые)
не понятно, нужно сделать ещё сниф к-лайн адаптером , тут выше описывалось.
PS Ссылка не работает
Ок, сделаю.
ССылка работает, скопировать и в адресную строку
Лог VAGCOM K-Line адаптер (запрос 1 группы) Скорость соединения 1200
Начинаю разбираться в логах, получается что VAG COM, что ардуино получают правильные параметры, но вот алгоритм не такой. Мой ЭБУ выдаёт 7 байт ,а не 15 и не разбивает группу на 4 параметра и результат по 4 параметрам группы считается как- то иначе. Запрсы правильные и там и там
Идём дальше выделил 4 группы, но как соотнести их с реальными данными? Думаю ответ кроется в 49-ти байтном блоке (его видно в логах), который выдаёт ЭБУ перед чтением групп??????????????
Попробывал разложить блок из 49 байт, по принципу 1-формула 2 слово "а" 3 слово" b", получается ерунда, групп всего 70, тут же всплывает группа 160
блок из 49 байт только один раз проскакивает? И какие группы выбраны при сниффе.