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