Всем привет! Подскажите с огранизацией протокола передачи данных по COM-порту. Есть Arduino Nano (со своим скетчем) и PC (например реализация в MATLAB, это не суть важно). Arduino считывает данные с трёх аналоговых пинов (по типу analogRead(A0)) и непрерывно передаёт в Serial COM-порт. Это: 1) управляющее напряжение источника питания фотоумножителя (положительные 0-5 Вольт) 2) реальное напряжение источника питания (оно через инвертор ОУ от 0 до минус 800 Вольт конвертируется в положительные 0-5 Вольт) 3) питания с выхода фотоумножителя (оно через инвертор ОУ от 0 до минус 40 Вольт конвертируется в положительные 0-5 Вольт) Т.е. с Ардуино на PC в COM-порт отдаётся три потока с цифрами напряжений, их нужно как то разделять при приёме на PC. С PC на Ардуино в COM-порт тоже может придти информация для выставления уровня ШИМ. Т.е. эта информация должна разбираться только в скетче Ардуины. На ум приходит такое решение. С Ардуины идут непрерывно пакеты в виде "SupplyControlVoltage:2,35", "SupplyOutputVoltage:3,86" и "PTMVoltage:1,67" С компа может придти например: "FromPCSupplyControlVoltage:1,89". Вопросы - как организовать такую передачу данных, как формировать сообщения в канал и на другой стороне разбирать их. Как их не перепутать? Покажите пожалуйста пример. Нужны ли открывающие и закрывающие биты для таких сообщений? Спасибо!
Сократите префиксы до одного символа, никому эти длинные портянки не нужны. Тривиальный формат пакета: начальный_символ+префикс+значение+конечный_символ: "<C2.35>" "<O3.86>" "<S1.89>" Разбирать - конечным автоматом (см http://wiki.amperka.ru/программирование:конечный-автомат), состояние которого будет соответствовать принимаемой части пакета. Значение накапливать в строке, потом переводить в число.
Передавать в двоичном виде самое эффективное решение, с учетом: Пример, если пишите на Си, просто отдам в хорошие руки 1 из реализаций такой передачи. Если не пишите на Си, то увы, такого примера нет. UDP. Уже публиковал, если будет интересно посмотрите http://forum.amperka.ru/threads/Реализация-uart-rs-485.6791/.
Таак, теперь начинаются вопросы. У меня формат команды такой: CV:1234 Короче, буквы, двоеточие, цифры. Я их ловлю в сериал порте. Есть скрипт простейший, суть которого: если первые буквы равны тому что мне нужно, то отсечь их, а остальные цифры перевести в int и далее работать с ними. Код (C++): void setup() { Serial.begin(9600); } void loop() { String input = ""; while (Serial.available()) { input = input + (char)(Serial.read()); Serial.print(input); } if (input.startsWith("CV:")) { String Voltage = input.substring(2); Voltage.trim(); int Vol = Voltage.toInt(); Serial.print(Vol); } } Почему не работает, можете подсказать?
Не часто пользуюсь обычной библиотекой. Что мне не нравится в этом коде. 1. String input =""; в начале loop. Дело в том, что может быть выполнено несколько циклов loop прежде, чем мы получим сообщение полностью. Именно это тут и происходит. 2. Serial.print(input); в цикле while, сначала получите данные, а потом работайте с ними, такой подход позволит ни когда не пропускать данные. Ваш вариант сработает, ну лучше писать правильно. UPD. Пример получения данных, правда в массив char-ов - http://forum.amperka.ru/threads/ascii.7002/#post-59237. UPD 2. 3. Нет символа конца пакета, как мы поймем, что все данные получены. Ваш пакет не удобен CV:1234, лучше CV:1234! (! символ конца пакета). 4. Зачем в начале CV: когда можно заменить 1 символом C? Теперь команда выглядит так C1234!, конечный код с учетом замечаний. Код (C++): String input = ""; boolean dataReady = 0; void setup() { Serial.begin(9600); } void loop() { while (Serial.available()) { char incomingChar = (char)Serial.read(); if (incomingChar == 'C') { dataReady = 0; input = ""; continue; } if (incomingChar != '!') { input += incomingChar; } else { dataReady = 1; } } if (dataReady) { int Vol = input.toInt(); Serial.print("Vol - "); Serial.println(Vol); dataReady = 0; } } Удачи!
Операции сложения строк лишние, пакет лучше считывать в статический буфер, особенно при фиксированной длине пакета.
Да, всего лишь сохранил стиль SpaceQuester. С статическим буфером уже давал ссылку. Но если исходить выше сказанного: То одного буфера, возможно, будет не достаточно, тогда кольцевые буферы, прерывания и передавать в структурах, разумеется в двоичном виде. О чем Вы упомянули, ссылку на такой вариант тоже указывал.
Возможно Вы меня не так поняли, предлагал уйти от самой библиотеки Serial. Сделать все на AVR + Си, благо примеров в сети предостаточно, один пример давал чуть выше (взятый из общественного проекта, сейчас допиливаю для себя). Но это мой взгляд на данную проблему, возможно есть другие, более оптимальные решения, если поделись направлением, буду признателен. Ассемблер не предлагать и без него голова пухнет от языков и технологий, доучить бы .
Предположил, что для непрерывной отправки (хотя, странная формулировка, ни чего не прерывного не бывает), может потребоваться уйти от библиотеки Serial. Соглашусь с Вами, что библиотека сделана достойно, едва ли у меня получится написать аналогичное решение лучше (с учетом поддержки микроконтроллеров и возможностей). Поэтому активно использую стандартную, но если размер или скорость, очень критична, пользуюсь другой. Размер скетча больше, Nano, Arduino IDE 1.6.5. Serial отправка через write 1 байт. Аналогично, библиотека для AVR в том же скетче. А вот максимальное время цикла ниже, раза в два. Подведем итог, в большинстве случаев Вы правы, лучше использовать Serial, если ее не достаточно, придется искать другие решения. P.S. Спасибо, что заставили меня более внимательно глянуть на библиотеку Serial.
Ну, мне пришлось как-то для влезания в tiny немного ее видоизменить. Выкинул всю объектную шелуху, сэкономил сколько то десятков или сотен байт.
Спасибо гляну на досуге, для развития. C++ для меня еще не много сложен, не получается пока читать код. Но в C уже многое достает не возможность указывать значения по умолчанию для аргументов функции, отсутствие наследования и т.д. Свою библиотеку уже скидывал, может будет полезно.