multidisplay в авто (Arduino vs Renault ECU)

red
Offline
Зарегистрирован: 19.12.2011

Приветствую уважаемое сообщество!

Опишу сразу свой уровень: когда-то в школе еще держал в руках паяльник и писал на Паскале. :) Всегда считал, что микроконтроллеры - удел спецов. Но поизучав неделю инфу про Ардуино, пришёл к выводу, что решение поставленной мной задачи мне же по силам. Конечно, с вашей помощью.

 

Итак, задача: получить в кокпите на LCD дисплее данные с ЭБУ автомобиля. По результату должно получиться что-то вроде этого

code.google.com/p/multidisplay/

Можно выделить два этапа.

1. Получить посылку с диагностического разъёма. Она состоит из 43 байт. Вот пример.

FF 00 72 04 92 26 5F 43 D3 CE B6 41 32 04 00 10 76 02 00 00 00 40 0A 00 00 00 00 00 00 7A 34 19 FF 00 72 04 92 26 60 44 D1 CE 20

2. Выбрать нужные байты, пересчитать значения по формуле и вывести на LCD (конечно, в DEC).

К примеру 9-й байт - это напряжение в бортовой сети. Передаётся с шагом в 0,0312 + 8 Вольт.

D3 (HEX) => 211 (DEC)

211*0.0312+8 = 14.6 Вольт (с округлением)

 

Из железа выбираю между Duemilanove и Mega на ATmega1280. Именно эти потому, что они имеют 232-ю микросхему. Почему нужна именно она - напишу ниже.

Кроме того нужен LCD 1602 и часы на базе 1307, чтобы использовать I2C, а не последовательный порт.

 

Итак, первая задача - получить посылку UART.

Сейчас я использую для этой цели ноут и USB адаптер, собранный на 232-й микросхеме.

Вот его схема.

Собственно, кроме 232-й микросхемы присутствуют только 6 деталей, обведённых прямоугольником в правом верхнем углу. Diag9 и Diag2 - это соответственно + и масса с диагностического разъёма на ЭБУ.

 

И вот у меня созрел ПЕРВЫЙ ВОПРОС к гуру электроники: правильно ли я понимаю, что вместо 232 миросхемы можно сразу подключать Arduino(соответственно Rx, +5В и земля)?

Mastino
Offline
Зарегистрирован: 03.12.2011

Какого года машина? у меня самого laguna..:), так как мне известно на всех сериях с 2001 был бортовой компьютер который выдает такую информацию.

red
Offline
Зарегистрирован: 19.12.2011

Не, у меня янгтаймер - 1988 :)

Mastino
Offline
Зарегистрирован: 03.12.2011

red пишет:

правильно ли я понимаю, что вместо 232 миросхемы можно сразу подключать Arduino(соответственно Rx, +5В и земля)?

Я не гуру.. но для начала я бы попробовал бы Arduino подключать не вместо 232 миросхемы, а к 232 миросхемe и посмотреть что пишет serial..

red
Offline
Зарегистрирован: 19.12.2011

Хочется максимально простую схему. У Ардуино и так на борту есть 232, и если еще одну подключать - это и сложнее, и дороже выходит.

step962
Offline
Зарегистрирован: 23.05.2011

 На приведенной схеме, как я понимаю, ноут слева, а машинко справа? Ну, тогда вам действительно для приема данных достаточно кинуть выход машинки на RXD-пин ардуины (D0). Только одно непонятно - почему справа один провод (только прием диагностической информации)? Диагностическая колодка постоянно гонит этот пакет и неспособна принимать команды от тестера? Едва ли. Но в таком случае и TXD-пин (D1) надо бы подключать. И, соответственно, команды управления (коды) осваивать. 

 ЗЫ: Насчет одного провода - поторопился. Там ведь, видимо, 1/2-проводная шина реализована (что-то вроде CAN/I2C/1-Wire)?

ЗЗЫ: А в диагностическом канале авто уровни какие? Не 12 В часом? В таком случае необходим преобразователь уровней с 12 В на 5. 

76region
Offline
Зарегистрирован: 08.07.2011

вот Q1 их и преобразовывает :)

76region
Offline
Зарегистрирован: 08.07.2011

Это обычный K-Line я правильно понимаю?

 

red
Offline
Зарегистрирован: 19.12.2011

step962 пишет:

Диагностическая колодка постоянно гонит этот пакет и неспособна принимать команды от тестера?

Да, именно так.

step962 пишет:

ЗЗЫ: А в диагностическом канале авто уровни какие? Не 12 В часом?

