Проблема с чтением данных из 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.
@gfd2, 👍4
1 ответ
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).
- GSM-модуль IOT-GA6 Arduino + ошибка CME 58
- Разница между массивом char и массивом unsigned char
- Arduino UNO + Ethernet Shield + ЖК-дисплей + RFID, но RFID не работает
- Модуль HC-05 не получает команд и не спаривается
- Firmata: как установить определенный PIN на высокий уровень при загрузке?
- Как погасить светодиод за определенное время с помощью FastLED
- Arduino wrap или подкласс print() для работы с несколькими Serial
- Считывание данных нескольких датчиков из текстового файла, расположенного на SD-карте в Arduino/ESP32