Arduinoはシリアルバッファオーバーフローをどのように処理しますか?


27

Arduinoはシリアルバッファオーバーフローをどのように処理しますか?最新の受信データまたは最も古い受信データを破棄しますか?バッファーは何バイト保持できますか?

serial 

回答:


13

ハードウェアシリアルポートの場合、HardwareSerial.cppで、特定のAVRで使用可能なRAMの量に応じてバッファーサイズが異なることがわかります。

#if (RAMEND < 1000)
    #define SERIAL_BUFFER_SIZE 16
#else
    #define SERIAL_BUFFER_SIZE 64
#endif

SoftwareSerial.hのソフトウェアシリアルポートの場合、受信バッファサイズ_SS_MAX_RX_BUFFは64バイトとして定義されます。どちらの場合も、キューがいっぱいになると受信データをキューに挿入しようとするのを停止するため、キューからデータを取得する方法に応じて、古いデータと新しいデータを混在させることができます。

理想的には、バッファがいっぱいにならないように、バッファを常にプロンプ​​ト方式で空にすることをお勧めします。問題がメインループをブロックしている他のコードに関連している場合は、タイマーと単純なステートマシンの実装をご覧ください。


Arduinoにデータを送信し、Arduino側にアクティブな「プル」データがない場合、バッファに収まらないほど多くのデータが到着すると破棄されるという印象を受けます。確認できますか?私は、データを保持するために利用可能なスペースが利用可能になるまで送信機がブロックすると単純に考えていました。
コルバン

すべてのコード(/ usr / share / arduino / hardware / arduino / core / arduino / HardwareSer‌ ial.cppの下)を調べたところ、ここで書いたことを確認できます。追加する唯一のことは、SRAMが2K(RAMEND> 1000)である場合、ステートメントがNanoまたはUnoで16ではなく常に64を使用することです。したがって、変更する場所となるリングバッファーのサイズを拡張する場合は、
SDsolar

5

受信中

HardwareSerialのソースから、着信バイトでリングバッファがいっぱいであることが検出されると、破棄されることがわかります。

inline void store_char(unsigned char c, ring_buffer *buffer)
{
  int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;

  // if we should be storing the received character into the location
  // just before the tail (meaning that the head would advance to the
  // current location of the tail), we're about to overflow the buffer
  // and so we don't write the character or advance the head.
  if (i != buffer->tail) {
    buffer->buffer[buffer->head] = c;
    buffer->head = i;
  }
}

Arduinoにデータを送信し、Arduino側にアクティブな「プル」データがない場合、バッファに収まらないほど多くのデータが到着すると破棄されるという印象を受けます。確認できますか?

はい、破棄されます。独自に実装しない限り、ソフトウェアまたはハードウェアのフロー制御はありません。

ただし、64バイトのバッファーを使用し、(たとえば)9600ボーでデータを受信すると、1.04ミリ秒ごとに1バイトを取得するため、バッファーがいっぱいになるのに66.6ミリ秒かかります。16 MHzプロセッサでは、バッファがいっぱいにならないように十分な頻度でバッファをチェックできるはずです。あなたが本当にしなければならないのは、すぐに処理したくない場合、HardwareSerialバッファから自分のバッファにデータを移動することです。

#if (RAMEND < 1000)1000バイト以上のRAMを搭載したプロセッサが64バイトのバッファを取得し、16バイトバッファを取得するRAMが少ないプロセッサを確認できます。


送信

書き込むデータは、同じサイズのバッファ(16または64バイト)に配置されます。バッファが次のバイトをシリアルポートから送信するための割り込みを待機しているコード「ブロック」をいっぱいにする場合に送信する場合。

割り込みがオフになっている場合、これは決して起こりません。したがって、割り込みサービスルーチン内でシリアル印刷を行いません。


私はあなたが桁違いに離れていると信じています:9600ボーで、あなたは〜0.1 msごとにバイトを得るので、バッファをいっぱいにするのに6.6 msしかかかりません。
エリックダンド

1
9600ボーでは、9600 ビット /秒になります。各バイトは10ビット(8データ+ 1スタートビット+ 1ストップビット)なので、1秒あたり960バイトになります。1/960 = 0.001042 s-1.04ミリ秒ごとに1バイトです。
ニックギャモン

ああ、もちろん、バイトではなくビット!修正していただきありがとうございます。
エリックダンド

だからニック、私にこれに答えてください:データロガーとしての入力を待っているser.readline()に座ってPythonを実行しているPiがあり、Arduinoによってシリアル経由でフィードされ、測定値を取得してタブでバッチとして送信する場合デリミタ、次にdelay(120000)を使用して、バッチが2分ごとに来るように、Python内臓はおそらく改行に遭遇するまで各文字をすぐに読み取り、その時点で行全体を戻り値として解放します。合計80文字を送信している場合でも、Arduinoのバッファサイズについて心配する必要はありません。それは良い仮定でしょうか?
–SDsolar

はい、このシナリオでは送信バッファサイズは重要ではありません。小さなバッファは送信を(少し)遅くしますが、とにかく長い遅延をしている場合は気にしません。
ニックギャモン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.