Нет, там очень маленькое напряжение - порядка 0,8 В.

76region пишет:

Это обычный K-Line я правильно понимаю?

Какой-то он необычный. :)

По-сути схемка, которая обведена, при подаче напряжения с диагностического разъёма пропускает на Rx микросхемы 5 Вольт, которые с неё же и сняты. Т.е., как вы написали, преобразовывает.

Я только не могу понять, что 232 дальше с ними делает (на виртуальный Ком-порт на компе поступают HEX посылки). Сможет ли Ардуино работать с "сырыми" данными, или нужна обязательно 232 для их преобразования? Вот в чём вопрос.

step962
Offline
Зарегистрирован: 23.05.2011

red пишет:

Я только не могу понять, что 232 дальше с ними делает (на виртуальный Ком-порт на компе поступают HEX посылки). Сможет ли Ардуино работать с "сырыми" данными, или нужна обязательно 232 для их преобразования? Вот в чём вопрос.

Ровно то же, что эта схема делает с данными, получаемыми в Arduino от микроконтроллера - преобразовывает их с из TTL- в USB-протокол. "HEX-посылки" на компьютер не поступают, поступает поток двоичных данных, которые затем выводятся в шестнадцатиричном представлении. Но данные, конечно, сгруппированы в пакеты вполне определенного формата (на логическом уровне идентичные - что слева от преобразователя USB-TTL, т.е. в компьютере, сто справа, т.е. там где с ардуиной наиболее удобно к этому потоку прислушаться)

red
Offline
Зарегистрирован: 19.12.2011

Спасибо!

Значит я предполагал правильно: Ардуино должна принять "сырой" двоичный поток.

Теперь осталось выбрать между Duemilanove и Mega. У Меги входов больше и памяти. Портов мне должно хватить и на Due, а вот насчёт памяти - не имею понятия сколько её понадобится для программы....

red
Offline
Зарегистрирован: 19.12.2011

Итак, процесс пошёл.

Приехал китайский клон Ардуино Мега. Включил я ее, помигал светодиодом. Подключил соответственно 5v, GND и Rx к заранее собранной схеме и пошел к машине, дабы убедится, что прямая передача на комп, используя 232 Ардуины работает.

А она, зараза, не заработала. Хотя моя схемка из 6 деталей 100% рабочая, и люди уже подключали таким образом, правда Due, но какая разница...

В задаче спрашивается, а почему у меня не работает?

Вариант первый (несколько идиотский): На схеме Меги к RXD микросхемы почему-то идёт контакт, помеченный M8TXD. Возможно, нужно подключится к пину Tx?

http://arduino.ru/Schematic/arduino-mega-schematic.pdf

Вариант второй (еще более неправдоподобный): может это "мигающий" скетч в памяти мешает? Но судя по описанию пины 0 и 1 напрямую подключены к 232. А если  и мешает этот "блинк", то как очистить память Ардуино я нигде не нашёл...

 

 

step962
Offline
Зарегистрирован: 23.05.2011

red пишет:

Вариант первый (несколько идиотский): На схеме Меги к RXD микросхемы почему-то идёт контакт, помеченный M8TXD. Возможно, нужно подключится к пину Tx?

У Arduino Mega 4 пары выводов, которые можно использовать для последовательной коммуникации. И каждую из этих пар можно использовать. Все они абсолютно равноправны. Лишь пара NX0/RX0 чуть более равноправна, чем другие - она через резисторы 1K подключена еще и к преобразователю USB-TTL (микросхема F232RL). Подключать к этой паре какое-либо устройство означает - следить за тем, чтобы это устройство было отключено в процессе программирования. Иначе устройство (в активном состоянии) помешает  процессу загрузки. (в более младших ардуинах с единственной парой RX/TX это происходит сплошь и рядом)

При выборе любой пары RXi/TXi необходимо обеспечить, чтобы в скетче использовался правильный объект Seriali (а для Меги доступны целых 4 подобных объекта - Serial, Serial1, Serial2, Serial3 или как там точно - посмотрите в документации на библиотеку Serial). Возможно, здесь ваша сабака порылась.

Цитата:

Вариант второй (еще более неправдоподобный): может это "мигающий" скетч в памяти мешает? Но судя по описанию пины 0 и 1 напрямую подключены к 232. А если  и мешает этот "блинк", то как очистить память Ардуино я нигде не нашёл...

 

