Ардуино и интерфейс управления

Тема в разделе "Arduino & Shields", создана пользователем kanibekasset, 29 апр 2014.

  1. kanibekasset

    kanibekasset Нуб

    Всем привет. Хочу написать интерфейс для управления для Ардуино, есть 2 варианта: Qt или PHP.

    Могу передать одно значение для одной переменной, но двум не получается. Как быть?
    Например: хочу передать 25 и 50 двум переменным, которые будут использоваться в условиях....
     
  2. Витя

    Витя Гик

    А что именно не получается? Послать? Прочитать?

    Чтение в Арудине:
    Код (Text):

    void loop()
    {
      if (Serial.available() >= 2)
      {
        a1 = Serial.read(); // первая переменная
        a2 = Serial.read(); // вторая переменная
      }
    }
     
    еще можно сразу прочесть в массив:
    Код (Text):

      uint8_t a[2];
      ...
      Serial.readBytes((char *)a, 2); // в a[0] первая переменная, а в a[1] вторая
     
     
  3. Mitrandir

    Mitrandir Гуру

    Не очень понято
    Я как понял он хочет на компе данный с ардуины зачитать, ибо в дуню ни куТе ни пхп не запихнуть
     
  4. kanibekasset

    kanibekasset Нуб

    обе переменные кажись будут хранить последнее значение передаваемое на порт, нет? А мне нужно что бы, две переменные могли сохранить совершенно разные цифры. По Вашему совету пробовал, не получилось. (
     
  5. kanibekasset

    kanibekasset Нуб

    как раз таки наоборот хочу сделать, стало быть на ардуино через интерфейс.
     
  6. geher

    geher Гуру

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

    Возможно, проблема в том, что передаваемые значения получаются размером больше байта, то это надо учесть и использовать для приема и передачи сущности одинакового размера.
    Для приема двух двухбайтовых переменных придется сделать что-то вроде
    int a[2];
    ...
    Serial.readBytes((char *)a, 4); // в a[0] первая переменная, а в a[1] вторая

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

    Другая проблема, которая может возникнуть - синхронизация передачи и приема данных.
    Может получиться, что в первую переменную будет попадать значение для второй, а во вторую для первой. Или случится переполнение буфера, поскольку ардуина не будет успевать забирать данные по какой-то причине.
    Чтобы этого избежать надо обрамлять передачу какими-то характерными посылками. Потом ожидать в потоке признак начала, читая байт за байтом, и только потом читать значения переменных.
     
    Mitrandir нравится это.
  7. kanibekasset

    kanibekasset Нуб

    Вы не сталкивались с такими проблемами?

    Последний абзац как можно реализовать? Я понятия не имею пока)

    До этого передавал два значения и как Вы описывали две переменные моментами принимали не свои значения (
     
  8. Витя

    Витя Гик

    А покажите код который отправляет у вас данные?
     
  9. geher

    geher Гуру

    Я передавал по последовательному порту большое количество разных данных. Вроде все передавалось нормально. Оформлял как передачу буфера, скармливая в качестве буфера при приеме и передаче структуру с данными.

    Примерно так.
    Со стороны ардуины:
    Код (Text):
    void loop()
    {
      struct t_data2 {
        uint8_t header;
        uint8_t a1;
        uint8_t a2;
        uint8_t checksumm;
      } data2;
      if (Serial.available())
      {
        int rc=ReadData((char*) &data2, sizeof(struct t_data2));
        if (rc==siztof(struct t_data2))
        {
          a1 = data2->a1; // первая переменная
          a2 = data2->a2; // вторая переменная
        }
      }
    }nt ReadData(char *buf, byte bufsize)
    {
      byte i=0;
      unsigned long startmillis=millis();
      //первый байт
      while ((millis()-startmillis<100)&&(i<bufsize)) // отрабатываем вариант с нулевой длиной буфера и таймаут (100 мс)
      {
        if (Serial.available()) {
          buf[0]=Serial.read();
          if (buf[0]==0xFF) // проверяем первый байт - индикатор начала передачи, должен быть 0xff
          {
            i++;
            break;
          }
        }
      }
      if (i<1) return(0); // если так и не дождались символа начала передачи - выход

    // чтение оставшихся байт
      while ((millis()-startmillis<100)&&(i<bufsize))
      {
        if (Serial.available()) {
          buf[i]=Serial.read();
          i++;
        }
      }
      if (i<bufsize) retun(-1); // считали не все, значит посылка была с ошибкой
      // проверяем что-то вроде контрольной суммы.
      int crc=0;
      for ( int j=0; j<i-1; j++ ) crc+=buf[j];
      if (buf[i-1]!=crc) retun(-1); // сумма не совпала, значит посылка была с ошибкой
      return(i);
    }
    Соответственно, с другой стороны нужно заполнить и записать в порт такую же структуру с таким же выравниванием. В первом поле признак начала передачи, дальше поля для значений переменных, в последнем поле сумма всех предшествующих полей структуры - что-то вроде контрольной суммы.
    Eсли я правильно понял, то по умолчанию для ардуины выравнивание структур идет на байт, если не прав, поправьте.
     
  10. kanibekasset

    kanibekasset Нуб

    Код (Text):
    <?php
    $num = 0;
    $numb = 0;
    if(isset($_POST['port'])){
        $num = (int)$_POST['port'];
        exec("mode com5: BAUD=9600 PARITY=n DATA=8 STOP=1 to=off dtr=off rts=off");
        $fp = fopen('COM5:', 'wb');
        if($fp){
            sleep(0.2);
            $_port = sprintf('%d',$num);
            fwrite($fp,$_port);
            echo 'SEND: '.$_port;
            sleep(0.2);
            fclose($fp);
        }
    }


    ?>
    <form action="" method="POST">
    <input type="text" name="port" value="<?php echo htmlspecialchars($num); ?>" />
    <input type="submit" />

    </form>
    Вот код, с помощью которого я отправляю значения.

    Вопрос, можно но ли передать не символ, а символы, то есть я передаю с веб хоста 456, а ардуино это читает как 4, 5 и 6 отдельно. Как это можно решить?
     
  11. geher

    geher Гуру

    Если я правильно понял, то число просто передается строкой.
    Чтобы его принять, надо всего лишь прочитать строку. Лучше ее ограничить символами начала и конца, чтобы на принимающей стороне обрабатывались только корректные посылки, например " 456\n" (т.е. пробел - признак начала, перевод строки - признак завершения).
    Для считывания ардуиной можно воспользоваться методом readBytesUntil класса Serial, в котором задается символ окончания строки.
    Можно самостоятельно считывать символ за символом, ожидая символ начала, затем помещать в буфер символы посылки, пока не встретится символ завершения.
    А потом остается только конвертировать содержимое буфера в число, например, примерно так,
    res=0;
    for (int i=0;i<len;i++) res=(res*10)+(s-0x30);