Проблема с чтением данных из ELM327

Идея заключалась в создании устройства Bluetooth на базе Arduino для считывания данных с машины (ELM327 v2.1) с использованием модуля Bluetooth HC-05.

В этом коде модуль bluetooth переключается в режим MASTER и подключается к ELM327, используя его MAC-адрес. Ответы модуля в коде находятся в комментариях.

#include <SoftwareSerial.h>
SoftwareSerial bluetoothSerial(4, 5);

void setup() {
  Serial.begin(9600);
  Serial.print("READY");
  bluetoothSerial.begin(38400);
  delay(1000);
  getSetAtCommand("AT");                         //ОК
  getSetAtCommand("AT+CMODE=0");                 //ОК
  getSetAtCommand("AT+PSWD=1234");               //ОК
  getSetAtCommand("AT+ROLE=1");                  //ОК
  getSetAtCommand("AT+BIND=0010,CC,4F3603");     //ОК
  getSetAtCommand("AT+LINK=0010,CC,4F3603");     //ОК
  delay(1000);
  getSetAtCommand("AT+STATE?");  // ОК: ПОДКЛЮЧЕНО
  delay(1000);
  getSetAtCommand("ATZ");      //нет ответа, буфер пуст
  getSetAtCommand("AT015B");//нет ответа, буфер пуст
  getSetAtCommand("015B");      //нет ответа, буфер пуст
  getSetAtCommand("ATRV");   //нет ответа, буфер пуст
  getSetAtCommand("0105");    //нет ответа, буфер пуст
  getSetAtCommand("at i");   //ответа нет, буфер пуст
  getSetAtCommand("at rv");   //ответа нет, буфер пуст
  getSetAtCommand("ati");    //нет ответа, буфер пуст
  getSetAtCommand("atrv");   //нет ответа, буфер пуст
}

void loop() {
}

void getSetAtCommand(String command) {
  Serial.println(command);
  String added_command = command + "\r\n";
  bluetoothSerial.print(added_command);
  delay(500);
  while (bluetoothSerial.available()) {
    Serial.write(bluetoothSerial.read());
  }
}

Поскольку State возвращает CONNECTED, я предполагаю, что он подключен к ELM.

На команду AT+PAIR=0010,CC,4F3603,20\r\n модуль не отвечает. Модуль также не отвечает на такие команды как ATZ\r\n, AT015B\r\n, 015B\r\n, ATRV\r\n, 0105\r\n, at i\r\n, at rv\r\n, ati\r\n, atrv\r\n. Иногда ответом будет ERROR[0], как я понимаю, это означает, что такой команды нет.

Мне кажется, что эти команды вообще не доходят до ELM. В чем может быть проблема?

Сам ELM327 работает, подключается к телефону без проблем и показывает данные.

Пробовал через симулятор на ноутбуке, подключенная модель bluetooth отображается в устройствах bluetooth на ноутбуке и также не работает как с ELM.

, 👍4


1 ответ


2

ELM закрылся, но в качестве любезности сохранил свой сайт документации. Вот ссылка на последнюю опубликованную версию, V2.3 в 2020 году -

https://www.elmelectronics.com/DSheets/ELM327DSL.pdf

