Проблема с очисткой строки, считанной из последовательного буфера

Я пытаюсь переместить шаговый двигатель, когда на Arduino Mega 2560 отправляется определенная команда. Эта команда считывается посимвольно и сохраняется в строковой переменной. Всякий раз, когда отправляется новая команда, должно выполняться действие. Однако этого не происходит, и я считаю, что проблема в чтении отправленной команды. Пробовал очищать символьные и строковые переменные, но безрезультатно. Скетч должен запускать цикл, который перемещает двигатель по часовой стрелке или против часовой стрелки в соответствии с отправленной командой, которая может быть "crx*" для по часовой стрелке или "clx*" против часовой стрелки, где "*" – критерий остановки чтения символов. Любые предложения, что делать? Скрипт:

void(* resetFunc) (void) = 0;//Сброс хода

// Шаговый двигатель X
const int stepPinX = 2; //X.ШАГ
const int dirPinX = 5; // Х.КАТАЛОГ
const int pinEnable = 8;

// Чтение строки
char c;
String readString; //основная захваченная строка

// Единичные шаги
double av_len = 1.029; //Средняя длина
double interval;
int cnt_steps = 0;
const int num_d = 200;//параметризованный шаг
int fact = int(num_d / av_len);
int unit_len = fact * 1;//единица длины (1 мм)

void setup()
{
  // Устанавливает контакты как выходы
  pinMode(stepPinX, OUTPUT);
  pinMode(dirPinX, OUTPUT);
  pinMode(pinEnable, OUTPUT);

  digitalWrite(pinEnable, HIGH);//блокировка драйвера на щите ЧПУ

  Serial.begin(115200);
  Serial.setTimeout(1);
  
  while (1) {
    
    while ( (Serial.available() == 0) )
    {

    }

    if (Serial.available())  {
      c = Serial.read();  //получает один байт из последовательного буфера
      //Serial.println(readString);
      if (c == '*') {
        Serial.println(readString);//тестовый ответ
        if (readString == "crx") {
          cnt_steps = cnt_steps + 1;
          Serial.println(cnt_steps);
          digitalWrite(pinEnable, LOW);
          digitalWrite(dirPinX, HIGH);
          for (int x = 0; x < unit_len; x++) {
            digitalWrite(stepPinX, HIGH);
            delayMicroseconds(500);
            digitalWrite(stepPinX, LOW);
            delayMicroseconds(500);
          }
           
        }
        else if (readString == "clx") {
          cnt_steps += -1;
          Serial.println(cnt_steps);
          digitalWrite(pinEnable, LOW);
          digitalWrite(dirPinX, LOW);
          for (int x = 0; x < unit_len; x++) {
            digitalWrite(stepPinX, HIGH);
            delayMicroseconds(500);
            digitalWrite(stepPinX, LOW);
            delayMicroseconds(500);
          }
        }
         digitalWrite(pinEnable, HIGH);//блокировка драйвера на щите ЧПУ
         c = (char)0;
         Serial.flush();
         readString = "";
         //resetFunc();
      }

      else {
        readString += c; // делает строку readString

      }
    }
  }
}


void loop() {

}

, 👍0

Обсуждение

Что вы отправляете в свой скетч? Что он печатает обратно на последовательный порт?, @Edgar Bonet

@EdgarBonet Я отправляю команды "crx*" для вращения по часовой стрелке и "cry*" против часовой стрелки, а "*" является критерием остановки чтения символов. Скетч не должен ничего печатать, но я попросил его распечатать отправленные команды, чтобы проверить правильность чтения, @Yan Araújo

1. Этот скетч не понимает "cry*": он ожидает либо "crx*", либо "clx*". 2. Насчет «_Скетч ничего не должен печатать_»: Должен. Тут и там есть Serial.println(). Позвольте мне еще раз спросить: что он печатает в последовательный порт?, @Edgar Bonet

@EdgarBonet Не обращайте внимания на «крик*». Это была опечатка. Правильным является "clx*". При получении одной из вышеупомянутых команд скетч должен выполнить циклы, содержащиеся в условиях, как показано в скрипте. Serial.println() предназначен исключительно для того, чтобы убедиться, что выполняется последовательное чтение символов. Можно комментировать. В зависимости от условий скетч воздействует на «цифровые порты» 2, 5 и 8 через «петли»., @Yan Araújo

@EdgarBonet Что происходит, так это то, что скетч выполняет «циклы» только после того, как «первая команда» отправляется через «последовательный». Если я попробую "второй раз", ничего не произойдет. Это как если бы последовательное чтение не соответствовало ни одному из условий "crx*" или "clx*"., @Yan Araújo

Как вы отправляете команды на скетч? Вы используете последовательный монитор Arduino? Если да, то настроили ли вы окончание строки?, @Edgar Bonet

@EdgarBonet Проблема в конце строки. Ваше предположение было правильным. Большое спасибо!, @Yan Araújo


2 ответа


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

1

При отправке текстовых команд на Arduino обычно определяется «линейный протокол»: каждая команда передается как одна строка, с окончанием строки, означающим конец команды. Общая линия окончания: возврат каретки (CR = '\r' = 0x0d = 13), перевод строки (LF = '\n' = 0x0a = 10) и последовательность CR+LF.

Монитор последовательного порта Arduino поддерживает это соглашение. автоматическое добавление строки, заканчивающейся при нажатии «Отправить». Эта линия окончание может быть настроено на один из следующих вариантов:

  • Нет окончания строки
  • Новая строка (означает «перевод строки»)
  • Возврат каретки
  • Оба NL и amp; CR (но на самом деле CR отправляется перед LF)

В вашем случае вы решили использовать '*' в качестве завершения команды. характер. Чтобы это работало, вы должны выбрать «Без окончания строки» и добавить «*» явно указывает на команду. В качестве альтернативы вы можете рассмотреть изменить свой скетч так, чтобы он ожидал '\r' или '\n', что является более стандартный способ завершения команды.

,

0

В дополнение к хорошим отзывам, которые вы уже получили, я предлагаю это.

Что касается Arduino, знайте разницу между массивами String string и char — об этом много, например, https://forum.arduino.cc/t/string-vs-string-vs-char-arrays-correct-approach/537468 . Многие не хотят иметь дело с капризами String, но их использование может быть удобным.

Запустите этот код:

String readstring = "xxx";

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

void loop() {
  if (Serial.available()) {
    readstring = Serial.readStringUntil('/n');
    Serial.print(readstring);
    Serial.println(" received");
    if (readstring.equals("crx")) {
      // двигаться против часовой стрелки
      Serial.println("moving counter clockwise");
      // против часовой стрелки() <-- ваша функция
    }
    else if (readstring.equals("clx") ) {
      // двигаться по часовой стрелке
      Serial.println("moving clockwise");
      // по часовой стрелке() <-- ваша функция
    }
    else {
      // неверная команда
      Serial.println("Bad command received - no action");
      // badcommand() <-- ваша функция
    }
  }
}

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

Обратите внимание, что для последовательного монитора установлено значение "без окончания строки". Завершающий символ '/n' предоставляется вашим вводом в монитор последовательного порта. Он будет делать то, что вы хотите, но опять же, многие советуют вам держаться подальше от String.

,