Невозможность сразу читать/писать данные с arduino после подключения

Тема в разделе "Arduino & Shields", создана пользователем Витя, 13 апр 2014.

  1. Витя

    Витя Гик

    Наткнулся на непонятную вещь.

    Есть код в ардуино уно, читает какие-то байты, пишет в ответ. Условно что-то такое:
    Код (Text):
    void loop() {
      if (Serial.available() > 0)
      {
        Serial.read();
        Serial.write(0xff);
      }
    }
    Подключаюсь с компьютера (пишу программу в mac os x 10.9) и вот в чем странность. Если сразу после открытия попытаться прочесть данные с ардуино, то программа зависает в read. Если подождать примерно 2 секунды прежде чем начать читать то все будет работать. Вот код подключения:
    Код (Text):
    - (BOOL)openPort:(char *)bsdPath
    {
        speed_t baudRate = B115200;

        _serialFileDescriptor = open(bsdPath, O_RDWR | O_NOCTTY | O_NONBLOCK);
        if (_serialFileDescriptor == -1) {
            NSLog(@"Can't open device (%@)", [NSString stringWithUTF8String:bsdPath]);
            return NO;
        }

        ioctl(_serialFileDescriptor, TIOCEXCL);
        fcntl(_serialFileDescriptor, F_SETFL, 0);
        ioctl(_serialFileDescriptor, IOSSIOSPEED, &baudRate);

        return YES;
    }
    после идет функция которая просто пишет/читает:
    Код (Text):
    uint8_t buf[1] = { 0x1 };
    write(_serialFileDescriptor, buf, sizeof(buf));
    uint8_t b;
    int n = read(_serialFileDescriptor, &b, sizeof(b));

    NSLog(@"%x - %d", b, n);
    Зависает в read. Понятное дело потому что убираю флаг NONBLOCK через F_SETFL и read будет ждать данные до тех пор пока не прочтет. Но странность как раз в том что данные так и не приходят. Если не сбрасывать не блокирующий флаг, то read ничего не прочитает и будет возвращать -1. Даже если зациклить, то всеравно ничего не приходит.
    С чем может быть связана эта задержка что нельзя сразу начать читать? Может какой-то режим работы особый нужно указать?
    p.s.
    Еще проверил, ловит ли arduino то что ей сразу послать через write. Оказалось что тоже данные не принимаются :(
     
    Последнее редактирование: 13 апр 2014
  2. Unixon

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

    Наверное Mac отсылает данные в штаб-квартиру Apple, чтобы там убедились, что в передаваемых данных не содержится коммерческеи значимой информации. :)
     
  3. Alex19

    Alex19 Гуру

    Сам не знаком с Mac.

    В Windows на C#, лучше вводить паузу если данные отправляются/читаются сразу после открытия порта, достаточно секунды.

    Как я понял связано это с Win32 API, на который опирается класс SerialPort в .Net.
    А там рекомендуется вводить паузу перед открытием и/или перед закрытием, связано с тем, что для закрытия порта может потребоваться время.

    Возможно в Mac, есть, что-то такое.

    UPD. Не знаю, какую задачу Вы решаете. Но больших проблем в таймауте не вижу.
    Если не хотите, чтобы ардуина работала в пустую, то можно после таймаута отправлять байт старта и в завершении байт остановки работы ардуины.
     
    Последнее редактирование: 13 апр 2014
    Максимус-Бог и Витя нравится это.
  4. Витя

    Витя Гик

    Проблемы нету. Просто вот наткнулся и думал что как то наверное не правильно открываю порт. Странно ведь почему такая задержка нужна.
     
  5. Unixon

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

    А со стороны мака буфер на запись сбрасывать насильно не требуется (если он есть)? А то может оно тупо ждет какой-нибудь общесистемной синхронизации. У вас по коду ардуина не отправит данные пока не примет их. Может задержка возникает еще на отправке?
     
  6. Alex19

    Alex19 Гуру

    Посмотрите внимательно свой фреймворк, описание открытие, закрытие порта.
    Ну а так же общую работу, как сказал Unixon, буфер и т.д. Это будет полезно в любом случае.

    Кроме этого проверьте DtrEnable в соединение, true оно или false.
    До конца не разобрался с ним, для некоторых плат в частности Leonardo (может быть еще какие-то, наверно связано с чипом Serial порта на ардуине), этот параметр обязательный.

    Вот пример
    http://forum.amperka.ru/threads/Проблема-получения-данных-от-arduino.2384/

    и еще один
    http://www.arduino.ru/forum/programmirovanie/c-i-arduino

    Mega 2560 R3 работает и без него.
    С DtrEnable = true, при открытии порта и подключении к ардуине, ардуина перезагружается и начинает выполнение с начала. И если в коде ардуины, в функции setup стоит какая задержка, то пока она не истечет, функция loop не будет запущена.

    Сам проверял на Mega 2560 R3, иногда такая функция бывает полезна.

    Если интересно почитайте о DtrEnable, вбив в поисковик - arduino DtrEnable

    UPD. На мой с коллегой субъективный взгляд c DtrEnable на большой скорости 115200 (десятки запросов в секунду) с DtrEnable = true программа на .Net работает стабильней.

    Вот ветка коллеги
    http://arduino.ru/forum/proekty/kontrol-peredachi-dannykh
     
    Последнее редактирование: 14 апр 2014
  7. Витя

    Витя Гик

    Начал разбираться что это такое. Короче DTR - это Data Terminal Ready специальный сигнал который отсылает терминал в модем когда он готов. Получается терминал - это программа которая подключается к ардуино, а ардуино - это типа как модем. Короче в Arduino Uno как у меня физически сигнал по линии DTR подключен к RESET пину через 100 нФ конденсатор. И если DTR сигнал посылается, то физически это значит посылается НОЛЬ и поэтому Ардуино перезагружается. И в линукс/макос такое происходит ВСЕГДА. Поэтому получается у меня ардуино перезагружается и я начинаю слать/читать данные в загрузчик и поэтому висну. А вот через 2 секунды все уже начинает работать.

    Попробовал выключить посылку сигнала DTR но не сработало. Наверное конденсатор успевает разрядится раньше чем проходит команда. А в виндоус я так понял данный сигнал не посылается если специально его не назначить.

    p.s.
    При этом получилось перезагружать Ардуино в любое время, если послать подряд снятие DTR сигнала и через небольшую задержку потом его установку.
     
    Последнее редактирование: 17 апр 2014
  8. Alex19

    Alex19 Гуру

    Да все именно так.

    Это относится к самому соединению Serial и по идее должно быть и в unix\linux. Может UNO относится к тем платам которым необходим этот параметр и драйвер, автоматом подставляет этот параметр соединения.

    Придется видимо смирится, можно выставить таймаут после подключения.
     
  9. Витя

    Витя Гик

    Не он не нужен именно что арудине. Короче по стандартам этот сигнал надо посылать когда терминал готов. И вот в *nixах он посылается всегда сразу после соединения так как это положено. А в винде надо отдельно посылать (таких разных сигналов вобше 4). А в ардуино уно данный сигнал идет от 13 пина контролера связи (atmega16u2) к reset пину и получается когда он приходит получается ребут. Короче неправильная задумка получается. Чтобы этого не было там на плате перемычку сделали, ее надо разрезать.
     
    Последнее редактирование: 21 апр 2014
    Alex19 и Megakoteyka нравится это.
  10. Alex19

    Alex19 Гуру

    Не знал, что по стандартам, надо посылать сигнал, когда терминал готов.

    Да интересно сделано. Сам так глубоко не вникал.

    Может быть проще тайм аут в программе, чем резать дорожку? Если программа позволяет.
     
  11. Витя

    Витя Гик

    Ну еще можно конденсатор засунуть в ножки reset - gnd. Тоже не будет перезагружаться.

    А мне так это безраницы, просто было интересно почему так все работает. Временно я сделал задержку пока но это пока арудино использую. Вот допишу программу на компьютере и потом буду делать само устройство и там просто у меня такого не будет. И даже USB наверное не будет, а будет Блютуз. Устройство делаю - подсветку для монитора как на телевизорах типа.
     
  12. Alex19

    Alex19 Гуру

    Да тоже вариант.

    Удачи!