При каждой загрузке нового скетча вся flash-память очищается и перезаписывается. Исключение составляет лишь защищенная от записи область (в нех как раз и размещается bootloader - коды, ведающие загрузкой скетчей). Так что не надейтесь - ничего от "мигающего" скетча в программной памяти вашей меги уже не осталось.

step962
Offline
Зарегистрирован: 23.05.2011

red пишет:

 

А она, зараза, не заработала. Хотя моя схемка из 6 деталей 100% рабочая, и люди уже подключали таким образом, правда Due, но какая разница...

В задаче спрашивается, а почему у меня не работает? 

Продолжая традицию несколько идиотских вопросов, выкладываю свой: а по каким признакам вы определили, что "она, зараза, не заработала"?

Если что - прицепленная вами картинка мне (возможно, и остальным посетителям форума) не видна - не загружается.

Опля. Выцепил URL из исходного кода вашего поста (вы, кстати, поместили в пост не URL картинки, а ссылку на страницу, на которой она размещается - отсюда и проблема с просмотром) и увидел-таки картинку. Хотел разместить здесь, но в связи с ее величиной предпочел правильно оформить ссылку на соответствующую страницу:

 www.imagebam.com/image/f26d5a113409791

По картинке не совсем ясно, к какому RX-выводу вы подключили "автомобильную" линию последовательной передачи данных. Если к стандартному UART-порту (выводы 0+1), то проблема во взамных помехех двух устройств, подключенных к одному UART-порту (компьютер и автомобиль). Если к любому из трех дополнительных, то используемый вами скетч должен быть соответствующим образом адаптирован.

Чтение из автомобиля:

SerialX.read(); // X - 1,2 или 3

Отправка компьютеру:

Serial.write();

Ну и соответствующая инициализация всех необходимых объектов.

Так что - выкладывайте скетч.

step962
Offline
Зарегистрирован: 23.05.2011

 Кстати, еще один идиотский вопрос: а почему на картинке Duemilanove, хотя речь вы ведете о меге?

Чем больше я вчитываюсь в ваши посты, тем чаще приходит на ум анекдот о пьянице, ищущем потерянные ключи под фонарем.

Может быть вы все же выложите СВОЮ схему, СВОЮ картинку, СВОЙ скетч? 

red
Offline
Зарегистрирован: 19.12.2011

Отвечаю по-порядку.

1. Схема в первом посте собрана и 100% работает, поскольку я подключал её к TTL-232R - программа на ноуте получает даные.

2. Может я непонятно выразился, но идея была в том, чтобы сначала проверить, работает ли F232RL на Ардуино. Т.е. скетча нет никакого вовсе. Данные должны идти как-бы "транзитом". Исходя из схемы Ардуино Rx0 и Тх1 подключены напрямую к F232RL.

3. Картинку я привёл как пример работы идентичной схемы. Её автор на мой вопрос об отсутствии скетча ответил мне следующее (он болгарин, но понять можно): "для работа Xr25 с Ардуино не было нужно сделать скетч. Tx и Rx на 1 и 2 вывод Digital pinout передает данны от программе прямой и не надо писать програма для это."

4. Демо-скетч "блинк" на данный момент в памяти, поскольку никакой другой я туда не записывал. Вот я и спрашивал, можно ли очистить память.

5. Какой самый простой способ проверить работоспособность последовательной шины?

step962
Offline
Зарегистрирован: 23.05.2011

red пишет:

5. Какой самый простой способ проверить работоспособность последовательной шины?

На меге TX (выв. 1) соединить с RX (выв. 0) и попытаться что нибудь отправить из терминальной программы компьютера. Все отправленное должно вернуться обратно.

Поскольку вы используете плату Arduino лишь в качестве донора USB-TTL-конвертора (т.е. "мучаете" только микросхему f232), то имеется смутное подозрение, что провод от компьютера надо соединить с выводом TX, а не RX. Ведь вконфигурации, описанной теперь во всей своей неприкрытой наготе, микроконтроллер не принимает данные (Receive - Rx) от автомобиля, а как-бы передает  (Transmit - Tx) их через f232 компьютеру. "Как-бы" - потому что эту работу за него делает соответствующий чип в недрах автомобиля.

Кстати, согласно упомянутой вами схеме Ардуины-меги, Tx микроконтроллера - это Rx микросхемы f232): цепочка меток Tx(PE1)-M8TXD-RXD. А по схеме из первого поста сигнал с авто надо подавать на RX-вывод микросхемы f232 (что логично).

