Hallo,
ich probiere mich derzeit im Umgang mit AVR-Assembler und komme an einer
Stelle einfach nicht weiter. Die Suche des Forums und diverse
Suchmaschinen konnten mir auch nicht wirklich weiterhelfen. Auch im
Tutorial, das ich schon durchgearbeitet habe, finde ich keine Antwort.
Ich habe also, wie ihr sehen könnte, versucht mir die Frage selbst zu
beantworten, was leider misslang. Daher die Frage nun an euch.
Ich habe ein Programm mit einer PWM (Tastverhälnis 50:50) und will nun
in einer Warteschleife auf die nächste Flanke (ob nun steigend oder
fallend ist von der Sache her erst einmal egal) der PWM warten, um
zwischen zwei Flanken eine AD-Umsetzung vorzunehmen. Also liegt es nahe,
das CompareMatch-Flag auszuwerten. Also habe ich eine Warteschleife
derart geschrieben:
warte:
sbis TIFR, OCF1A
rjmp warte2
Das funktioniert aber so überhaupt gar nicht, bzw. ich bekomme dort
einen Fehler beim Compilieren. Die Frage die sich mir jetzt stellt, wie
kann ich sinnvoll Auslesen, ob das Flag gesetzt wurde, oder nicht?
Oder sollte ich einen anderen Ansatz wählen und den Interrupt beim
CompareMatch verwenden, um ein selbst definiertes Flag zu setzen? Wenn
ja, wie schaut solch ein Ansatz aus?
Ich danke euch für euere Hilfe.
Sonnige Grüße, Branadic
Hallo ehde,
das ist natürlich richtig... die zwei ist überflüssig, ändert jedoch
nichts an dem Problem... hatte nur vergessen auch diese zu entfernen,
als ich den Ausschnitt hier ins Forum kopiert habe, richtig heißt es
natürlich:
warte:
sbis TIFR, OCF1A
rjmp warte
War also nur ein Fehler beim kopieren, um die Schleife namentlich
allgemein zu halten, weil ich in meinem Programm mehrere Schleifen
verwende ;)
Sonnige Grüße, Branadic
Hallo "inoffizieller WM-Rahul",
es ist ein Tiny15, aber spielt der Controller eine Rolle bei der Frage?
Der Lösungsansatz wäre doch beim Tiny2313, Mega8 oder 16 der gleiche,
oder zielt die Frage auf den vorhandenen Befehlssatz im Controller?
Sonnige Grüße, Branadic
Könnte das daran liegen, daß Dein OutputCompareFlag OCF1A immer gesetzt
ist, weil es nie jemand löscht? Findet ein OutputCompare statt und wird
kein Interrupt bedient, muß das Flag durch Schreiben einer 1 in das Flag
"manuell" gelöscht werden.
Ach ja und der der Fehler beim Assemblieren kann durch ein falsches
Label entstehen. Gucke nochmal in´s Datenblatt des betreffenden
Controllers, ob die Bezeichnung für das Flag richtig ist.
>oder zielt die Frage auf den vorhandenen Befehlssatz im Controller?
Jain. Manche Controller haben halt einen erweiterten Adressraum, den man
über neuere Befehle erreicht...
TravelRec hat Recht: Wird das Flag auch gelöscht?
Eine andere Möglichkeit wäre, den ADC in der ISR zum OCF zu
konfigurieren / zu starten.
Hallo,
also ich habe den Ausdruck:
sbis TIFR, OCF1A
nun mal gegen den Ausdruck:
sbis TIFR, 7
ausgetauscht. Jetzt bekomme ich statt zwei Fehlermeldungen nur noch die
Fehlermeldung:
Operand 1 out of Range
Es ist richtig, dass ich das Flag selbst nicht lösche, da im Datenblatt
ja steht:
"...OCF1A is cleared by hardware when executing the corresponding
interrupt handlings vector..."
Der Interrupt ist aktiviert, auch wenn da nur ein RETI drin steht, so
sollte doch das Flag automatisch vom ausgelösten Interrupt zurückgesetzt
werden, oder?
Gruß, Branadic
> Der Interrupt ist aktiviert, auch wenn da nur ein RETI drin steht,> so sollte doch das Flag automatisch vom ausgelösten Interrupt> zurückgesetzt werden, oder?
Das war eine wichtige Information, die du bis jetzt vorenthalten
hast.
Überleg doch mal:
Du hast den Interrupt aktiviert. Sobald der Compare Match
da ist, wird
* das OCF1A Flag gesetzt
* da der Interrupt aktiviert ist, wird sofort beim
nächsten Befehl der Interrupt auch ausgeführt
* welcher macht:
* das Flag wieder löschen
* einen RETI
Wie also willst du von ausserhalb jemals das gesetzte Flag
Bit sehen? Sobald es von der Hardware gesetzt wird, wird
der Interrupt ausgelöst, der es sofort wieder löscht.
Also entscheide dich:
* entweder du wertest den Compare Match im Interrupt aus
* oder du machst es manuell mit einer Schleife, wie
du sie oben hast und setzt das Flag selbst wieder zurück
Beides gemeinsam bringt dich nur in Schwierigkeiten.
@ inoffizieller WM-Rahul,
>Eine andere Möglichkeit wäre, den ADC in der ISR zum OCF zu
konfigurieren / zu starten.
Diese Möglichkeit kann ich nicht nutzen, da die ADC nur in einem
bestimmten Zeitintervall ausgeführt werden soll und nicht bei jedem
Flankenwechsel. Also angenommen ich möchte alle 5min eine ADC starten
(hierfür gibt es den entsprechenden Counter), so muss ich vor der
Umsetzung eben auf die nächste Flanke warten, um keine Störungen durch
einen Flankenwechsel in meinen AD-Wert zu erhalten.
> Diese Möglichkeit kann ich nicht nutzen
Und was hindert dich daran, in der Interrupt Routine besagten
Counter zu überprüfen und nur dann, wenn der 5min anzeigt
den ADC zu starten?
Eine ähnliche Überlegung ist mir auch schon gekommen. Also könnte ich es
doch durch ein selbstdefiniertes Flag lösen, welches im Interrupt
gelöscht wird. Vor der Warteschleife setze ich dieses auf Null zurück
und warte dann in der Warteschleife, bis es wieder gesetzt ist. Nur wie
definiere ich mir ein solches? Ich hatte da schon einen Ansatz, aber der
wollte auch partou nicht funktionieren.
Was mich daran hindert? Nun, ich hatte irgendwo gelesen, dass man die
Interrupts möglichst kurz halten soll, also mache ich die
Counterauswertung in meinem Hauptprogramm und warte im Hauptprogramm auf
das gesetzte Flag...
> Eine ähnliche Überlegung ist mir auch schon gekommen. Also könnte ich es> doch durch ein selbstdefiniertes Flag lösen, welches im Interrupt> gelöscht wird. Vor der Warteschleife setze ich dieses auf Null zurück> und warte dann in der Warteschleife, bis es wieder gesetzt ist. Nur wie> definiere ich mir ein solches? Ich hatte da schon einen Ansatz, aber der> wollte auch partou nicht funktionieren.
Nun ja. Da frag ich mich doch: Wozu der ganze Aufwand?
Du hast dich schon ein Flag, welches ganu dieses macht.
Alles was du tun musst ist: den Interrupt weglassen und dich
selbst drum kümmern, dass das entsprechende Bit wieder
zurückgesetzt wird.
Ansonsten: ein Flag ist auch nur ein Bit.
Du definierst dir einfach eine Variable und setzt ein Bit.
> Nun, ich hatte irgendwo gelesen, dass man die> Interrupts möglichst kurz halten soll
Schon. Nur in deinem Fall ist das sinnlos. Irgendetwas sinnvolles
sollte eine Interrupt Funktion schon auch machen. Eine
Interrupt Funktion nur dafür, damit man einen RETI hat und
das Flag wieder gelöscht wird (noch dazu zum unpassendsten
Zeitpunkt) ist wohl ziemlich sinnfrei. Da kannst du sie
auch gleich weglassen und dich selbst um das Löschen des Bits
kümmern. Dann hast du wenigstens die Kontrolle darüber, wann
dieses passiert.
Zum anderen: So kurz wie möglich: Ja. Gemeint ist damit, dass
man in einem Interrupt nicht 2000 quadratische Gleichungen
löst und das Ergebnis per UART zu einem Terminal schickt, während
gleichzeitig der Brandmelder nur darauf wartet endlich seinen
Interrupt durchzubringen um dich nach 2 Stunden über das Vorhandensein
eines Feuers zu benachrichtigen.
Wenn es dein Gesamt-Timing zulässt, kann eine Interruptbehandlung
solange dauern wie sie will.
Merke: sog. Regeln in der Programmierung sind eher Richtlinien.
Im Einzelfall kann es durchaus sein und auch Sinn machen, diese
mal zu umgehen. Wie lange dauert es den Counter zu checken und
den ADC zu aktivieren (der dann seinerseits wiederrum mit
einem Interrupt die beendete Wandlung verkündet)? Das kann
ja nicht allzulange dauern. Also kannst du das ruhig in dieser
Interrupt-Behandlung des Compare Match machen.
Najaaa - so kurz wie möglich heißt nicht, daß der Interrupt gar nix
machen darf. Die ISR muß nur in einem vernünftigen, von den äußeren
Ansprüchen an die Laufzeit abhängigen Verhältnis stehen. Warteschleifen
sind übrigens zu 98% reine Zeitverschwendung, ein Timer-Interrupt kann
das viel effizienter. Es ist Sache des Programmierers, zu entscheiden,
ob bestimmte Dinge besser sofort im Interrupt oder später zu
unkritischen Zeiten in der Hauptschleife erledigt werden. Dies hängt im
Wesentlichen von der Aufgabe des Proramms und dessen Struktur ab.
Wieso benutzt du nicht einfach den Output-Compare-INT? Dann bist du ganz
sicher nach der Flanke. Das OC-INT-Flag wird nicht gelöscht werden, wenn
keine INT-Routine durchlaufen (beendet) wird.
Danke für die Hilfe...
ich habe jetzt die Lösung probiert mir ein eigenes Flag zu basteln,
welches im Interrupt gesetzt wird, im Programm dann geprüft und wieder
gelöscht wird. Die Lösung erscheint vielleicht grobmotorisch,
funktioniert jetzt aber. Ich werde aber den Ansatz, die Counter-Prüfung
in den Interrupt zu verlegen, mal mit ins Auge fassen.
Besten Dank an dieser Stelle für die wirklich qualifizierten Antworten.
Sonnige Grüße, Branadic
>grobmotorisch
nö, ist es aber nicht.
Statemachines arbeiten ähnlich.
Leg mal deinen µC schlafen. Dann wirst du dich freuen, wenn das
"grobmotorische" Flag dir anzeigt, was dein µC geweckt hat...