Jak Arduino obsługuje przepełnienie bufora szeregowego?


27

Jak Arduino obsługuje przepełnienie bufora szeregowego? Czy wyrzuca najnowsze przychodzące dane czy najstarsze? Ile bajtów może pomieścić bufor?

serial 

Odpowiedzi:


13

W przypadku sprzętowych portów szeregowych można zobaczyć w HardwareSerial.cpp, że rozmiar bufora różni się w zależności od ilości pamięci RAM dostępnej w danym AVR:

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

W przypadku portu szeregowego oprogramowania w SoftwareSerial.h rozmiar bufora odbiornika _SS_MAX_RX_BUFFjest zdefiniowany jako 64 bajty. W obu przypadkach przestaje próbować wstawiać odebrane dane do kolejki, gdy jest pełna, dzięki czemu można uzyskać mieszanie starych i nowych danych w zależności od sposobu pobierania danych z kolejki.

Najlepiej byłoby upewnić się, że bufor jest zawsze opróżniany w szybki sposób, aby uniknąć zapełnienia bufora. Być może spójrz na liczniki czasu i implementację prostej maszyny stanów, jeśli twój problem jest związany z innym kodem blokującym główną pętlę.


Odnoszę wrażenie, że jeśli przesyłam dane do Arduino i nie mam aktywnego „ściągacza” danych po stronie Arduino, to jeśli pojawi się więcej danych, niż można zmieścić w buforze, zostaną one odrzucone. Czy możesz to potwierdzić? Naiwnie zakładałem, że nadajnik będzie blokował, dopóki nie będzie dostępna przestrzeń do przechowywania danych.
Kolban

Właśnie przejrzałem cały ten kod (pod / usr / share / arduino / hardware / arduino / core / arduino / HardwareSer‌ ial.cpp) i mogę potwierdzić, co tu napisałeś. Dodam tylko, że skoro SRAM ma 2K (RAMEND> 1000), to jeśli instrukcja zawsze użyje 64 zamiast 16 na Nano lub Uno. Więc jeśli ktoś chciałby powiększyć rozmiar bufora pierścieniowego, byłby to miejsce na jego zmianę
SDsolar

5

Odbieranie

Ze źródła HardwareSerial widać, że jeśli przychodzący bajt znajdzie pełny bufor bufora, zostanie odrzucony:

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

Odnoszę wrażenie, że jeśli przesyłam dane do Arduino i nie mam aktywnego „ściągacza” danych po stronie Arduino, to jeśli pojawi się więcej danych, niż można zmieścić w buforze, zostaną one odrzucone. Czy możesz to potwierdzić?

Tak, zostanie odrzucony. Nie ma kontroli oprogramowania ani sprzętu, chyba że wprowadzisz własne.

Jednak przy 64-bajtowym buforze i odbiorze danych z (powiedzmy) 9600 bodów, dostajesz jeden bajt co 1,04 ms, a zatem wypełnienie bufora zajmuje 66,6 ms. W przypadku procesora 16 MHz powinieneś być w stanie często sprawdzać bufor, aby się nie zapełniał. Wszystko, co naprawdę musisz zrobić, to przenieść dane z bufora HardwareSerial do własnego, jeśli nie chcesz ich teraz przetwarzać.

Z #if (RAMEND < 1000)kontroli wynika, że ​​procesory z ponad 1000 bajtami pamięci RAM otrzymują bufor 64-bajtowy, te mniej pamięci RAM otrzymują bufor 16-bajtowy.


Wysyłanie

Zapisywane dane są umieszczane w buforze tej samej wielkości (16 lub 64 bajtów). W przypadku wysyłania, jeśli bufor wypełnia kod, „bloki” czekają na przerwanie, aby wysłać kolejny bajt z portu szeregowego.

Wyłączenie przerwań nigdy się nie wydarzy, dlatego nie wykonuje się wydruków seryjnych w ramach procedury obsługi przerwań.


Uważam, że jesteś wyłączony o rząd wielkości: przy 9600 bodów dostajesz bajt co ~ 0,1 ms, więc wypełnienie bufora zajmuje tylko 6,6 ms.
Eric Dand

1
Przy 9600 bodów dostajesz 9600 bitów na sekundę. Ponieważ każdy bajt ma 10 bitów (8 danych + 1 bit początkowy + 1 bit stopowy), otrzymujesz 960 bajtów na sekundę. 1/960 = 0.001042 s- to jest jeden bajt co 1,04 ms.
Nick Gammon

Ach, oczywiście, bitów nie bajtów! Dziękuję za poprawienie mnie.
Eric Dand

Tak więc Nick, proszę odpowiedz mi na to: Jeśli mam Pi działającego w Pythonie, siedzącego na ser.readline (), czekającego na dane wejściowe jako rejestrator danych, i jest on przesyłany szeregowo przez Arduino, dokonując odczytów, a następnie wysyłając je jako wsad z kartą delimetry, a następnie użycie opóźnienia (120000), aby partie przychodziły co dwie minuty, wnętrze Pythona prawdopodobnie natychmiast odczytuje każdy znak, aż napotka nowy wiersz, w którym to momencie zwalnia całą linię jako wartość zwracaną. Więc nie muszę się martwić o rozmiar bufora Arduino, nawet jeśli wysyłam łącznie 80 znaków, co? Czy to byłoby dobre założenie?
SDsolar,

Tak, rozmiar bufora wysyłającego nie będzie miał znaczenia w tym scenariuszu. Mały bufor spowolniłby wysyłanie (nieco), ale jeśli robisz długie opóźnienie, i tak nie będziesz się przejmować.
Nick Gammon
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.