内部ループがtrueの場合でも、voidループは実行されます。

ボタンがクリックされたときにLED_ONまたはLED_OFFを送信する簡単なモバイルアプリケーションを作成しました。以下のコードでは、whileループは実行中に完全には完了していませんが、コントローラはvoid loop()に行きそこから継続しています。

char command;
String my_final="LED_OFF";
#define led 9

void setup(){
  Serial.begin(9600);
  pinMode(led, OUTPUT);
  Serial.println("ready");
}

void loop(){
  if(Serial.available() > 0){
    my_final = "";
    while(Serial.available() > 0){
      command = (byte)Serial.read();
      my_final += command;
      Serial.println("test");
    }
    Serial.println(my_final);
    }

  if(my_final == "LED_ON"){
    Serial.println(my_final);
    analogWrite(led, 255);
    my_final == "LED_ON";
  }

  if(my_final == "LED_OFF"){
    Serial.println(my_final);
    analogWrite(led, 0);
    my_final == "LED_OFF";
  }
}

私はブルートゥースからの新しい入力を受け入れるためにこれをしなければならないので、主な問題は my_final = "" で起こります。私はこの問題を回避する方法を見つけることができないようです。

編集

これは私がシリアルモニタに入ってくるものです。 テストLテストEテストDテスト_テストOテストN

5
追加された 編集された
ビュー: 1
ru de
おそらくあなたはあなたの質問の中でシリアルモニタに何が入っているのか を述べるべきです。現在のところ、あなたの質問は、実行が while ループから飛び出しているように見えますが、これはシリアルモニタでは見ることができません。
追加された 著者 Dmitry Grigoryev,
あなたがあなたの質問に書いていることはほとんど不可能です。デバッガの中で、条件 Serial.available()がまだ真のままで実行が while ループを終了することを本当に見たことがありますか?
追加された 著者 Dmitry Grigoryev,
whileループが完全に完了したことをどのようにしてわかりますか?
追加された 著者 immibis,
my_final == "LED_ON"; とは何ですか。 ( if(my_final == "LED_ON"){} ブロックの末尾、 OFF も同様)
追加された 著者 AaronD,
私はこれまでに何らかの理由で使用していた2行を削除するのを忘れていました。
追加された 著者 Dylan,
これがシリアルモニタに入ってくるものです。テストLテストEテストDテスト_テストOテストN
追加された 著者 Dylan,

4 答え

シリアル通信は一度に1バイトずつデータを送信します。あなたのコードは次のバイトが受け取られる前に1バイトを読んで処理するのに十分速いです。

これには多くの解決策がありますが、遅延を使用するのは適切ではありません。

各コマンドの最後にマーカー文字を送ることができます。 LED_ON!そうすれば、感嘆符が表示されるまで、配列に文字を追加し続ける必要があることがわかります。マーカーの一般的な候補は改行文字です。

他の解決策は、全てのコマンドが確実に同じ長さ(例えば6バイト)を有するようにすることである。それから、あなたはとてもたくさんの文字を受け取るまで単に待つことができます。

if(Serial.available() >= 6) ...

2番目の解決策では、1バイトを失うと、再同期するまでコマンドを正しく受け取れなくなります。再同期するために、例えば、不完全なコマンドがあまりにも長くそこにある場合、タイムアウト後に Serial の内容を捨てることができます。

9
追加された
もう1つのオプション:文字を一度に1つずつバッファーにシフトし、新しい文字ごとに最も古い文字をドロップして、バッファーの内容が有効なコマンドであるかどうかを確認します。または1文字のコマンドを使用してください。
追加された 著者 Rhys,
もちろん、それも可能です。ただし、再同期アルゴリズムはまだ必要です。
追加された 著者 Dmitry Grigoryev,
循環バッファを使用する@Julesでは、コマンドにサブストリングとして他のコマンドを含めることはできません。
追加された 著者 Dmitry Grigoryev,
より拡張可能なプロトコルは、メッセージの長さをエンコードするために最初の数バイト(最大予想コマンド/メッセージ長に応じて1から4)を予約することです。それからあなたのアルゴリズムは基本的に「メッセージサイズを読む - >メッセージを読む」です。
追加された 著者 Orgmo,

@9600 Baudrate, you are receiving data at 10 bits per millisecond. One character is 8 bits + start and stop bits in a frame. You are reading the buffer faster than it. So a simple solution would be to put a delay of > 1 ms or so after serial read(), inside the loop.

5
追加された
Serial.available()== 0 の場合、 read()の後に delay(1)するだけで、バッファオーバーフローを回避できます
追加された 著者 My name is Jeff,
@MITURAJ私は実際には他の何かを意味しました。コンピュータのCOMポートに "LED_OFF"のような文字列を書いても、すべての文字が遅滞なく送信されるという保証はありません。 UART ISRが最優先されていないマイクロコントローラにも同じことが言えます。
追加された 著者 Dmitry Grigoryev,
これはおそらくOPが問題の原因を確認するために試みることができる最も簡単なことです。しかし長期的には、私はそれをお勧めしません。遅延ベースのコードが失敗する可能性がある方法はたくさんあります...
追加された 著者 Dmitry Grigoryev,
はい本当...連続したデータストリームでより高いボーレートで動作しているときデータ損失が発生する可能性があります...
追加された 著者 msb,
うんその場合のバッファオーバーフロー。同意した。
追加された 著者 grongor,

改行までのバッファリングは次のようになります(私のarduinoのコードは少し錆びているので、単純なエラーはご容赦ください - アルゴリズムは正しいはずです)。

finished = false;
command = "";
while (!finished) {
   if (Serial.available() > 0) {
      c = (byte)Serial.read();
      if (c == '\n') {
         finished = true;
      }
      else {
         command += c;
      }
   }
}

このループは単に文字を読み続けてこれらの文字を変数commandに追加するだけです。

これは、通信リンクが完璧であると仮定しています、それはそれが文字を落としたり、壊したりしないということです。これをより堅牢にするために、コマンドを受け取る時間が長すぎないことを確認するためにチェックインを入れることができます。

また、それぞれのコマンドにack応答またはハァッ応答することもできます。何が起こっているのかをサーバーに知らせる(nack)応答。

ハッピーメイキング!

1
追加された

着信データストリームが次のようになったときに何が起こりますか。

LE..Td..D_O..Td..N?

Td is a random small delay.

If your while(Serial.available() > 0){ is faster than Td, you will have reset my_final = ""; with only LE in it. Meaning, next you receive D_O, and then you reset it again.

0
追加された
@ ganeshvickyいいえ、遅れてシリアルポートを読むことができません。 \ n を受け取るまでバッファする必要がありますが、それでも Serial.available()をポーリングする必要があるので、何かを考え出す必要があります。
追加された 著者 Jeroen3,
@ganeshvicky改行までバッファする。
追加された 著者 Jeroen3,
あなたはdelay()関数を使うということですか?申し訳ありません。
追加された 著者 Dylan,
まさにそれがここで直面している問題です。これを克服する方法はありますか?
追加された 著者 Dylan,