Вот что, по-моему, говорит доктор:

  • Механизм обмена внешними данными ELM использует 4-битные шестнадцатеричные «полубайты» с 2 полезными полубайтами в каждом 8-битном «байте», которые могут быть «дополнены» начальным пустым старшим полубайтом «0000», когда выводится только один 4-битный младший полубайт.

  • Директивы ELM327 представляют собой текстовые символы, начинающиеся с «AT» (или «at», они не чувствительны к регистру); в их первом старшем полубайте всегда установлен как минимум 1 бит. Полубайты запроса OBDII начинаются с одной шестнадцатеричной цифры 0, в которой никогда не установлен ни один из старших битов полубайта, что позволяет ELM327 легко различать директивы и запросы OBDII, проверяя только первый байт любого нового сообщения, отправленного ему.

  • Все обмены завершаются возвратом каретки, который представлен как код ASCII 13; 0xD или символ C '\r'. Но строки Arduino (& C) ожидают 'nul terminator = '\0'. Будьте осторожны, чтобы использовать команды, которые правильно завершают строки.

  • Период тайм-аута используется при ожидании ответа от OBDII. После получения новый период тайм-аута применяется в случае дополнительных ответов (до '\r'). Только после того, как тайм-аут действительно наступит, ELM327 передаст данные и подготовится к принятию новой директивы или запроса. Он часто будет выполнять некоторые внутренние действия перед отправкой конца ответа '\r' или приглашения о готовности '>'. [Период тайм-аута адаптивен и будет автоматически сокращен до максимально короткого безопасного времени] [Отправка одного полубайтового значения «count» в конце запроса возвращает ответ, как только получает необходимое количество байтов данных от OBDII]

  • ELM327 использует '>' как символ готовности или приглашения. Не пытайтесь установить связь, пока не будет получено приглашение.

  • Неполные или не завершенные команды все равно будут отправлены с ELM327 на OBDII после тайм-аута. ELM327 вернет один '?', чтобы указать, что директива или запрос были искажены, не заканчивались на '\r' или не были возвращены никакие данные.

  • Запросы OBDII и возврат данных определяются как байты. Обмен ELM327 выполняется через полубайты. UART используют символьные байты. Поэтому запросы OBDII необходимо преобразовать из байтовой формы (показанной в документации) в заполненные полубайты для отправки/возврата в/из ELM327.

  • Запросы ELM327 начинаются с 2-х полубайтового значения режима от 0 1 до 0 B, затем с 4-8-ми полубайтового идентификатора параметра (PID) и, наконец, с 2-х полубайтового представления '\r' (0 D).

  • Ответы ELM327 добавляют 0x40 к первому полубайту режима, затем передают измененный байт режима, PID и возвращаемые данные, завершающиеся символом '\r'. Этот поток необработанных данных необходимо повторно собрать в отдельные байты перед интерпретацией.

  • При желании эхо Mode & PID можно отключить с помощью директивы 'AT E0 \r'. Пробелы необязательны, 'ATE0\r' работает нормально. [Некоторые старые устройства ELM327 могут иногда возвращать символ '\0' = null, их следует удалить из потока необработанных данных]

  • Отправка голого '\r' в ELM327 интерпретируется как 'повтор' последней директивы или запроса. Самый быстрый метод сбора повторных данных требует запроса с ответным полубайтом длины данных, отправленным первым, а затем нового '\r', как только появится приглашение.

Обмен данными OBDII -

  • Заголовки, режим, PID и контрольные суммы должны быть созданы/собраны внешним устройством, а затем переданы в систему OBDII с использованием любого протокола, выбранного производителем транспортного средства (из типов, определенных в спецификациях OBDII). Ответы должны быть проверены (с использованием возвращаемого режима, PID и возвращаемой контрольной суммы); ELM327 выполняет все это предварительное и последующее кодирование и проверку данных внутри. Если вы решите сделать это в своем собственном коде, то «удачи».

  • Возвращаемые данные могут быть закодированы битами, отдельными байтами или строкой значений байтов. Некоторые значения смещены для расширения диапазона данных с целью включения отрицательной части в пределах одного беззнакового байта (от 0 до 255).

  • Байты OBDII имеют прямой порядок байтов, и при объединении в слова данных целые слова данных также имеют прямой порядок байтов.

  • Максимальный объем возвращаемых «стандартных» данных составляет 41 байт для различного прошедшего времени, но большинство из них намного, намного короче.

  • Производители транспортных средств могут возвращать данные любой желаемой длины, поэтому следите за символами '>' в ELM327.

  • Данные могут быть возвращены в нескольких блоках. Например, 17-байтовый идентификационный номер транспортного средства (VIN) возвращается как 5 из 4-байтовых слов. Режим запроса 09 PID 02 возвращает «0 1 2 3», «4 5 6 7», «8 9 10 11», «12 13 14 15», «16 xx x» без «\r» между ними, только один в конце; это должно быть собрано в «0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 xx x».

Пример запроса ELM327 - RPM имеет режим 01, PID 12. Преобразование из десятичной системы в шестнадцатеричную - 01, 0C. Дополнение из 4 полубайтов до 4 байтов - 00 01 00 0C. Добавьте '\r'. Подождите '>', затем отправьте. Подождите, пока ответ полностью не придет ('\r' получен).

Пример ответа ELM327 - 40 01 00 0C 1A F8 '\r'. Отбросьте измененный запрос эха и заголовок (если оставлены On), затем преобразуйте возвращенный шестнадцатеричный код в десятичное значение 1A F8 -> 26 248, соберите 2-байтовое слово (26 * 256) + 248 = 6904. Разделите /4, чтобы преобразовать в 1726 об/мин. Перед отправкой нового запроса дождитесь получения '>'. Обратите внимание на порядок байтов little-endian — сначала отправляется little end 248, затем big end (26 * 256).

,