Как изменить этот код, чтобы использовать последовательное событие для действия после возврата каретки?

В части кода, используемого с UNO, я хочу отправить число A и число B одновременно как A, B на плату Arduino, если есть возврат каретки. Итак, в данный момент в HyperTerminal, когда я набираю: 100,0,5, плата Arduino немедленно реагирует, x становится 100, а n становится 0,5. Следующие части относятся к чтению с последовательным событием:

void loop() {

      if (stringComplete){ 

      delay(1000);
      Mwrite(level);
      sendFrequency(n); 
      delay(100);  

      stringComplete = false;   

   } 
}

и в последовательном событии:

void serialEvent() {  

     while (Serial.available()) {

     slevel  = Serial.readStringUntil(',');
     Serial.read(); //следующий символ - запятая, поэтому пропустите его, используя этот
     x = Serial.readStringUntil(',');

     level = slevel.toInt();
     n = x.toDouble();
     stringComplete = true;  
  }  
}

Но я хочу, чтобы плата считывала последовательные данные только в том случае, если я нажимаю возврат каретки. Поэтому я должен ввести 100,1, а затем нажать возврат каретки, чтобы Arduino отреагировал на последовательные данные.

Как можно изменить этот код для достижения этой цели?

, 👍-1

Обсуждение

Забудьте serialEvent(). Это то, что Arduino *никогда* не должен был включать в API. Это идиотская функция, которая в реальности не имеет смысла. Помещение содержимого serialEvent() в loop() точно такое же (и часто гораздо более удобное)., @Majenko

https://majenko.co.uk/blog/reading-serial-arduino, @Majenko

SerialMonitor ничего не отправляет, пока вы не нажмете «Отправить». Рекомендуется выбрать новую строку в качестве дополнительного символа-разделителя при отправке. В дополнение к строке чтения Majenko: есть функция strtok, которую вы можете использовать., @DataFiddler

настроить терминал на отправку при вводе, а не каждый символ. кстати. readStringUntill удаляет терминальный символ из приемного буфера. и не должен ли ваш второй readStringUntil читать до '\ n'?, @Juraj

@ Маженко, нет, это не идиотизм, это просто неправильно поняли. Я признаю, что у него ограниченные варианты использования, но это может быть большим подспорьем. Например, это очень помогло при разработке моей [библиотеки радиоуправляемых самолетов](https://github.com/PowerBroker2/ArdUAV)., @P_B

Задумка может и имеет смысл, но реализация идиотская. Теперь, если бы они подключили его к прерыванию RX, это могло бы быть полезно. Как то это идиотизм. И я придерживаюсь этого слова., @Majenko


1 ответ


0

Есть несколько способов решить эту проблему. Самый простой способ сделать это — просто добавить еще одну строку в свой код.

static bool stringComplete = false;
String x;
String slevel;
static int level;
static int n;

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

void loop() 
{
  if (stringComplete)
  {
    Serial.println(level);
    Serial.println(n);   
    stringComplete = false;   
  } 
}

void serialEvent()
{
  while(Serial.available())
  {
    slevel  = Serial.readStringUntil(',');

    //Серийный.читать(); // <-- Вам не нужна эта строка. readStringUntil() будет читать ','

    x = Serial.readStringUntil(',');

    level = slevel.toInt();
    n = x.toDouble();
    Serial.readStringUntil('\r'); // <--------- Добавляем эту строку
    stringComplete = true;  
  }  
}

Но это, вероятно, неправильный способ сделать это. Во-первых, serialEvent() выполняется между loop(), то есть вот как это выглядит:

while(1)
{
    loop();
    serialEvent();
}

Таким образом, функция не будет вызываться во время последовательного события. Он просто выполняется сразу после loop(). Также readStringUntil() имеет время ожидания (по умолчанию: 1 с). Поэтому, если ваш символ «до» не появляется в течение одной секунды после вызова функции, он вернется с тем, что у него есть. Чтобы проверить это, просто введите один символ на вашем HyperTerminal, подождите хотя бы секунду и посмотрите результат.

В идеале вы должны обрабатывать входящий байт серийного номера следующим образом:

  • Проверить, доступен ли последовательный байт для чтения
  • Если есть, прочитайте один байт и сохраните его в буфере/строке. (Я не очень люблю переменные String, но в примере я буду использовать String, потому что вы использовали String)
  • Если байт, который вы только что прочитали, является разделителем (например, CR или '\r'), укажите в основном цикле, что строка завершена.
  • В основном цикле анализируется вся строка.

Вот как выглядит код с указанными выше пунктами:

static bool stringComplete = false;
String x;
String slevel;
static int level;
static int n;
String rxString = "";

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

void loop() 
{
  if (stringComplete)
  {
    // Разбираем rxString
    int index1 = rxString.indexOf(',');             // находит местоположение первого ,
    slevel = rxString.substring(0, index1);         // фиксирует первую строку данных
    int index2 = rxString.indexOf(',', index1 + 1); // находит местоположение секунды,
    x = rxString.substring(index1 + 1, index2);     // захватывает вторую строку данных

    level = slevel.toInt();
    n = x.toDouble();

    Serial.println(level);
    Serial.println(n);  

    // Сбросить строку
    rxString = ""; 
    stringComplete = false;   
  } 
}

void serialEvent()
{
  while(Serial.available())
  {
    // получаем новый байт:
    char inChar = (char)Serial.read();
    // добавляем его в rxString:
    rxString += inChar;
    // если входящий символ является возвратом каретки, указать основной цикл
    if (inChar == '\r') 
    {
      stringComplete = true;
    }
  }  
}
,