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
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.
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
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.