После выяснения деталей конкретной конфигурации можно сказать, что "блинк" вам не помешает - он изменяет состояние ноги 13 - и только. С выводами 0 и 1 никаких действий не производится. Вот если какой-нибудь другой скетч-пример залить - из раздела COMMUNICATION - тогда да, тогда можно и побочный эффект схлопотать.

Но если вам хочется полностью обезопасить себя от тайных опасений, залейте пустой скетч:


void setup() {
}

void loop() {
}

 

red
Offline
Зарегистрирован: 19.12.2011

Получил подтверждение от своего боларского друга: таки надо подключаться к Тх. Данные пошли.

Можно возвращаться к первому посту.

Теперь самое сложное: научить Ардуино обрабатывать входящий поток. Идея моя в том, чтоб создать массив 1х43 и постоянно его перезаписывать данными из диагностической линии. Дальше прога должна выбирать нужные байты из массива и производить с ними математические операции.

Вопрос первый: как определить начало строки? Проблема в том, что строка начинается с "FF 00", но этот же фрагмент есть и в середине строки...

step962
Offline
Зарегистрирован: 23.05.2011

red пишет:

 

Вопрос первый: как определить начало строки? Проблема в том, что строка начинается с "FF 00", но этот же фрагмент есть и в середине строки...

Имеется протокол всего этого безобразия? Как правило, между пакетами передаваемых данных имеются паузы, значительно превышающие длину самого пакета - ну не гонит же аавтомобиль информацию о себе без перерыва, начиная передачу нового пакета данных сразу же после завершения передачи предыдущего.

Ну, а если такая пауза есть, то задача поиска начала посылки становится тривиальной - отлавливаем низкий уровень в линии, продолжающийся более n миллисекунд, становимся в позу ожидания и, получив первый же фронт, очищаем входной буфер USART-канала и начинаем считывать поступающие данные.

red
Offline
Зарегистрирован: 19.12.2011

К сожалению, протокола нет - есть только разрозненные данные о том, какой байт за какую характеристику отвечает.

Поэтому я и хотел отлавливать начало строки таким образом.

Возможно может помочь определить есть ли пауза исходник программы для PC. Она работает коряво, но тем не менее работает. Я просто в С++ полный ноль...

Вот сайт автора

http://frederic.bedon.perso.sfr.fr/XR26/

А вот сама прога и исходники

http://frederic.bedon.perso.sfr.fr/FICHIERS/

В наиболее полном из известных мне описаний протокола чётко сказано: Byte 1,2 - FF 00 - Block start

Я сравнил ту часть данных, которая находится в конце строки после FF 00 - она аналогична началу строки. Т.е. возможно на разных автомобилях и на разных ЭБУ длина строки была разная. И чтобы диагностический прибор чётко понимал где начало новой строки и сделали такой "ключ". Так что будем отталкиваться от этой информации. А массив можно сделать и больше. Просто при каждом "ключе" FF 00 нужно начинать записывать данные в его начало.

 

step962
Offline
Зарегистрирован: 23.05.2011

 Первый шаг "взламывания" - постоянно читать поступающую информацию и фиксировать (с точностью до миллисекунд - для скорости 9600 более точное измерение не имеет смысла) моменты поступления стартовой последовательности FF00. достаточно прочитать с полсотни таких последовательностей и вывести результаты на печать - недолгое изучение позволит выдеить периодичность отправки пакетов данных.

Цитата:

Итак, задача: получить в кокпите на LCD дисплее данные с ЭБУ автомобиля.

Кстати, а автомобиля-то какая (модель/год выпуска/...)?

ЗЫ: www.ardio.ru/obd2.php По ссылке описывается то,что вы пытаетесь получить?

ЗЗЫ: Это OBD называется? Или ECU (Engine Control Systems)?

ЗЗЗЫ: Если это ECU, то, похоже, ею и управлять можно.

whoim
Offline
Зарегистрирован: 03.11.2011

 Мне кажется, событие OnSerial, если есть паузы достаточные - подойдет. Событие шустрое, мне чтоб с тормозного компа получать данные, задержку пришлось ставить

Ну а в событии засовываем сразу в массив с индексом по счетчику.

step962
Offline
Зарегистрирован: 23.05.2011

 Событие OnSerial использует аппаратное прерывание UASRT_RX (Заверние приема по каналу UART). Это прерывание генерируется в момент, когда завершился цикл приема очередного байта (регистр сдвига принял 8 бит, сформировал принятый байт, отправил его в буфер приема-передачи UART, очистился и готов к приему очередного байта). По факту генерации события нельзя сказать, принят первый байт посылки, или последний. То есть в деле определения момента начала передачи очередной порции информации оно вряд ли может помочь.

