Не знаю в чём дело.

Тема в разделе "Arduino & Shields", создана пользователем Иван С, 19 июн 2012.

  1. Иван С

    Иван С Гик

    Ситуация следующая. Две меги2560 с Xbee модулями. Одна из них "пульт" с кучей кнопок, lcd и ethernet шилдом. Другая "приёмник/исполнитель" без обвеса (кроме Xbee).

    Пульт посылает команды:
    • COV00t0000
    • CCV00t0000
    1. Первый байт "C" показывает что пришла команда, также это может быть "R" - запрос или "S" - ответ на запрос.
    2. Два следующих байта "OV" или "CV" - команда, которую нужно выполнить
      1. "OV" - подать сигнал "HIGH" на выход...
      2. "CV" - подать сигнал "LOW" на выход...
    3. Далее два байта - индекс, под которым в массиве хранится pin, на который должно послать сигнал
    4. Далее "t" (time) - в общем не несущий смысла разделитель, но если его нет - команда перестанет выполняться и вылетит ошибка
    5. После чего четыре байта - время, в течение которого будет посылаться сигнал "HIGH" или "0" - тогда этот сигнал будет посылаться всегда.
    Исполнитель, приняв команду (т.е. "C"), правильно определяет OV и CV, а приняв "00" (индекс) переводит его из String в int (str.toInt()) и получает - 0. Тоже со временем.

    Всё работает, но получив вторую команду он уже из "00" получает - 000. Тоже со временем. При этом команда не выполняется.

    Я записал принятые команды в файл на mSD, вот что вышло:
    CCV0t0 - первая команда
    COV000t0000 - вторая команда (откуда взялся третий ноль в индексе я ума не приложу)
    Хотя все числа были перевидены в Int...
    Все последующие команды также не выполняются, хотя если пульт держать включённым, а исполнитель перезапустить, то первая команда опять выполнится как надо, а остальные опять "пролетят". Значит проблема в исполнителе, но где?
    Код формировки запроса на пульте:
    Код (Text):
    void valve(int valve, boolean open_valve, int time = 0){ //Изменяет состояние
      lcd.clear();
      lcd.print("\x4F\xB2\x70\x61\xB2\x6F\xBF\xBA\x61""..."); //Обработка...
      String query = "C";
      if(open_valve)
        query += "OV";
      else
        query += "CV";
     
      if(valve < 10)
        query += "0" + String(valve);
      else
        query += String(valve);
     
      query += "t";
     
      if(time < 10)
        query += "000" +String(time);
      else if(time >= 10 && time < 100)
        query += "00" + String(time);
      else if(time >= 100 && time < 1000)
        query += "0" + String(time);
      else if(time >= 1000 && time < 10000)
        query += String(time);
      Serial.print(query);
     
     
      prepare_lcd("valve select");
      mod = "valve select";
    }
    Код обработки команды:
    Код (Text):
    void loop(){
     
     
      if(Serial.available() > 0){
        File f = SD.open("test.txt", FILE_WRITE);
        serial_hendler(f);
        f.close();
      }
     
     
    }
     
    void serial_hendler(File f){
      char input_byte = Serial.read();
      f.print(input_byte);
      if(input_byte == 'C')
        command_handler(f);
    }
     
    void command_handler(File f){
      boolean command_cot = false;
      boolean valve_open;
      String command = "";
      command += char(Serial.read());
      command += char(Serial.read());
      f.print(command);
      if(command == "OV"){
        valve_open = true;
        command_cot == true;
      }
      if(command == "CV"){
        valve_open = false;
        command_cot == true;
      }
      if(command == "OV" || command == "CV"){
        String str_valve = "";
        str_valve += char(Serial.read());
        str_valve += char(Serial.read());
        int valve = str_valve.toInt();
        f.print(valve);
        char t = char(Serial.read());
        if(t == 't'){
          f.print(t);
          String str_time = "";
          str_time += char(Serial.read());
          str_time += char(Serial.read());
          str_time += char(Serial.read());
          str_time += char(Serial.read());
          int time = str_time.toInt();
          f.print(time);
          valve_control(valve, valve_open, time);
        }
        else{
       
        }
      }
    }
     
    void valve_control(int valve, boolean VO, int time){
      int valve_pin = valves[valve];
      valve_open[valve] = VO;
      valve_time[valve] = time;
      if(time > 0)
        time_is_on = true;
      digitalWrite(valve_pin, VO);
    }
     
  2. nailxx

    nailxx Официальный Нерд Администратор

    Предположу, что дело вот в чём. При включении приёмника он пару секунд тупит и поэтому в Serial успевает скопиться полные 10 байт сообщения и он их прожёвывает как вы и хотели.

    Далее. Приходит один байт. Вы попадаете в serial_hendler (handler, кстати), пишите байт в файл, идёте в command_handler, пытаетесь считать пару следующих байт, а фигушки — их ещё нет; функция возвращается ни с чем. Далее подходит второй байл, вы опять в serial_hendler, байт != 'C' — вы печатаете его в файл и выходите и так далее байт за байтом.

    В общем, попробуйте вместо:

    if(Serial.available() > 0)

    использовать

    #define MESSAGE_LENGTH 10
    if(Serial.available() >= MESSAGE_LENGTH)
     
    Иван С нравится это.
  3. Иван С

    Иван С Гик

    Точно! В это то и проблема. Я и сам хотел сделать ожидание с помощью пустого while, но из-за ошибки я подсознательно отложил это дело на потом :)

    Спасибо, nailxx.