Вот код
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
#include <SoftwareSerial.h>
#include <utf8rus2.h>
SoftwareSerial K_LINE(2, 3); // RX, TX
#define TIMER_DELAY \
Delay = 0; \
timerdelay = curmillis // включение этого таймера
#define TFT_CS 10
#define TFT_RST 8
#define TFT_DC 9
#define SERIAL_BAUDRATE 10400
const byte PCMaddress = 0x7A; // адрес эбу
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST); // Инициализация объекта для работы с дисплеем
byte header = 0; // состояние заголовка
byte message_size = 0; // размер тела принимаемого сообщения, кол-во байт
byte j = 2; // инкремент
byte n = 2;
const byte bufsize = 100; // размер буфера принятого сообщения
byte buf[bufsize] = { 0 }; // буфер принятого сообщения
byte checksum = 0; // контрольная сумма входящего сообщения
uint32_t curmillis = 0; // снимок системного времени
byte delaybyte_TX = 0; // задержка между байтами отправляемого сообщения
byte waitbyte_RX = 1; // задержка, мс для успевания заполнения буфера RX (подрегулировать в зависимости от уровня жизнидеятельности на Марсе)
uint32_t timerdelay = 0; // таймер ожидания байт (для успевания заполнения буфера УАРТ)
bool Delay = 0; // таймер ожидания байт (для успевания заполнения буфера УАРТ)
#define TIMER_DELAY \
Delay = 0; \
timerdelay = curmillis // включение этого таймера
uint32_t prevRESETheader = 0; // таймер сброса заголовка если в момент приёма сообщения данные оборвались
bool RESETheader_timer = 0; // таймер сброса заголовка если в момент приёма сообщения данные оборвались
uint32_t prevtimeRequest = 0;
uint16_t periodRequest = 1000; // периодичность запроса параметров ЭБУ, мс
int Init = 0;
uint32_t prevInit = 0;
String VIN="";
int Speed_engine;
int Vitesse;
//**************************** команды, посылаемые на ЭБУ
byte StartSession[] = { 0x81 }; // команда на старт диагностики (может также быть 82)
byte StopSession[] = { 0x82 }; // команда на стоп диагностики
//byte DataRequest[] = { 0x21, 0x80 }; // команда на запрос параметров
byte DataRequest[] = { 0x21, 0xAA }; // команда на запрос параметров
byte VINRequest[] = { 0x21, 0x81 }; // команда на запрос параметров
//byte DataRequest[] = { 0x21, 0x01 }; // команда на запрос параметров
//****************************
void lcdPrint(int x, int y, int c1, int c2, String s, int width = 0, int f = 0){
String ss;
tft.setCursor(x,y);
if (width == 0) {
width = s.length();
}
while (ss.length() < width-s.length()) ss += " ";
ss += s;
if (c2 == 0){
tft.setTextColor(c1);
}
else{
tft.setTextColor(c1, c2);
}
tft.print(ss);
}
String str_buf_word(byte buf[], int n, int size){
byte word[size] = { 0 }; // Очистка слова перед формированием
for (int i = n; i < size; i++) {
word[i-n] = buf[i];
}
return String((char*)word);;
}
void setup() {
Serial.begin(SERIAL_BAUDRATE); // настойки монитора порта отладки
K_LINE.begin(SERIAL_BAUDRATE); // настройки шины к-лайн
delay(2000);
tft.initR(INITR_BLACKTAB); // Инициализация дисплея
tft.fillScreen(ST7735_BLACK); // Очистка экрана перед выводом новых данных
tft.setTextColor(ST7735_WHITE); // Установка цвета текста
tft.setRotation(3);
tft.setTextSize(1,2);
lcdPrint(0, 20, ST7735_WHITE, ST77XX_RED, String("-----------------"));
tft.setTextSize(2);
lcdPrint(0, 0, ST7735_WHITE, ST77XX_RED, utf8rus2(" Связь с ЭБУ "));
lcdPrint(0, 50, ST7735_WHITE, ST77XX_RED, utf8rus2("Обороты"));
lcdPrint(0, 70, ST7735_BLACK, ST77XX_GREEN, String("------"), 6);
lcdPrint(85, 70, ST7735_BLACK, ST77XX_GREEN, utf8rus2("об/мин"));
lcdPrint(0, 90, ST7735_WHITE, ST77XX_RED, utf8rus2("Скорость"));
lcdPrint(0, 110, ST7735_BLACK, ST77XX_GREEN, String("------"), 6);
lcdPrint(85, 110, ST7735_BLACK, ST77XX_GREEN, utf8rus2("км/ч"));
}
void loop() {
curmillis = millis(); // снимок системного времени
K_LINEread(); // читаем шину к-лайн
if (curmillis - prevtimeRequest > periodRequest) { // периодически делаем запрос параметров
if (Init) {
lcdPrint(0, 0, ST7735_BLACK, ST77XX_GREEN, utf8rus2(" Связь с ЭБУ "));
if (Init == 1) SendMessage(VINRequest, sizeof(VINRequest));
else SendMessage(DataRequest, sizeof(DataRequest));
}else SendMessage(StartSession, sizeof(StartSession));
prevtimeRequest = curmillis;
}
if (curmillis - prevInit > 10000) {
SendMessage(StopSession, sizeof(StopSession));
lcdPrint(0, 0, ST7735_WHITE, ST77XX_RED, utf8rus2(" Связь с ЭБУ "));
tft.setTextSize(1,2);
lcdPrint(0, 20, ST7735_WHITE, ST77XX_RED, String("-----------------"));
tft.setTextSize(2);
lcdPrint(0, 110, ST7735_BLACK, ST77XX_GREEN, String("------"), 6);
lcdPrint(0, 70, ST7735_BLACK, ST77XX_GREEN, String("------"), 6);
Init = 0;
prevInit = curmillis;
} // периодически делаем сброс инита, если ЭБУ не отвечает
}
void SendMessage(const byte *command, const size_t size) {
const byte siZe = size + 4;
byte Mes[siZe];
byte Checksum = 0;
for (byte i = 0; i < siZe; i++) {
if (i == 0) {
Mes[i] = size;
bitWrite(Mes[i], 7, 1);
}
if (i == 1) Mes[i] = PCMaddress;
if (i == 2) Mes[i] = 0xF1;
if (i == 3) {
for (byte t = 0; t < size; t++) {
Mes[i] = command[t];
Checksum += Mes[i];
K_LINE.write(Mes[i]);
//Serial.write(Mes[i]);
i++;
}
}
if (i != siZe - 1) Checksum += Mes[i];
else Mes[i] = Checksum;
K_LINE.write(Mes[i]);
//Serial.write(Mes[i]);
}
}
void K_LINEread() {
if (K_LINE.available()) {
//if (Serial.available()) {
// первый старт байт
if (header == 0 && Delay) {
TIMER_DELAY;
buf[0] = K_LINE.read();
//buf[0] = Serial.read();
if (!bitRead(buf[0], 6) && bitRead(buf[0], 7)) {
header = 1;
RESETheader_timer = 1;
prevRESETheader = curmillis;
}
}
// второй старт байт
if (header == 1 && Delay) {
TIMER_DELAY;
buf[1] = K_LINE.read();
//buf[1] = Serial.read();
if (buf[1] == 0xF1) {
header = 2;
} else {
header = 0;
RESETheader_timer = 0;
}
}
// третий старт байт
if (header == 2 && Delay) {
TIMER_DELAY;
buf[2] = K_LINE.read();
//buf[2] = Serial.read();
if (buf[2] == PCMaddress) {
message_size = buf[0];
if (buf[0] != 0x80) {
header = 4;
message_size &= ~0x80;
j = 3;
n = 3;
} else {
header = 3;
j = 4;
n = 4;
}
if (message_size > bufsize) message_size = bufsize;
checksum = 0;
} else {
header = 0;
RESETheader_timer = 0;
}
}
// если размер сообщения указан в дополнительном байте (нулевой байт 0x80) читаем этот дополнительный байт:
if (header == 3 && Delay) {
TIMER_DELAY;
buf[3] = K_LINE.read();
//buf[3] = Serial.read();
message_size = buf[3];
if (message_size > bufsize) message_size = bufsize;
checksum = 0;
header = 4;
}
// пишем тело сообщения
if (header == 4 && Delay && j < message_size + n + 1) {
buf[j] = K_LINE.read();
//buf[j] = Serial.read();
j++;
if (j < message_size + n) checksum ++; // подсчёт КС
if (j == message_size + n) header = 5;
TIMER_DELAY;
}
} // end of K_LINE.available()
// сообщение приняли, действуем
if (header == 5) {
checksum ++;
TIMER_DELAY;
Serial.print(F("Receive from PCM: "));
for (byte i = 0; i < message_size + n + 1; i++) {
if (buf[i] <= 0x0F) Serial.print(F("0"));
Serial.print(buf[i], HEX);
Serial.print(" ");
} // Отладка в монитор порта
Serial.println();
// если контрольная сумма верна:
if (message_size == checksum) {
prevInit = curmillis; // сбрасываем таймер сброса инита, если получили хоть какое-то сообщение от ЭБУ
if (buf[n] == 0xC1) Init = 1; // если пришёл ответ на запрос инита, делаем инит прошёл успешно
// ниже если получили длинный ответ от ЭБУ с параметрами парсим его, я взял только температуру ДВС
else if (buf[n] == 0x61 && buf[n + 1] == VINRequest[1]) {
VIN = str_buf_word(buf, n+2, message_size + n);
tft.setTextSize(1,2);
lcdPrint(0, 20, ST7735_WHITE, ST77XX_RED, String(VIN));
tft.setTextSize(2);
Init = 2;
}
else if (buf[n] == 0x61 && buf[n + 1] == DataRequest[1]) {
Speed_engine = 256 * buf[n + 14] + buf[n + 15];
Vitesse = (256 * buf[n + 16] + buf[n + 17])/100.0;
lcdPrint(0, 70, ST7735_BLACK, ST77XX_GREEN, String(Speed_engine), 6);
lcdPrint(0, 110, ST7735_BLACK, ST77XX_GREEN, String(Vitesse), 6);
}
// ТУТ ЧТО НИБУДЬ ДЕЛАЕМ КОГДА ПОЛУЧИЛИ СООБЩЕНИЕ ОТ ЭБУ
}
// если контрольная сумма не совпала:
//else Serial.println("CRC fail!!!" );
message_size = 0;
header = 0;
RESETheader_timer = 0;
j = 3;
checksum = 0;
}
// таймер ожидания байт (для успевания появления данных в буфере UART)
if (!Delay && curmillis - timerdelay > waitbyte_RX) Delay = 1;
// таймер сброса заголовка если данные оборвались во время приёма заголовка
if (RESETheader_timer && curmillis - prevRESETheader > 500) {
RESETheader_timer = 0;
header = 0;
}
}
MMM:
и полную схему
Если подключить по такой схеме, то в Serial Port Monitor видно что ардуина посылает команды
А если вот так подключить, то команды не посылаются