Хотя...

Оно вполне может пригодиться в качестве индикатора КОНЦА передачи пакета. А за концом, как известно, всегда следует начало. Достаточно в обработчике этого прерывания записывать время приема очередного байта, а потом в главном цикле сравнивать его с текущим времением. Любая задержка больше среднего времени приема одного байта ( а для 9600 бит/с это чуть меньше миллисекунды), скажем, 2 (ну, или с запасом - 3) миллисекунды становится вполне надежным индикатором конца передачи пакета, и соответственно, момента, когда надо готовиться к приему стартовой последовательности "FF00".

long timeByteReceived; // или какой там тип нужен?
OnSerial() {
 timeByteReceivedd=millis();
// остальные операторы обработки события
}

loop() {
// ...
  if(millis()-timeByteReceived>3000) {
// время насторожиться и готовиться к началу очередной передачи
  }
// ...
}

 

whoim
Offline
Зарегистрирован: 03.11.2011

 step962

странно, но у меня OnSerial вполне себе работает именно на прием пакета (с задержкой 1ms), только внутри еще один цикл while Serial.Avariable. То есть я шлю с компа 96 байт (часто, но с задержкой как минимум 50ms). И по счетчику (будущий индекс массива) оно вполне себе успешно загоняется в этот самый массив в одном событии OnSerial

red
Offline
Зарегистрирован: 19.12.2011

Спасибо за помощь!

Отвечаю по-порядку. Машина - горячо любимая Renault 21 Turbo 1988 года выпуска. Вот характеристики

carsguru.net/catalog/renault/21/13605/

Протокол - не OBD, а чисто реношный XR25. Получаю я данные действительно с ECU (по-другому - ЭБУ, в простонародье -"мозги"). Управлять не получится. Для этого нужно менять чип и подключаться к нему по-другому, но такая задача и не стоит.

Для начала я бы написал простенький скетч, чтобы проверить есть ли вообще пауза как таковая между посылками. Но к сожалению не могу найти описание OnSerial...

step962 , еще такой вопрос возник глядя на пример скетча: что, можно строчки программы номеровать? Лично мне так больше нравится (Бейсик напоминает :)) ). И может можно влепить какой-то оператор типа goto ?

whoim
Offline
Зарегистрирован: 03.11.2011

 ошибочка вышла, дельфи совсем мозг съело

http://arduino.cc/en/Reference/SerialEvent

whoim
Offline
Зарегистрирован: 03.11.2011

 Нумеровать - нет. Можно http://arduino.cc/it/Reference/Goto

скетч - в одном событии получить строку и передать ее в другой порт сериал - к компу подключенный. Ну или дисплей и вывести на него, если нет варианта еще одну ft232 тулить

step962
Offline
Зарегистрирован: 23.05.2011

 Похоже, этот serialEvent никакой не event,  а лишь эмуляция. 

По ссылке my.safaribooksonline.com/book/hardware/arduino/9781449321185/4dot-serial-communications/104 читаем:

Цитата:

Arduino 1.0 added the serialEvent function that you can use to handle incoming serial
characters. If you have code within a serialEvent function in your sketch, this will be
called once each time through the loop function.

Функция никак не связана с прерываниями AVR USART_RX/USART_UDRE/USART_TX, вызывается при каждом проходе loop() - вне зависимости от того, поступало ли что-нибудь по UART, отправлялось ли.  Просто стандартизованное место для размещения кодов обработки последовательного ввода-вывода.

whoim
Offline
Зарегистрирован: 03.11.2011

 понятно...

red
Offline
Зарегистрирован: 19.12.2011

Пока морозы ужасно не хочется лишний раз выходить к машине. Поэтому занялся пока перефирией: подключил часы на базе DS1307 (покупал готовый шильдик) .

Также подключил LCD HD44780 и сделал для него несколько кириллических символов (библиотека LiquidCrystalRus не заработала: вместо русских букв - иероглифы).

Задался вопросом регулирования яркости подсветки, поскольку светит экранчик достаточно ярко и однозначно будет в машине ночью слепить. Первый вариант, пришедший в голову - регулировать через ШИМ. Насколько я понял, максимальный для выводов Ардуино ток - 50 мА. Но в документации на LCD не указано никаких параметров по подсветке...

 

whoim
Offline
Зарегистрирован: 03.11.2011

 транзистор pnp, подтягивается (открывается) на минус, регулирует плюс. Подсветка от 200 ма будет кушать. Один слабенький светодиод - 20ма минимум

