Очистить существующий массив при получении новой последовательной команды

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

Я получаю последовательные данные с консоли и сохраняю их в массиве символов под названием «данные».

Затем, когда я отправляю новое консольное сообщение в Arduino, я хочу, чтобы он очистил существующий массив «данных» и сохранил в этом массиве только новые данные.

Я не совсем понимаю, что не так с моим кодом: я считаю, что эти вложенные операторы Serial.available() не работают, но у меня нет идей, как исправить код.

Данные правильно сохраняются в Arduino, но новая строка объединяется со старой.

int count = 0;
char data[30];
boolean dataComplete = false;

void setup() {
  Serial.begin(9600);
}


void loop() {

  if (Serial.available() > 0){
    if (dataComplete == true){
    Serial.println("There is data already, clearing...");
    char data[30];
    dataComplete = false;
  }
    if (dataComplete == false){
      Serial.println("New command, collecting...");
      while (Serial.available()>0){
        char character = Serial.read();
        data[count] = character;
        count++;
      }
     dataComplete = true;
    }
  }
  Serial.print("Command received: ");
  Serial.println(data);
  delay(1000);
}

Заранее спасибо!

, 👍7


5 ответов


Лучший ответ:

18

Чтобы очистить массив, вы должны сделать следующее:

for( int i = 0; i < sizeof(data);  ++i )
   data[i] = (char)0;

или

memset(data, 0, sizeof(data));

, который делает то же самое, используя библиотечную функцию.

Однако, поскольку строки символов (здесь не относящиеся к объектам String) завершаются нулевым байтом, обнуляться необходимо только первый байт:

data[0] = (char)0;

сделаю это.

,

1

Вероятно, это не делает то, что вы намеревались сделать:

Serial.println("There is data already, clearing...");
char data[30];

В выводе говорится, что вы очищаете массив data, но вы этого не делаете. Фактически вы объявляете новую локальную переменную с именем data, которая не зависит от глобальных data, которые вы уже объявили в верхней части вашего файла. программа. Локальные переменные существуют только в той области, в которой они объявлены (внутри ближайшего к ним { ).

Вместо этого ваша переменная count отслеживает объем полученных вами данных. Поэтому, возможно, сделайте следующее:

Serial.println("There is data already, clearing...");
count = 0;

Это не единственное, что может привести к неожиданной работе вашей программы, но это должно, по крайней мере, решить проблему, указанную в вашем вопросе.

,

Также для данных необходим нулевой терминатор: добавьте data[count]='\0'; после dataComplete = true;, @Craig

Да, это правда, но более серьезная проблема заключается в том, что у отправителя нет другого способа указать конец передачи данных, кроме как приостановить ее. А поскольку это последовательный файл, между *каждым* передаваемым символом будет достаточно длинная пауза., @Greg Hewgill

Спасибо вам обоим, ребята. Мой код был неправильным, и его изменение на «count = 0» сработало. Я также добавил разделитель, обозначающий конец команды ввода, и теперь он работает так, как задумано. Однако единственным способом очистить массив «данные» было использование цикла for, как указано @JRobert: таким образом новые команды работают, даже если они короче старых., @squeck


2

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

Фиксированный код:

int count = 0;
char data[30];
boolean dataComplete = false;

void setup() {
  Serial.begin(9600);
}

void loop() {
  if (Serial.available() > 0){
    if (dataComplete == true){
      Serial.println("There is data already, clearing...");
      char data[30];
      dataComplete = false;
    }
    if (dataComplete == false){
      Serial.println("New command, collecting...");
      while (Serial.available()>0){
        char character = Serial.read();
        data[count] = character;
        count++;
      }
     dataComplete = true;
    }
  }
  Serial.print("Command received: ");
  Serial.println(data);
  delay(1000);
}

Кроме того, кажется, что он печатает «Команда получена:» на каждой итерации, независимо от того, есть ли новые данные или нет (хотя это может быть запланированной функцией).

Как уже упоминалось, вы не очищаете переменную, а просто создаете новую. Чтобы устранить эту проблему, вам потребуется очистить и сбросить count. Однако простой сброс счетчика не сработает, если вторая команда короче предыдущей.

Кроме того, зачем вы усложняете код переменной dataComplete? Я упростил код ниже:

int count = 0;
char data[30];
boolean dataComplete = false;

void setup() {
  Serial.begin(9600);
}

void loop() {
  if (Serial.available()){
    Serial.println("New command, collecting...");
    count = 0;
    data[] = "";
    while (Serial.available()){
      char character = Serial.read();
      data[count] = character;
      count++;
    }
  }
  Serial.print("Command received: ");
  Serial.println(data);
  delay(1000);
}
,

0

Чтобы рассказать о сути вопроса и о том, чего пытался достичь автор.

Ни один из этих кодов на самом деле не работает в целом. Данные будут перезаписаны и будут продолжать непрерывно работать в цикле... в любом случае, вот рабочий пример исходного кода.

Я предпочитаю этот метод очистки массива:

    for( int i = 0; i < sizeof(data);  ++i )
    data[i] = (char)0;

Вот рабочий пример. (Обязательно выберите «Возврат каретки» на последовательном мониторе)

    char message[32];
    uint8_t incomingByte = 0; 
    uint8_t BufferPos = 0;
    int clearbyte = 0;


    void setup() {
    Serial.begin(9600);
    Serial.println("\n String conversion testing");

    }

    void loop() {

       if (BufferPos >= 32) {
              Serial.print("Buffer Full\n");
              BufferPos = 00;
              incomingByte = 0;

       }  

      if (Serial.available()) {
             incomingByte = Serial.read();
             message[BufferPos++]= incomingByte;   

         switch(incomingByte)
      {
           case '\n':
           case ' ':
             break;
           case '\r':
              Serial.println(message); 

          for( int i = 0; i < sizeof(message);  ++i )
         message[i] = (char)0;
              BufferPos= 0;
              incomingByte= 0;

      }
      }
    }
,

0

Я прочитал все комментарии по этому вопросу, но все коды оказались настолько многословными. После этого я создаю код с простыми функциями и меньшим количеством строк. в данном случае, я думаю, этот код будет работать нормально

если вы установили скорость передачи данных ниже 115200, необходимо добавить задержку() для сохранения сообщения в массив символов

void loop() {
    char data[255];
    uint8_t k = 0;
    while (Serial.available()) {
        data[k] = Serial.read();
         k++;
    }
    for (int i = 0; i < k; i++) {
        Serial.print(data[i]);
        data [i] = '\0';
    }
    //delay(50);
}
,

char data[] = {}; даст вам массив нулевой длины. Попытка поместить в него данные — плохая идея., @Nick Gammon

Я согласен с @NickGammon. Пожалуйста, отредактируйте свой ответ, заменив «Я думаю... будет работать нормально» на однозначное да/нет после того, как вы протестируете код., @MichaelT

@NickGammon спасибо за исправление, я пересматривал свой код, @Ashif Riady