Forum: Mikrocontroller und Digitale Elektronik Interrupt von UART (Mega8)


von Sebastian K. (basti)


Angehängte Dateien:

Lesenswert?

Hallo!
Hab mich entschlossen von Bascom auf Assembler umzusteigen, und schon
steh ich vor einem kleinem Problem:
Ich möchte ein kleines Oszi mit dem ATMega 8 bastelln (gab's glaub ich
schon öfter). Als Auflösung nehm ich wegen der Datenmenge 8Bit.
Diese möchte ich z.B. in Register R16 laden und immer wenn UDR leer ist
(also wieder ein Byte übertragen werden kann) an den PC übertragen. Ohne
den Interrupt (also mit ständigem abfragen des UDRE-Bits) funktioniert
alles prima!
Wenn ich das jetzt allerdings mit dem Interrupt für das UDRE-Register
machen will kommt nix am PC an.
Brauche ich da einen anderen Interrupt (Transmit Complete statt
UDR-Empty)?

Wäre auch toll wenn ihr mir noch Tips zur Optimierung geben könntet
(den ADC wollte ich irgendwann auch noch per Interrupt ansprechen,
nicht in einer Schleife). Ich will das die Datenrate (Baudrate wird
noch erhöht) möglichst hoch ist...also die vollen 9600Baud ausgenutzt
werden!

MfG
BastiK

von Sebastian K. (basti)


Lesenswert?

Hat denn keiner einen Rat für mich?

MfG

von papa_of_t (Gast)


Lesenswert?

Hallo Basti,

also den Assembler kannst Du Dir noch sparen - ich denke der
Flaschenhals ist bei Dir die serielle Schnittstelle. Ich hoffe, Du hast
zum Übertragen nicht den Print-Befehl verwendet, der kostet nämlich viel
Zeit. Seriell senden in Bascom (Schnittstelle vorher initialisieren
natürlich):

'-------------------------------------------------
'hier den ADC starten
XXX

'während der ADC mißt - Wert der letzten Messung senden
UDR=myByte  'Byte in den Sendepuffer schreiben
Do:Loop Until UCSRA.UDRE=1 'Warten bis Senden fertig ist

'hier den ADC auslesen
myByte = XXX
'-------------------------------------------------

Bei 9600 Baud kannst Du maximal etwa bis 500 Hz sinnvoll messen. Wenn
der Prozessor nebenbei noch was anderes tun soll, kannst Du die
Schleife da oben in eine Timer-Interrupt-Routine einbinden, die
Baudrate erhöhen und testen, wie weit Du den Timer beschleunigen
kannst, ohne Interrupts zu verlieren. Optimieren kann man nch mit der
Reihenfolge der Befehle und dem ADC-Modus.

Viel Spaß beim Basteln!

von Sebastian K. (basti)


Lesenswert?

Hallo!
Ich denke das dieses Projekt gut zum "Eingewöhnen" in den Assembler
ist. In Bascom ist das alles für mich kein Problem (da alles Vorgekaut
ist), aber in Assembler schon!

Die 9600Baud sind ja eigentlich nur am Anfang zum ausprobieren, mit dem
angeschlossenen 3,6864MHz Quarz kann ich ja bis 230400 Baud gehen! Ggf.
wird das ganze nochmal seperat aufgebaut mit kleinerem AVR und
schnellerem Takt. Da ist dann eine Schleife etwas blöd, da ich ja noch
ein paar Takte benötige um die neuen Werte in ein Register zu laden und
wieder auszugeben!

Weisst du vielleicht trotzdem wie ich das in Assembler mit dem
Interrupt drehen muss?

MfG
Basti

von papa_of_t (Gast)


Lesenswert?

In Assembler mußt Du u.a. Interrupt-Vektoren beschreiben usw. Ein gutes
Tutoial dafür fand ich hier:

http://www.avr-asm-tutorial.net/avr_de/index.html

Also ich habe gute Ergebnisse beim Tuning erreicht (und das ist sicher
auch für Deinen geplanten "Umstieg" ganz lehrreich und weniger
frustrierend), indem ich Assembler und Bascom erstmal gemixt habe - so
kannst Du z.B. weiter in Bascom die ISR mit der Option NoSave
deklarieren ("On UTXC myISR NoSave") und dann in der ISR Assembler
verwenden - das ist sehr schnell. Wenn Du wissen willst wie schnell
genau (oder vergleichen Basic/Assembler), kannst Du sehr schön im
Bascom-Simulator an den Clocks sehen, daß z.B. ein Do:loop until..
mindestens 14 Takte braucht, währenddessen das gleiche in Assembler nur
4-5 Takte dauert.

von gerd (Gast)


Lesenswert?

Hallo.

Es gibt eine nette kleine Falle, wenn Du mit Int bei UDRE arbeitest.
Wenn Du das erste Byte in das UDR geschrieben hast, ist es ratzfatz
schon wieder leer, weil es ja nur zum Senderegisterc durchgereicht
wird, und der zweite Int folgt unmittelbar hinterher. Erst danach geht
alles seinen geregelten Gang.

Eine zweite Falle ist, dass der Int bei nicht vorhandenen Daten nicht
einfach verlassen werden darf, weil dann der UDRE-Int dauernd weiter
zuschlägt. Das Int-Bit wird nicht wie bei anderen Ints durch das
Ausführen der Service Routine rückgesetzt. Wenn also der Int erfolgt,
aber gerade kein Byte gesendet werden soll, muss das gesetzte Int-Bit
explizit zurückgesetzt werden. Im data sheet steht dazu:
"When interrupt-driven data transmission is used, the Data Register
empty Interrupt routine must either write new data to UDR in order to
clear UDRE or disable the Data Register".
Das ist gar nicht schön, weil "disable the data register" soviel
heißt wie "setze UDRE zurück". Damit ist der Int dann auch gleich mit
abgeschaltet. Und muss dann zur Auslösung eines Int einmalig manuell
wieder gesetzt werden.
Hier ist es Atmel gelungen, die Maximalverwirrung anzurichten.
Ich finde, wenn Du eine feste Datenrate einstellen willst, dann mache
die Datenrate nicht vom USART abhängig. Nimm lieber eine feste Rate
(z.B. Timer- oder ADC-gesteuert), wähle eine Baudrate, die groß genug
ist und sende das Ergebnis blind ab. Damit gibt es keine Konflikte mit
dem Int.

Ansonsten wünsche ich Dir viel Erfolg mit Assembler. Wenn Du erst mal
richtig merkst, wie rasch und einfach die Mehrzahl der Aufgaben in
Assembler zu lösen sind, wirst Du wahrscheinlich süchtig danach.

mfg
gerd

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.