red
Offline
Зарегистрирован: 19.12.2011

Ого, даже не думал, что столько. Мультиметр китайский, зараза, накрылся. Придётся еще транзисторный ключик собрать.

red
Offline
Зарегистрирован: 19.12.2011

Сделал регулировку яркости через транзистор BC547B. С железом практически всё.

Начал пробовать получать данные через Serial и писать их в массив. Что-то делаю не так, но не пойму что.

Вкратце: отправляю, к примеру, число 25 из компа: программа читает их как 2 и 5, и соответственно записывает в две ячейки.

Вот содранный откуда-то и изменённый мной скетч для получения 10 значений и их последующего вывода на LCD.

#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(53, 52, 51, 50, 49, 48);
byte incom; //входящий байт
byte str [45]; // строка с данными
int strcount = 1; //счётчик строки

void setup(){
    // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
  // initialize the serial communications:
  Serial.begin(9600); 

}

void loop()
{
  // when characters arrive over the serial port...
  if (Serial.available()) {
    // wait a bit for the entire message to arrive
    delay(100);
    // clear the screen
    lcd.clear();
    // read all the available characters
    while (Serial.available() > 0) {
      // display each character to the LCD
      incom = Serial.read();
      str[strcount] = incom; 
      strcount++;
      lcd.setCursor(0,0);
      lcd.print(strcount);

      if (strcount==10) {
         for (int i=1; i < 10; i++) {
         lcd.setCursor(0,1);
         lcd.print(i);
         lcd.print(": ");
         lcd.print(str[i]);
         delay (1500);
         }
        lcd.clear();
        strcount = 1;   
  }
  }
}
}

 

whoim
Offline
Зарегистрирован: 03.11.2011

 Вкратце: отправляю, к примеру, число 25 из компа: программа читает их как 2 и 5, и соответственно записывает в две ячейки.

программа все делает правильно - принимает два (char) и пишет их так. А вам как надо?

red
Offline
Зарегистрирован: 19.12.2011

Мне надо, чтоб она записывала в массив числа от 0 до 255. Я поэтому и массив делал byte... А прога принимает не число, а символ. Т.е. если ввести число 123, то она запишет в 3 ячейки массива 1, 2 и 3.

 

whoim
Offline
Зарегистрирован: 03.11.2011

 ну все правильно она делает. Отсылаете чем и как?

Diemon
Offline
Зарегистрирован: 18.11.2011

 чтобы возвращала 25 а не 2 и 5

int serReadInt()
{
  int i, serAva;
  char inputBytes [7]; // массив для хранения байтов
  char * inputBytesPtr = &inputBytes[0]; // указатель на первый элемент массива

  if (Serial.available()>0) // проверяем есть ли данные
 {
    delay(5);//чутка ждем, чтобы все данные прошли
    serAva = Serial.available(); // получаем количество доступных байт
    for (i=0; i<serAva; i++) // загружаем байты в массив
      inputBytes[i] = Serial.read();

    inputBytes[i] = '\0'; // дописываем NULL в конец массива
    return atoi(inputBytesPtr); // Вызываем atoi функцию, стандартная функция С
  }
  else
    return -1; // Возвращаем -1, если ничего не получили
}

step962
Offline
Зарегистрирован: 23.05.2011

Diemon пишет:

 чтобы возвращала 25 а не 2 и 5

А это уже не от Arduino-скетча зависит, а от того, что отправляется с компьютера. Из терминала данные посылаете? Сначала нажимаете клавишу "2", потом "5" и, наконец, "Enter"?

Терминал и отправляет - "2" (0x32), "5" (0x35), "\r" (0x0D) и "\n" (0x0A). А Arduino все это прилежно получает.

Хотите получить именно 25? Отправьте символ 0x19. Поскольку отображаемого символа с таким кодом нет, попробуйте, удерживая Alt, набрать 25 на цифровой клавиатуре, а затем, отпустив Alt, нажать Enter.

Либо производите преобразование на стороне Arduino:

if(Serial.available()) {
  int val=0,d;
  while(Serial.available()) {
    d=(int)Serial.read()-0x30;  // для '0'..'9' получаем, соответственно 0...9
    val=val*10+d;
    delay(1);  // это чтобы символы успевали приходить
  }
  // Теперь можно вывести принятое значение
}

 

red
Offline
Зарегистрирован: 19.12.2011

Всем спасибо за разъяснения!

Взял нормальную терминальную программу, установил в ней на передачу HEX и всё заработало - Ардуино принимает строчки с данными и записывает их в массив.

