Forum: Mikrocontroller und Digitale Elektronik USART, Receiver Buffer


von Bene (Gast)


Lesenswert?

Hallo Experten,
ich habe eine Frage zum USART Receiver Buffer des ATMEGA8.
Der nimmt ja 2 Zeichen auf und ist dann voll.
Im Datenblatt des Megas gibt es eine kleine Funktion zum leeren des 
Buffers.

Meine Fragen:
Wird dabei der ganze Buffer gelöscht?
bzw. wenn ich UDR auslesen speiechere ich nur das erste Zeichen in 
meiner Variable bzw. meinem Register. Wenn ich nun aber nach diesem 
auslesen des UDR den Buffer lösche, wird ja auch gleichzeitig das zweite 
Zeichen gelöscht, was evtl. im Buffer lag?

Wie kann das umgangen werden?

Grüße Bene

von Krapao (Gast)


Lesenswert?

Eine Speicherstelle #A in der vom AVR aus ein komplettes empfangenes 
Zeichen abgelegt ist. Das ist das special function register UDR.

Während der AVR das Zeichen in UDR bereitstellt aber dein Programm das 
Zeichen noch nicht ausgelesen hat, kann der AVR in einer anderen 
Speicherstelle #B die eintröpfelnden Bits des nächsten Zeichens sammeln.

ABER: sobald das Zeichen in #B vollständig ist, wird das Zeichen nach #A 
(= UDR) transportiert - EGAL ob du UDR vorher ausgelesen hast oder 
nicht. Hast du UDR nicht ausgelesen, geht ein Zeichen verloren.

> Im Datenblatt des Megas gibt es eine kleine Funktion zum Leeren des
> Buffers.

"Flushing the Receive Buffer: The Receiver buffer FIFO will be flushed 
when the Receiver is disabled (i.e., the buffer will be emptied of its 
contents). Unread data will be lost. If the buffer has to be flushed 
during normal operation, due to for instance an error condition, read 
the UDR I/O location until the RXC Flag is cleared." Source: Atmega8 
Datenblatt

Beide Methoden kannst du verwenden, um gezielt ein unvollständig 
empfangenes Zeichen aus #B zu löschen. #A wird dabei automatisch immer 
mitgelöscht.

von oldmax (Gast)


Lesenswert?

Hi
Das Zauberwort heißt Ringpuffer
Du empfängst ein Byte per Interrupt. In der ISR nimmst du das Byte und 
schreibst es an eine indizierte Adresse, setzt den Index hoch, fragst 
die Grenze ab und wenn diese erreicht ist setzt du den Index wieder auf 
0. Da ich in Assembler programmiere hier mal kurz ein Beispiel  mit zwei 
Variablen
Read_Pos: Indexzeiger zum Lesen
Write_Pos: Indexzeiger zum schreiben
Com:Buff: 20 Byte Ringpuffer
1
;------------------ Empfangsroutine im Controler ----------------------- 
2
3
int_rxc:
4
  PUSH  R16    ; temp auf dem Stack sichern
5
  IN  R16, sreg    ; SREG sichern    
6
  PUSH  R16
7
  PUSH  R17
8
  PUSH  XL
9
  PUSH  XH
10
  PUSH  R1
11
  CLR  R1
12
  LDS  R16, Write_Pos
13
  IN  R17, UDR
14
  LDI  XL,LOW(Com_Buff)  ; x-Pointer auf Empfangspuffer
15
  LDI  XH,HIGH(Com_Buff)
16
  ADD  XL, R16
17
  ADC  XH, R1  
18
  ST  X, R17
19
  INC  R16
20
  CPI  R16, 20
21
  BRLO  End_rxc
22
  CLR  R16
23
End_rxc:  
24
  STS  Write_Pos, R16
25
  POP  R1
26
  POP  XH
27
  POP  XL
28
  POP  R17
29
  POP  R16    
30
  OUT  sreg, R16    ; SREG wiederherstellen
31
  POP  R16    ; temp wiederherstellen    
32
RETI
Read_Pos und Write_Pos sind am Anfang gleich. Bei einem Unterschied bist 
du sicher, das ein Zeichen eingetroffen ist. Nun kannst du in deiner 
Programmschleife darauf reagierren. Zeichen aus Ringpuffer lesen, 
Lesezeiger erhhen und bei Grenzüberschreitung auf 0 setzen. Dann kannst 
du die Daten in aller Ruhe verarbeiten.
Gruß oldmax

von Karl H. (kbuchegg)


Lesenswert?

Bene schrieb:

> Wird dabei der ganze Buffer gelöscht?
> bzw. wenn ich UDR auslesen speiechere ich nur das erste Zeichen in
> meiner Variable bzw. meinem Register. Wenn ich nun aber nach diesem
> auslesen des UDR den Buffer lösche, wird ja auch gleichzeitig das zweite
> Zeichen gelöscht, was evtl. im Buffer lag?
>
> Wie kann das umgangen werden?

Was willst du eigentlich machen.
Normalerweise brauchst du dich da drum überhaupt nicht kümmern. Du liest 
UDR aus und damit rutscht das nächste Zeichen nach (wenn eines vorhanden 
ist), so dass beim nächsten Auslesen dann eben dieses kommt.

von Bernd (Gast)


Lesenswert?

Der Beitrag von "oldmax (Gast)" zeigt schon mal eine
Lösung.

Ich wundere mich aber, warum du die Buffer leeren möchtest...

Den richtigen Zeitpunkt (UDR-Inhalt ist alter Kram, der USART-
Receive-Buffer hat noch nichts neues drin) kann der µC doch nie
und nimmer wissen!

Warum nicht einfach UDR auslesen und "wegwerfen"?

Was dann kommt, wird nun mal am besten per Interrupt ausgelesen
und in einem Ringspeicher abgelegt. Ist eine Millionenfach
bewährte Methode! Wenn dir was Besseres einfällt, lass es uns
wissen.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.