Hallo Ihr, ich hab folgendes Problem. Das CD-Laufwerk das ich benutze kommuniziert mit 115200 baud mit einme ATMEGA 644. Dem Laufwerk Befehle zu schicken ist kein Problem. Nur die Aubereitung der Daten die vom Laufwerk kommen bereitet mir etwas Kopfzerbrechen. Das erste empfangene bit ist OK, nur die folgenden bekomme ich nicht mit. Die Idee war: auf das erste bit mit einem Interrupt reagieren und die weiteren dann durch polling einlesen und in einem String abspeichern. Zwischen den einzelnen Byte ist keine Pause. Mein Code bis jetzt hab ich angehängt. Sieht einer von euch den Fehler? Oder geht das so garnicht? Danke Andy PS: Das zweite Byte das übertragen wird ist die anzahl der byte die noch kommen.
Andreas Geissler schrieb: > Mein Code bis jetzt hab ich angehängt. Ein Text-Programm. Cool. > Das erste empfangene bit ist OK Du meinst wohl Byte... Wenn du mit einem Schlosser sprichst und M8 sagst, dann hat der sofort ein Bild vor dem Auge und kann nicht wissen, dass du "eigentlich" eine M22 Schraube meinst. Gut soweit. Zur Sache: > Die Idee war: auf das erste bit mit einem Interrupt reagieren und die > weiteren dann durch polling einlesen Und das in der Interruptroutine. Du hältst also solange den Prozessor von der Arbeit ab und sperrst andere Interrupts. Die Idee scheint mir ungünstig. Aber dein Problem ist schon seit Ende des letzten Jahrtausends gelöst und die Lösung heißt FIFO. Andreas Geissler schrieb: > Zwischen den einzelnen Byte ist keine Pause. Doch: zwischen den einzelnen Bytes ist von Sicht deiner Software aus jeweils ca. 90us Pause. Denn so lange ist der Empfänger mit dem nächsten Byte beschäftigt... Andreas Geissler schrieb: > Das zweite Byte das übertragen wird ist die anzahl der byte die noch > kommen. Woran erkennst du das erste Byte?
Hallo Lothar, das erste Byte erkenne ich am Interrupt. Das erste byte kann alles mögliche sein. Es ist kein einheitliches Zeischen. Von daher war die Idee den Interrupt zu sperren und die weiteren Bytes zu pollen. Die kommen mehr oder weniger ohne Pause, Maximal 10 Stück. Wenn der player läuft kommen die Bytets im Sekunden Rhytmus.
Andreas Geissler schrieb: > Die Idee war: auf das erste bit mit einem Interrupt reagieren und die > weiteren dann durch polling einlesen und in einem String abspeichern. > Zwischen den einzelnen Byte ist keine Pause. Mal abgesehen davon, dass du Byte meinst und nicht Bit: Warum zur Hölle beginnst du in der ISR mit Polling? Das ist ja mal völlig sinnbefreit. Überlege doch jetzt einfach mal, was passiert wenn die ISR des USART ausgelöst wird. Genau, immer dann wenn ein Zeichen empfangen wurde (wäre übrigens die Antwort auf Lothars letzte Frage). Wie Lothar schon schrieb hast du nun 90 µs Zeit den Eingangsbuffer auszulesen und auf das nächste Zeichen zu warten. Sollte also mehr als genug Zeit sein um den Buffer wieder zu leeren und sich auf das folgende Byte vorzubereiten.
Das Laufwerk wird mit Sicherheit ein Protokoll sprechen, d.h. irgendwie ist festgelegt, was das erste und was das letzte Byte ist. Der Interrupt liefert Dir nur die Aussage es ist irgend ein Byte da, aber nie, welches. Dir bleibt also nichts anderes übrig, als das Protokoll zu implementieren.
Hallo Peter, ich möchte das Protokol implementieren, ganz klar, da bin ich dran. Wie gesagt das erste byte ist kein Problem das bekomme ich nur dann hört es auf, obwohl noch weitere bytes übertragen werden. Ich überlege wie ich es besseer machen könnte, ich werde mir nachher den FIFO puffer anschauen den ich im Forum gefunden habe. Andy
Andreas Geissler schrieb: > Wie gesagt das erste byte ist kein Problem das bekomme ich nur dann hört > es auf, obwohl noch weitere bytes übertragen werden. Das Problem ist dein Polling denke ich. Wie schon gesagt, der ISR kommt ja bei jedem Zeichen, dass empfangen wird. Du musst also in der ISR gar kein Polling verwenden sondern nur eben das empfangene Zeichen aus dem Empfangsspeicher in einen Puffer schreiben (das dauert 1-2 Zyklen) und die ISR beenden und zack musst du warten bis das CD-Laufwerk dir das nächste Zeichen überhaupt sendet (ich geh mal davon aus, dass dein Atmega nicht nur mit 128 kHz Taktrate läuft sondern eher so mit 8 MHz oder schneller). Während du dann also quasi auf das nächste Byte wartest kannst du prüfen ob das letzte empfangene Byte ein Start- oder Endbyte war. Das sollte aber schon das Protokoll machen. Ist halt wie bei RS232. Da definiert man ja auch, dass man z.B. 1 Start-Bit und 2 Stopp-Bits hat aber damit hat es sich dann auch, man schaut dann nicht mehr nach ob man das Startbit oder ein Stoppbit empfangen hat. Das macht der µC dann alleine.
Also nochmal: Du musst das Protokoll implementieren. In den Unterlagen steht ganz bestimmt, wie das Laufwerk seine Antworten formatiert. Entweder steht irgendwo in der Antwort (meist am Anfang), wie viele Bytes jetzt kommen werden oder es gibt ein dezitirtes Endekennzeichen ... evtl. auch Beides und möglicherweise eine Prüfsumme. Nachdem das erste Byte hereingekommen ist, musst du es in einen Puffer "wegschaffen", ein par Zeilen Auswertung ausführen und einen Zähler hochzählen, damit du weisst, wieviel schon da ist ... dann auf das nächste Byte warten. Pause ist immer, es gibt garantiert mind. 1 Stopbit. Wenn du das Protokoll des Laufwerkes kennst, weisst du wann die Mengenangabe kommt - auf die must du warten und entsprechend reagieren - das meine ich mit "einige Zeilen Code ausführen" ...
Michael Köhler schrieb: > nur eben das empfangene Zeichen aus dem > Empfangsspeicher in einen Puffer schreiben (das dauert 1-2 Zyklen) Naja. 2 Zyklen UDR0 lesen, 4 Zyklen Zeiger lesen, 2 Zyklen byte speichern, 2 Zyklen Zeiger inkrementieren, 4 Zyklen auf Überlauf testen 4 Zyklen Zeiger speichern Dann noch ~30..40 Zyklen Interrupt + Prolog + Epilog. Aber ja. Die Antwort ist dennoch richtig. Jedes Zeichen löst einen Interrupt aus und die Interrupt-Routine soll jedes einzelne Byte so schnell wie möglich behandeln (speichern, vielleicht noch Ende des Pakets erkennen falls möglich und globales flag setzen). Der rest passiert in der main() wo alle Zeit der Welt ist.
Bernd K. schrieb: > Dann noch ~30..40 Zyklen Interrupt + Prolog + Epilog. Also überschlagen etwa 100 Zyklen, das sind bei 10MHz dann gerade mal 10us. Kein Grund, dafür dann 80us (und damit gut 85% der Rechenleistung) mit Polling zu verplempern...
Andreas Geissler schrieb: > Das erste empfangene bit ist OK, nur die folgenden bekomme ich nicht > mit. > Die Idee war: auf das erste bit mit einem Interrupt reagieren und die > weiteren dann durch polling einlesen und in einem String abspeichern. > Zwischen den einzelnen Byte ist keine Pause. > > Mein Code bis jetzt hab ich angehängt. > > Sieht einer von euch den Fehler? Oder geht das so garnicht? Hallo Andreas, du machst in deinem Programm einen grundsätzlichen Fehler. Du programmierst so:
1 | while (!(UCSR0A & (1<<RXC0))) { |
2 | rc_array[i] = UDR0; |
3 | PORTA ^= (1<<PA5); |
4 | }
|
5 | i++; |
Das bedeutet aber nichts anderes als dass du UDR0 ausliest solange da noch nichts drin angekommen ist. Sobald etwas angekommen ist liest du UDR0 nicht mehr und verlässt die Schleife. Der richtige Weg ist im Datenblatt beschrieben und besteht aus einem sehr leicht zu übersehenden Semikolon:
1 | while (!(UCSR0A & (1<<RXC0))) ; |
2 | rc_array[i] = UDR0; |
3 | PORTA ^= (1<<PA5); |
4 | i++; |
Ich hasse diese Notation und benutze in solchen Fällen daher immer folgendes Konstrukt:
1 | while (!(UCSR0A & (1<<RXC0))) continue; |
2 | rc_array[i] = UDR0; |
3 | PORTA ^= (1<<PA5); |
4 | i++; |
Das Schlüsselwort continue ist zwar unnötig, führt aber dazu dass man das Semikolon nicht überliest! LG, Sebastian
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.