Организация передачи данных по COM-порту

Тема в разделе "Проводная и беспроводная связь", создана пользователем SpaceQuester, 24 фев 2016.

  1. SpaceQuester

    SpaceQuester Нерд

    Всем привет!

    Подскажите с огранизацией протокола передачи данных по 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".

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

    Спасибо!
     
  2. Unixon

    Unixon Оракул Модератор

    Сократите префиксы до одного символа, никому эти длинные портянки не нужны.

    Тривиальный формат пакета:
    начальный_символ+префикс+значение+конечный_символ: "<C2.35>" "<O3.86>" "<S1.89>"

    Разбирать - конечным автоматом (см http://wiki.amperka.ru/программирование:конечный-автомат), состояние которого будет соответствовать принимаемой части пакета. Значение накапливать в строке, потом переводить в число.
     
    Последнее редактирование: 25 фев 2016
    Tomasina нравится это.
  3. Unixon

    Unixon Оракул Модератор

    Ну, можно еще воспользоваться структурами и передавать данные в двоичном виде.
     
    Alex19 нравится это.
  4. Alex19

    Alex19 Гуру

    Передавать в двоичном виде самое эффективное решение, с учетом:
    Пример, если пишите на Си, просто отдам в хорошие руки 1 из реализаций такой передачи:). Если не пишите на Си, то увы, такого примера нет.

    UDP. Уже публиковал, если будет интересно посмотрите http://forum.amperka.ru/threads/Реализация-uart-rs-485.6791/.
     
    Последнее редактирование: 24 фев 2016
  5. SpaceQuester

    SpaceQuester Нерд

    Таак, теперь начинаются вопросы.
    У меня формат команды такой: 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);
      }
    }
    Почему не работает, можете подсказать?
     
  6. Alex19

    Alex19 Гуру

    Не часто пользуюсь обычной библиотекой.

    Что мне не нравится в этом коде.
    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;
      }
    }
    Удачи!
     
    Последнее редактирование: 3 мар 2016
    SpaceQuester нравится это.
  7. SpaceQuester

    SpaceQuester Нерд

    Супер! Спасибо за помощь! Ушло в работу.
     
  8. Unixon

    Unixon Оракул Модератор

    Операции сложения строк лишние, пакет лучше считывать в статический буфер, особенно при фиксированной длине пакета.
     
  9. Alex19

    Alex19 Гуру

    Да, всего лишь сохранил стиль SpaceQuester.

    С статическим буфером уже давал ссылку.

    Но если исходить выше сказанного:
    То одного буфера, возможно, будет не достаточно, тогда кольцевые буферы, прерывания и передавать в структурах, разумеется в двоичном виде. О чем Вы упомянули, ссылку на такой вариант тоже указывал.
     
    Последнее редактирование: 6 мар 2016
  10. Unixon

    Unixon Оракул Модератор

    Ну, один кольцевой буфер внутри Serial уже есть...
     
  11. Alex19

    Alex19 Гуру

    Возможно Вы меня не так поняли, предлагал уйти от самой библиотеки Serial.

    Сделать все на AVR + Си, благо примеров в сети предостаточно, один пример давал чуть выше (взятый из общественного проекта, сейчас допиливаю для себя).

    Но это мой взгляд на данную проблему, возможно есть другие, более оптимальные решения, если поделись направлением, буду признателен. Ассемблер не предлагать и без него голова пухнет от языков и технологий, доучить бы :).
     
  12. Unixon

    Unixon Оракул Модератор

    Она настолько маленькая, что практически любой такой уход выльется всего лишь в её повторение.
     
    Alex19 нравится это.
  13. Alex19

    Alex19 Гуру

    Предположил, что для непрерывной отправки (хотя, странная формулировка, ни чего не прерывного не бывает), может потребоваться уйти от библиотеки Serial.

    Соглашусь с Вами, что библиотека сделана достойно, едва ли у меня получится написать аналогичное решение лучше (с учетом поддержки микроконтроллеров и возможностей). Поэтому активно использую стандартную, но если размер или скорость, очень критична, пользуюсь другой.

    Размер скетча больше, Nano, Arduino IDE 1.6.5.

    Serial отправка через write 1 байт.
    Аналогично, библиотека для AVR в том же скетче.
    А вот максимальное время цикла ниже, раза в два. Подведем итог, в большинстве случаев Вы правы, лучше использовать Serial, если ее не достаточно, придется искать другие решения.

    P.S. Спасибо, что заставили меня более внимательно глянуть на библиотеку Serial.
     
  14. Unixon

    Unixon Оракул Модератор

    Ну, мне пришлось как-то для влезания в tiny немного ее видоизменить.
    Выкинул всю объектную шелуху, сэкономил сколько то десятков или сотен байт.
     

    Вложения:

    • hwserial.cpp
      Размер файла:
      7,1 КБ
      Просмотров:
      504
    • hwserial.h
      Размер файла:
      2 КБ
      Просмотров:
      713
    • macro.h
      Размер файла:
      182 байт
      Просмотров:
      694
    Alex19 нравится это.
  15. Alex19

    Alex19 Гуру

    Спасибо гляну на досуге, для развития. C++ для меня еще не много сложен, не получается пока читать код. Но в C уже многое достает не возможность указывать значения по умолчанию для аргументов функции, отсутствие наследования и т.д.

    Свою библиотеку уже скидывал, может будет полезно.