Wie geht der Arduino mit einem seriellen Pufferüberlauf um?


27

Wie geht der Arduino mit einem seriellen Pufferüberlauf um? Wirft es die neuesten eingehenden Daten oder die ältesten weg? Wie viele Bytes kann der Puffer aufnehmen?

serial 

Antworten:


13

Bei seriellen Hardware-Ports können Sie in HardwareSerial.cpp sehen, dass die Puffergröße abhängig von der auf dem jeweiligen AVR verfügbaren RAM-Größe variiert:

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

Für einen seriellen Software-Port in SoftwareSerial.h ist die Puffergröße des Empfängers _SS_MAX_RX_BUFFmit 64 Byte definiert. In beiden Fällen wird der Versuch, empfangene Daten in die Warteschlange einzufügen, abgebrochen, wenn sie voll sind, sodass Sie eine Mischung aus alten und neuen Daten erhalten können, je nachdem, wie Sie Daten aus der Warteschlange abrufen.

Im Idealfall sollte sichergestellt werden, dass der Puffer immer rechtzeitig geleert wird, um ein Füllen des Puffers zu vermeiden. Vielleicht werfen Sie einen Blick auf Timer und implementieren eine einfache Zustandsmaschine, wenn Ihr Problem mit anderem Code zusammenhängt, der die Hauptschleife blockiert.


Ich habe den Eindruck, dass, wenn ich Daten an das Arduino übertrage und auf der Arduino-Seite keinen aktiven "Puller" für Daten habe, wenn mehr Daten ankommen, als in den Puffer passen, diese verworfen werden. Kannst du das bestätigen? Ich war naiv davon ausgegangen, dass der Sender blockieren würde, bis Speicherplatz für die Daten verfügbar wurde.
Kolban,

Ich habe gerade den ganzen Code durchgesehen (unter /usr/share/arduino/hardware/arduino/core/arduino/hardwareserial.cpp) und kann bestätigen, was Sie hier geschrieben haben. Das einzige, was ich hinzufügen möchte, ist, dass, da der SRAM 2K (RAMEND> 1000) ist, die if-Anweisung auf einem Nano oder einem Uno immer 64 statt 16 verwendet. Wenn man also die Größe des Ringpuffers erweitern möchte, ist dies der Ort, an dem er geändert werden kann
SDsolar

5

Empfang

An der Quelle von HardwareSerial können Sie erkennen, dass ein eingehendes Byte verworfen wird, wenn es den Ringpuffer voll findet:

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;
  }
}

Ich habe den Eindruck, dass, wenn ich Daten an das Arduino übertrage und auf der Arduino-Seite keinen aktiven "Puller" für Daten habe, wenn mehr Daten ankommen, als in den Puffer passen, diese verworfen werden. Kannst du das bestätigen?

Ja, es wird verworfen. Es gibt keine Software- oder Hardware-Flusskontrolle, es sei denn, Sie implementieren Ihre eigene.

Mit einem 64-Byte-Puffer und Datenempfang bei (sagen wir) 9600 Baud erhalten Sie jedoch alle 1,04 ms ein Byte, und daher sind 66,6 ms erforderlich, um den Puffer zu füllen. Auf einem 16-MHz-Prozessor sollte es möglich sein, den Puffer häufig genug zu überprüfen, damit er nicht voll wird. Alles, was Sie wirklich tun müssen, ist, die Daten aus dem HardwareSerial-Puffer in Ihren eigenen zu verschieben, wenn Sie sie jetzt nicht verarbeiten möchten.

Sie können #if (RAMEND < 1000)anhand der Überprüfung feststellen, dass Prozessoren mit mehr als 1000 Byte RAM den 64-Byte-Puffer erhalten, während Prozessoren mit weniger RAM den 16-Byte-Puffer erhalten.


Senden

Daten, die Sie schreiben, werden in einem Puffer gleicher Größe (16 oder 64 Byte) abgelegt. Im Falle des Sendens, wenn der Puffer den Code füllt, "blockiert" das Warten auf einen Interrupt, um das nächste Byte über die serielle Schnittstelle zu senden.

Wenn Interrupts deaktiviert sind, geschieht dies niemals. Sie führen also keine seriellen Drucke innerhalb einer Interrupt-Serviceroutine durch.


Ich glaube, Sie haben eine Größenordnung weniger: Bei 9600 Baud erhalten Sie alle ~ 0,1 ms ein Byte, sodass Sie nur 6,6 ms benötigen, um den Puffer aufzufüllen.
Eric Dand

1
Bei 9600 Baud erhalten Sie 9600 Bits pro Sekunde. Da jedes Byte 10 Bits umfasst (8 Daten + 1 Startbit + 1 Stoppbit), erhalten Sie 960 Bytes pro Sekunde. 1/960 = 0.001042 s- das ist ein Byte alle 1,04 ms.
Nick Gammon

Ahh natürlich, Bits nicht Bytes! Danke für die Korrektur.
Eric Dand

Also Nick, bitte beantworte dies für mich: Wenn ein Pi mit Python an einer ser.readline () auf die Eingabe als Datenlogger wartet und von Arduino seriell gespeist und dann als Stapel mit Tab gesendet wird Delimeter, dann Verzögerung (120000) verwenden, damit die Stapel alle zwei Minuten eingehen. Die Python-Innereien lesen wahrscheinlich jedes Zeichen sofort ein, bis sie auf eine neue Zeile stoßen. An diesem Punkt gibt sie die gesamte Zeile als Rückgabewert frei. Also muss ich mir keine Sorgen um die Arduino-Puffergröße machen, auch wenn ich insgesamt 80 Zeichen sende, oder? Wäre das eine gute Annahme?
SDsolar

Ja, die Sendepuffergröße spielt in diesem Szenario keine Rolle. Ein kleiner Puffer würde das Senden (leicht) verlangsamen, aber wenn Sie trotzdem eine längere Verzögerung machen, ist es Ihnen egal.
Nick Gammon
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.