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
[C] warte: sbis TIFR, OCF1A rjmp warte2 [C] wenn du in der Schleife bleiben willst, sollte es doch "rjmp warte" heißen, oder? Gruß
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...
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.