Forum: Mikrocontroller und Digitale Elektronik Richtiger Umgang mit Flags


von Branadic (Gast)


Lesenswert?

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

von ehde76 (Gast)


Lesenswert?

[C]
warte:
sbis  TIFR, OCF1A
rjmp  warte2
[C]

wenn du in der Schleife bleiben willst, sollte es doch "rjmp  warte" 
heißen, oder?

Gruß

von Branadic (Gast)


Lesenswert?

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

von inoffizieller WM-Rahul (Gast)


Lesenswert?

Weclher Controller?

von Branadic (Gast)


Lesenswert?

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

von TravelRec. (Gast)


Lesenswert?

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.

von TravelRec. (Gast)


Lesenswert?

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.

von inoffizieller WM-Rahul (Gast)


Lesenswert?

>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.

von Branadic (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

> 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.



von Branadic (Gast)


Lesenswert?

@ 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.

von Karl H. (kbuchegg)


Lesenswert?

> 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?

von Branadic (Gast)


Lesenswert?

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.

von Branadic (Gast)


Lesenswert?

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...

von Karl H. (kbuchegg)


Lesenswert?

> 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.

von TravelRec. (Gast)


Lesenswert?

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.

von Sonic (Gast)


Lesenswert?

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.

von Branadic (Gast)


Lesenswert?

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

von inoffizieller WM-Rahul (Gast)


Lesenswert?

>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
Noch kein Account? Hier anmelden.