Как раз получил текст программы на С++ от французского энтузиаста по работе с реношным протоколом XR25. Для того, чтоб программа верно определила начало строки с данными, он тоже отлавливал связку байт FF 00. Его алгоритм показался мне слишком громоздким (правда программа была написана для PC).

Я написал свой вариант, опробовал с терминальной программой - вроде работает. Завтра попробую на машине.

Правда я использовал в своём скетче goto. Насколько я понял, сейчас это не комильфо. Но я же не профессионал. Главное, чтобы заработала. :))

whoim
Offline
Зарегистрирован: 03.11.2011

red пишет:

Всем спасибо за разъяснения!

Взял нормальную терминальную программу, установил в ней на передачу HEX и всё заработало - Ардуино принимает строчки с данными и записывает их в массив.

Как раз получил текст программы на С++ от французского энтузиаста по работе с реношным протоколом XR25. Для того, чтоб программа верно определила начало строки с данными, он тоже отлавливал связку байт FF 00. Его алгоритм показался мне слишком громоздким (правда программа была написана для PC).

Я написал свой вариант, опробовал с терминальной программой - вроде работает. Завтра попробую на машине.

Правда я использовал в своём скетче goto. Насколько я понял, сейчас это не комильфо. Но я же не профессионал. Главное, чтобы заработала. :))

 

Почти всегда готу можно заменить различными комбинациями циклов ) Давайте текст, подумаем вместе.

Мне работа протокола интересна на будущее - в моей волге помоему этот же реношный протокол используется.

red
Offline
Зарегистрирован: 19.12.2011

Насчёт Волги: я сомневаюсь. Это протокол системы Реникс/Феникс. Реношные движки ставились еще на Вольво и на Москвич "Святогор". Ну в любом случае, если будет интересно - поделюсь.

А у меня "следствие зашло в тупик". :(

Подключил сегодня Ардуино к ЭБУ - не ловит она связку FF 00. Решил принять на ноут терминальной программой данные и посмотреть на них сам: поствил галку на HEX, принял пару сотен байт. А там действительно не встречается такая комбинация.

Решил проверить другие варианты. Комбинация 72 04 тоже должна быть обязательно (указывает тип машины, двигателя) и тоже не встречается. Вместе с тем, программа на ноуте четко показывает сттроку FF 00 72 04 и т.д. Т.е. работает.

Я прямо не представляю, куда дальше двигаться...

step962
Offline
Зарегистрирован: 23.05.2011

red пишет:

Подключил сегодня Ардуино к ЭБУ - не ловит она связку FF 00. Решил принять на ноут терминальной программой данные и посмотреть на них сам: поствил галку на HEX, принял пару сотен байт. А там действительно не встречается такая комбинация.

Ну, вообще-то, 0xFF часто используется в качестве признака завершения передаваемого по UART пакета данных. И программы могут автоматически интерпретировать его таким образом. Такая информация попадалась мне пару раз во время блужданий по Интернету. Вполне возможно, что используемые вами программы этот символ соответствующим образом и интерпретируют. Для терминала - посмотрите в настройках, нет ли там возможности настройки метода интерпретации отдельных символов (как символ/как числовое значенгие/как команда) .

А в Arduino... В Arduino вы возможно с типами переменных и их обработкой немного ошиблись. Вот почитайте это. И вообще - пошерстите Интернет с помощью запроса "UART 0xff" и ему подобных.

red
Offline
Зарегистрирован: 19.12.2011

С помощью коллеги по цеху двигаюсь дальше. Оказывается, старые ЭБУ Рено имеют нестандартную скорость передачи - 62500. Поставил её в своём скетче, и данные пошли как положено!

Но мой алгоритм "отлавливания" начала строки FF 00 работает не совсем правильно. Примерно первых пять циклов всё отлично, а потом сбивается. Подозреваю, что переполняется буфер на Ардуине, а в какой момент его очистить не соображу...

Появился альтернативный вариант: один из энтузиастов работы с протоколом XR25 в своей статье пишет, что между посылками есть пауза в 25 миллисекунд. Подскажите, как её всё-таки можно отловить?

whoim
Offline
Зарегистрирован: 03.11.2011

 Появился альтернативный вариант: один из энтузиастов работы с протоколом XR25 в своей статье пишет, что между посылками есть пауза в 25 миллисекунд. Подскажите, как её всё-таки можно отловит

Посмотрите такие вещи, как if (Serial.Avariable) и как работать с millis()

red
Offline
Зарегистрирован: 19.12.2011

Не понимаю, как можно с помощью этих операторов добиться нужного мне результата...

Я нашёл еще такой оператор, как pulseIn(), но не знаю, можно ли его применить в этом случае.

step962
Offline
Зарегистрирован: 23.05.2011

 Функция Serial.available() имеет возвращаемое значение - количество символов в приемном буфере UART-канала.

В главном цикле (функция loop()) читайте это значение и если оно в течение 1-2 миллисекунд не меняется, значит, передача очередного пакета завершена и можно (даже нужно) считать все содержащиеся в приемном буфере символы и приготовиться к приему очередного пакета.

int millisold,milliscur,timeElapsed=0;
int buflenold,buflencur;
setup() {
// ...
  millisold = millis();
  milliscur = millis();
  buflenold = 0;
  buflencur = 0;
}

loop() {
  buflencur=Serial.available();
  milliscur=millis();
  if(buflencur>0) { // проверку делаем только для непустого буфера
    if(buflencur==buflenold) { // новый символ не пришел
      timeelapsed = timeelapsed + (milliscur-millisold);
    }
    if(timeelapsed > 2) { // контрольное время истекло 
      while (Serial.available())
  // читаем символы из буфера и сохраняем в своем или передаем куда-нибудь или ... все что угодно
    } 
  }
// настройка на следующий цикл
  millisold=milliscur;
  buflenold=buflencur;
// остальная часть цикла...
}

Ну и помним о принципах структурного программирования - все написанное в loop() лучше оформить отдельной функцией, а в loop() оставить лишь вызов этой функции (например testUARTbuf()). Когда программа разрастется, разбивка на функции будет очень помогать не терять обзорность и не рушить всю логику программы неудачной вставкой не того оператора не в то место.

red
Offline
Зарегистрирован: 19.12.2011

Спасибо за такой детальный скетч!

Но у меня всё-равно осталось несколько вопросов, которые происходят от того, что я не до конца понимаю как работает буфер последовательного порта.

1. Не нужно ли применить Serial.flush() после 18 строки? Возможна ли такая ситуация, когда часть посылки из 43 байт будет потеряна из-за достижения конца буфера?

2. Что если вместо такого алгоритма просто подключить линию с данными еще и к одному из digital pin и ждать на ней LOW>10мс функцией pulseIn(), а потом начинать писать в массив байты из последовательного порта?

step962
Offline
Зарегистрирован: 23.05.2011

red пишет:

Спасибо за такой детальный скетч!

1. Не нужно ли применить Serial.flush() после 18 строки? Возможна ли такая ситуация, когда часть посылки из 43 байт будет потеряна из-за достижения конца буфера?

Приемный буфер последовательного порта имеет организацию FIFO (First In - First Out или по-русски Первым Пришел - Первым Ушел, или очередь).  Serial.flush() применять не надо, если вы не доводите до переполнения буфера (когда хвост очереди упирается в голову). Все, что надо - это с достаточной частотой делать вызовы Serial.read(). Каждый такой вызов читает один символ из очереди и соответственно укорачивает ее на один байт.

А flush просто очищает буфер, т.е. все данные будут потеряны. Никакого отличия от переполнения - как говорится, те же яйца ...

Использовать flush имеет смысл разве что для настройки на начало пакета - когда точно известно, что содержимое буфера представляет собой остаток предыдущего пакета, который не представляет информационной ценности.

 

Цитата:

2. Что если вместо такого алгоритма просто подключить линию с данными еще и к одному из digital pin и ждать на ней LOW>10мс функцией pulseIn(), а потом начинать писать в массив байты из последовательного порта?

Вполне себе можно - для этой цели хорошо подходят линии D2 и D3. Если не ошибаюсь, именно к ним подключены выводы микроконтроллера, имеющие функции INT0 и INT1 - входы внешних прерываний.

red
Offline
Зарегистрирован: 19.12.2011

Получилось обойтись без прерываний: программа ждёт низкого уровня на цифровом входе и записывает массив.

Довёл до ума и алгоритм поиска начала строки. Так что теперь работают оба варианта. Ура!

Правда не знаю, какой теперь лучше использовать: программный или "железный"?

whoim
Offline
Зарегистрирован: 03.11.2011

 С прерываниями всегда симпатичнее.

step962
Offline
Зарегистрирован: 23.05.2011

red пишет:

Правда не знаю, какой теперь лучше использовать: программный или "железный"?

Лучшее - враг хорошего...

Используйте оба и ищите третий вариант. ;)