<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://www.mikrocontroller.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=85.183.44.11</id>
	<title>Mikrocontroller.net - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="https://www.mikrocontroller.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=85.183.44.11"/>
	<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/articles/Spezial:Beitr%C3%A4ge/85.183.44.11"/>
	<updated>2026-04-10T13:13:51Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_7-Segment-Anzeige&amp;diff=34584</id>
		<title>AVR-Tutorial: 7-Segment-Anzeige</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_7-Segment-Anzeige&amp;diff=34584"/>
		<updated>2009-02-24T13:37:24Z</updated>

		<summary type="html">&lt;p&gt;85.183.44.11: /* Schaltung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Die Ausgabe von Zahlenwerten auf ein Text-LCD ist sicherlich das Nonplusultra, aber manchmal liegen die Dinge sehr viel einfacher. Um beispielsweise eine Temperatur anzuzeigen ist ein LCD etwas Overkill. In solchen Fällen kann die Ausgabe auf ein paar 7-Segmentanzeigen gemacht werden. Ausserdem haben 7-Segmentanzeigen einen ganz besonderen Charme :-)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Eine einzelne 7-Segment Anzeige==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Codetabelle===&lt;br /&gt;
&lt;br /&gt;
Die Umkodierung von einzelnen Ziffern in ein bestimmtes Ausgabemuster bezeichnet man als Codetabelle. Die auszugebende Ziffer wird als Offset zum Anfang dieser Tabelle aufgefasst und aus der Tabelle erhält man ein Byte (Code), welches direkt auf den Port ausgegeben werden kann und das entsprechende Bitmuster enthält, sodass die für diese Ziffer notwendigen LED ein- bzw. ausgeschaltet sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Um die Ziffer &#039;&#039;&#039;3&#039;&#039;&#039; anzuzeigen, müssen auf der Anzeige die Segmente &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, &#039;&#039;&#039;c&#039;&#039;&#039;, &#039;&#039;&#039;d&#039;&#039;&#039; und &#039;&#039;&#039;g&#039;&#039;&#039; aufleuchten. Alle anderen Segmente sollen dunkel sein.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tut_7_Seg_02a.gif | framed | left | Darstellung der Ziffer &amp;quot;3&amp;quot;]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aus dem Anschlußschema ergibt sich, dass die dazu notwendige Ausgabe am Port binär &#039;&#039;&#039;10110000&#039;&#039;&#039; lauten muss. Untersucht man dies für alle Ziffern, so ergibt sich folgende Tabelle:&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
    .db  0b11000000     ; 0: a, b, c, d, e, f&lt;br /&gt;
    .db  0b11111001     ; 1: b, c&lt;br /&gt;
    .db  0b10100100     ; 2: a, b, d, e, g&lt;br /&gt;
    .db  0b10110000     ; 3: a, b, c, d, g&lt;br /&gt;
    .db  0b10011001     ; 4: b, c, f, g&lt;br /&gt;
    .db  0b10010010     ; 5: a, c, d, f, g&lt;br /&gt;
    .db  0b10000010     ; 6: a, c, d, e, f, g&lt;br /&gt;
    .db  0b11111000     ; 7: a, b, c&lt;br /&gt;
    .db  0b10000000     ; 8: a, b, c, d, e, f, g&lt;br /&gt;
    .db  0b10010000     ; 9: a, b, c, d, f, g&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Programm===&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm stellt nacheinander die Ziffern 0 bis 9 auf der 7-Segmentanzeige dar. Die jeweils auszugebende Zahl steht im Register &#039;&#039;&#039;count&#039;&#039;&#039; und wird innerhalb der Schleife um jeweils 1 erhöht. Hat das Register den Wert 10 erreicht, so wird es wieder auf 0 zurückgesetzt. Nach der Erhöhung folgt eine Warteschleife, welche dafür sorgt, dass bis zur nächsten Ausgabe eine gewisse Zeit vergeht. Normalerweise macht man keine derartigen langen Warteschleifen, aber hier geht es ja nicht ums Warten sondern um die Ansteuerung einer 7-Segmentanzeige. Einen Timer dafür zu benutzen wäre zunächst zuviel Aufwand.&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Ausgabe und damit der in diesem Artikel interessante Teil findet jedoch direkt nach dem Label &amp;lt;i&amp;gt;loop&amp;lt;/i&amp;gt; statt. Die bereits bekannte Codetabelle wird mittels &#039;&#039;&#039;.db&#039;&#039;&#039; Direktive (&#039;&#039;&#039;d&#039;&#039;&#039;efine &#039;&#039;&#039;b&#039;&#039;&#039;yte) in den [[Speicher#Flash-ROM | Flash-Speicher]] gelegt. Der Zugriff darauf erfolgt über den Z-Pointer und dem Befehl &#039;&#039;&#039;lpm&#039;&#039;&#039;. Zusätzlich wird vor dem Zugriff noch der Wert des Registers &#039;&#039;&#039;count&#039;&#039;&#039; und damit der aktuelle Zählerwert zum Z-Pointer addiert.&lt;br /&gt;
&lt;br /&gt;
Beachtet werden muss nur, dass der Zählerwert verdoppelt werden muss. Dies hat folgenden Grund: Wird die Tabelle so wie hier gezeigt mittels einzelnen &#039;&#039;&#039;.db&#039;&#039;&#039; Anweisungen aufgebaut, so fügt der Assembler sog. &#039;&#039;&#039;Padding Bytes&#039;&#039;&#039; zwischen die einzelnen Bytes ein, damit jede &#039;&#039;&#039;.db&#039;&#039;&#039; Anweisung auf einer geraden Speicheradresse liegt. Dies ist eine direkte Folge der Tatsache, dass der Flash-Speicher &#039;&#039;&#039;wortweise&#039;&#039;&#039; (16 Bit) und nicht &#039;&#039;&#039;byteweise&#039;&#039;&#039; (8 Bit) organisiert ist. Da aber von einem .db in der Tabelle zum nächsten .db eine Differenz von 2 Bytes vorliegt, muss dies in der Berechnung berücksichtigt werden. Im zweiten Beispiel auf dieser Seite wird dies anders gemacht. Dort wird gezeigt wie man durch eine andere Schreibweise der Tabelle das Erzeugen der Padding Bytes durch den Assembler verhindern kann.&lt;br /&gt;
&lt;br /&gt;
Aus dem gleichen Grund wird auch der Z-Pointer mit dem 2-fachen der Startadresse der Tabelle geladen. Die Startadresse wird vom Assembler in wortweiser Adressierung eingesetzt, &#039;&#039;&#039;lpm&#039;&#039;&#039; möchte die Zugriffsadresse als Byteadresse angegeben haben.&lt;br /&gt;
&lt;br /&gt;
Interessant ist auch, dass in der Berechnung ein Register benötigt wird, welches den Wert 0 enthält. Dies deshalb, da es im AVR keinen Befehl gibt der eine Konstante mit gleichzeitiger Berücksichtigung des Carry-Bits addieren kann. Daher muss diese Konstante zunächst in ein Register geladen werden und erst dann kann die Addition mithilfe dieses Registers vorgenommen werden. Das Interessante daran ist nun, dass dieser Umstand in sehr vielen Programmen vorkommt und es sich bei der Konstanten in der überwiegenden Mehrzahl der Fälle um die Konstante 0 handelt. Viele Programmierer reservieren daher von vorne herein ein Register für diesen Zweck und nennen es das Zero-Register. Sinnvollerweise legt man dieses Register in den Breich r0..r15, da diese Register etwas zweitklassig sind (ldi, cpi etc. funktionieren nicht damit).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
.def zero  = r1&lt;br /&gt;
.def count = r16&lt;br /&gt;
.def temp1 = r17&lt;br /&gt;
&lt;br /&gt;
.org 0x0000&lt;br /&gt;
           rjmp    main                ; Reset Handler&lt;br /&gt;
;&lt;br /&gt;
main:&lt;br /&gt;
           ldi     temp1, LOW(RAMEND)  ; Stackpointer initialisieren&lt;br /&gt;
           out     SPL, temp1&lt;br /&gt;
           ldi     temp1, HIGH(RAMEND)&lt;br /&gt;
           out     SPH, temp1&lt;br /&gt;
;&lt;br /&gt;
           ldi     temp1, $FF        ; die Anzeige hängt am Port D&lt;br /&gt;
           out     DDRD, temp1       ; alle Pins auf Ausgang&lt;br /&gt;
;&lt;br /&gt;
           ldi     count, 0          ; und den Zähler initialisieren&lt;br /&gt;
           mov     zero, count&lt;br /&gt;
;&lt;br /&gt;
loop:&lt;br /&gt;
           ldi     ZL, LOW(Codes*2)  ; die Startadresse der Tabelle in den&lt;br /&gt;
           ldi     ZH, HIGH(Codes*2) ; Z-Pointer laden&lt;br /&gt;
&lt;br /&gt;
           mov     temp1, count      ; die wortweise Adressierung der Tabelle&lt;br /&gt;
           add     temp1, count      ; berücksichtigen&lt;br /&gt;
&lt;br /&gt;
           add     ZL, temp1         ; und ausgehend vom Tabellenanfang&lt;br /&gt;
           adc     ZH, zero          ; die Adresse des Code Bytes berechnen&lt;br /&gt;
&lt;br /&gt;
           lpm                       ; dieses Code Byte in das Register r0 laden&lt;br /&gt;
&lt;br /&gt;
           out     PORTD, r0         ; und an die Anzeige ausgeben&lt;br /&gt;
;&lt;br /&gt;
           inc     count             ; den Zähler erhöhen, wobei der Zähler&lt;br /&gt;
           cpi     count, 10         ; immer nur von 0 bis 9 zählen soll&lt;br /&gt;
           brne    wait&lt;br /&gt;
           ldi     count, 0&lt;br /&gt;
;&lt;br /&gt;
wait:      ldi     r17, 10           ; und etwas warten, damit die Ziffer auf&lt;br /&gt;
wait0:     ldi     r18, 0            ; der Anzeige auch lesbar ist, bevor die&lt;br /&gt;
wait1:     ldi     r19, 0            ; nächste Ziffer gezeigt wird&lt;br /&gt;
wait2:     dec     r19&lt;br /&gt;
           brne    wait2&lt;br /&gt;
           dec     r18&lt;br /&gt;
           brne    wait1&lt;br /&gt;
           dec     r17&lt;br /&gt;
           brne    wait0&lt;br /&gt;
;&lt;br /&gt;
           rjmp    loop              ; auf zur nächsten Ausgabe&lt;br /&gt;
;&lt;br /&gt;
Codes:                               ; Die Codetabelle für die Ziffern 0 bis 9&lt;br /&gt;
                                     ; sie regelt, welche Segmente für eine bestimmte&lt;br /&gt;
                                     ; Ziffer eingeschaltet werden müssen&lt;br /&gt;
                                     ;&lt;br /&gt;
           .db     0b11000000        ; 0: a, b, c, d, e, f&lt;br /&gt;
           .db     0b11111001        ; 1: b, c&lt;br /&gt;
           .db     0b10100100        ; 2: a, b, d, e, g&lt;br /&gt;
           .db     0b10110000        ; 3: a, b, c, d, g&lt;br /&gt;
           .db     0b10011001        ; 4: b, c, f, g&lt;br /&gt;
           .db     0b10010010        ; 5: a, c, d, f, g&lt;br /&gt;
           .db     0b10000010        ; 6: a, c, d, e, f, g&lt;br /&gt;
           .db     0b11111000        ; 7: a, b, c&lt;br /&gt;
           .db     0b10000000        ; 8: a, b, c, d, e, f, g&lt;br /&gt;
           .db     0b10010000        ; 9: a, b, c, d, f, g &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Mehrere 7-Segment Anzeigen (Multiplexen)==&lt;br /&gt;
&lt;br /&gt;
Mit dem bisherigen Vorwissen könnte man sich jetzt daran machen, auch einmal drei oder vier Anzeigen mit dem Mega8 anzusteuern. Leider gibt es da ein Problem, denn für eine Anzeige sind acht Portpins notwendig - vier Anzeigen würden demnach 32 Portpins benötigen. Die hat der Mega8 aber nicht. Dafür gibt es aber mehrere Auswege. Schieberegister sind bereits in einem anderen [[AVR-Tutorial:_Schieberegister|Tutorial]] beschrieben. Damit könnte man sich ganz leicht die benötigten 32 Ausgangsleitungen mit nur 3 Portpins erzeugen. Das Prinzip der Ansteuerung unterscheidet sich in nichts von der Ansteurung einer einzelnen 7-Segment Anzeige, lediglich die Art und Weise, wie die &#039;Ausgangspins&#039; zu ihren Werten kommen ist anders und durch die Verwendung von Schieberegistern vorgegeben. An dieser Stelle soll aber eine andere Variante der Ansteuerung gezeigt werden. Im Folgenden werden wir uns daher das [[Multiplexen]] einmal näher ansehen.&lt;br /&gt;
&lt;br /&gt;
Multiplexen bedeutet, dass nicht alle vier Anzeigen gleichzeitig eingeschaltet sind, sondern immer nur Eine für eine kurze Zeit. Geschieht der Wechsel zwischen den Anzeigen schneller als wir Menschen das wahrnehmen können, so erscheinen uns alle vier Anzeigen gleichzeitig in Betrieb zu sein obwohl immer nur Eine für eine kurze Zeit aufleuchtet. Dabei handelt es sich praktisch um eine [[LED-Matrix]]. Die vier Anzeigen können sich dadurch die einzelnen Segmentleitungen teilen und alles was benötigt wird sind 4 zusätzliche Steuerleitungen für die 4 Anzeigen, mit denen jeweils eine Anzeige eingeschaltet wird. Dieses Ein/Ausschalten wird mit einem pnp-Transistor in der Versorgungsspannung jeder Anzeige realisiert, die vom Mega8 am &#039;&#039;&#039;PortC&#039;&#039;&#039; angesteuert werden.&lt;br /&gt;
&lt;br /&gt;
Ein Aspekt dieser Ansteuerungsart ist die Multiplexfrequenz. Sie muss hoch genug sein, um ein Flimmern der Anzeige zu vermeiden. Das menschliche Auge ist träge, im Kino reichen 24 Bilder pro Sekunde, beim Fernseher sind es 50. Um auf der sicheren Seite zu sein, dass auch Standbilder ruhig wirken, sollen jedes Segment mit mindestens 100 Hz angesteuert werden, es also mindestens alle 10ms angeschaltet ist. In Ausnahmefällen können aber selbst 100 Hz noch flimmern, z.B. wenn die Anzeige schnell bewegt wird oder wenn es zu Interferenzerscheinungen mit künstlichen Lichtquellen kommt, die mit Wechselstrom betrieben werden.&lt;br /&gt;
&lt;br /&gt;
Bei genauerer Betrachtung fällt auch auf, dass die vier Anzeigen nicht mehr ganz so hell leuchten wie die eine einzelne Anzeige ohne Multiplexen. Bei wenigen Anzeigen ist dies praktisch kaum sichtbar, erst bei mehreren Anzeigen wird es deutlich. Um dem entgegen zu wirken lässt man pro Segment einfach mehr Strom fließen, bei LEDs dürfen dann 20mA überschritten werden. Als Faustregel gilt, dass der n-fache Strom für die (1/n)-fache Zeit fließen darf. Details finden sich im Datenblatt unter dem Punkt &#039;&#039;&#039;Peak-Current&#039;&#039;&#039; (Spitzenstrom) und &#039;&#039;&#039;Duty-Cycle&#039;&#039;&#039; ([[PWM | Tastverhältnis]]).&lt;br /&gt;
 &lt;br /&gt;
Allerdings gibt es noch ein anderes Problem wenn insgesamt zu viele Anzeigen gemultiplext werden. Die Pulsströme durch die LEDs werden einfach zu hoch. Die meisten LEDs kann man bis 8:1 multiplexen, manchmal auch bis 16:1. Hier fliesst aber schon ein Pulsstrom von 320mA (16 x 20mA), was nicht mehr ganz ungefährlich ist. &#039;&#039;&#039;Strom lässt sich durch Multiplexen nicht sparen&#039;&#039;&#039;, denn die verbrauchte Leistung ändert sich beim n-fachen Strom für 1/n der Zeit nicht. Kritisch wird es aber, wenn das Multiplexen deaktiviert wird (Ausfall der Ansteuerung durch Hardware- oder Softwarefehler) und der n-fache Strom dauerhaft durch eine Segment-LED fließt. Bei 320mA werden die meisten LEDs innerhalb von Sekunden zerstört. Hier muss sichergestellt werden, dass sowohl Programm (Breakpoint im Debugger) als auch Schaltung (Reset, Power-On, [http://www.mikrocontroller.net/topic/107941]) diesen Fall verhindern. Prinzipiell sollte man immer den Pulsstrom und die Multiplexfrequenz einmal überschlagen, bevor der Lötkolben angeworfen wird.&lt;br /&gt;
&lt;br /&gt;
===Schaltung===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tut_7_Seg_03.gif | framed | left | Ansteuerung von vier 7-Segmentanzeigen per Multiplex]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollten die Anzeigen zu schwach leuchten so können, wie bereits beschrieben, die Ströme durch die Anzeigen erhöht werden. Dazu werden die 330 Ohm Widerstände kleiner gemacht. Da hier 4 Anzeigen gemultiplext werden, würden sich Widerstände in der Größenordnung von 100 Ohm anbieten. Auch kann dann der Basiswiderstand der Transistoren verkleinert werden.&lt;br /&gt;
&lt;br /&gt;
===Programm===&lt;br /&gt;
&lt;br /&gt;
Das folgende Programm zeigt eine Möglichkeit zum Multiplexen. Dazu wird ein Timer benutzt, der in regelmässigen Zeitabständen einen Overflow [[Interrupt]] auslöst. Innerhalb der Overflow Interrupt Routine wird&lt;br /&gt;
* die momentan erleuchtete Anzeige abgeschaltet&lt;br /&gt;
* das Muster für die nächste Anzeige am Port D ausgegeben&lt;br /&gt;
* die nächste Anzeige durch eine entsprechende Ausgabe am Port C eingeschaltet&lt;br /&gt;
&lt;br /&gt;
Da Interruptfunktionen kurz sein sollten, holt die Interrupt Routine das auszugebende Muster für jede Stelle direkt aus dem SRAM, wo sie die Ausgabefunktion hinterlassen hat. Dies hat 2 Vorteile:&lt;br /&gt;
* Zum einen braucht die Interrupt Routine die Umrechnung einer Ziffer in das entsprechende Bitmuster nicht selbst machen&lt;br /&gt;
* Zum anderen ist die Anzeigefunktion dadurch unabhängig von dem was angezeigt wird. Die Interrupt Routine gibt das Bitmuster so aus, wie sie es aus dem SRAM liest. Werden die SRAM Zellen mit geeigneten Bitmustern gefüllt, können so auch einige Buchstaben oder Balkengrafik oder auch kleine Balken-Animationen abgespielt werden. Insbesondere letzteres sieht man manchmal bei Consumer-Geräten kurz nach dem Einschalten des Gerätes um eine Art Defektkontrolle zu ermöglichen oder einfach nur als optischer Aufputz.&lt;br /&gt;
&lt;br /&gt;
Die Funktion out_number ist in einer ähnlichen Form auch schon an anderer Stelle vorgekommen: Sie verwendet die Technik der fortgesetzten Subtraktionen um eine Zahl in einzelne Ziffern zu zerlegen. Sobald jede Stelle feststeht, wird über die Codetabelle das Bitmuster aufgesucht, welches für die Interrupt Funktion an der entsprechenden Stelle im SRAM abgelegt wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung&#039;&#039;&#039;: Anders als bei der weiter oben gezeigten Variante wurde die Codetabelle ohne Padding Bytes angelegt. Dadurch ist es auch nicht notwendig derartige Padding Bytes in der Programmierung zu berücksichtigen.&lt;br /&gt;
&lt;br /&gt;
Der Rest ist wieder die übliche Portinitialisierung, Timerinitialisierung und eine einfache Anwendung, indem ein 16 Bit Zähler laufend erhöht und über die Funktion out_number ausgegeben wird. Wie schon im ersten Beispiel, wurde auch hier kein Aufwand getrieben: Zähler um 1 erhöhen und mit Warteschleifen eine gewisse Verzögerungszeit einhalten. In einer realen Applikation wird man das natürlich nicht so machen, sondern ebenfalls einen Timer für diesen Teilaspekt der Aufgabenstellung einsetzen.&lt;br /&gt;
&lt;br /&gt;
Weiterhin ist auch noch interessant. Die Overflow Interrupt Funktion ist wieder so ausgelegt, dass sie völlig transparent zum restlichen Programm ablaufen kann. Dies bedeutet, dass alle verwendeten Register beim Aufruf der Interrupt Funktion gesichert und beim Verlassen wiederhergestellt werden. Dadurch ist man auf der absolut sicheren Seite, hat aber den Nachteil etwas Rechenzeit für manchmal unnötige Sicherungs- und Aufräumarbeiten zu &#039;verschwenden&#039;. Stehen genug freie Register zur Verfügung, dann wird man natürlich diesen Aufwand nicht treiben, sondern ein paar Register ausschließlich für die Zwecke der Behandlung der 7-Segment Anzeige abstellen und sich damit den Aufwand der Registersicherung sparen (mit Ausnahme von &#039;&#039;&#039;SREG&#039;&#039;&#039; natürlich!).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
.def temp  = r16&lt;br /&gt;
.def temp1 = r17&lt;br /&gt;
.def temp2 = r18&lt;br /&gt;
&lt;br /&gt;
.org 0x0000&lt;br /&gt;
           rjmp    main                ; Reset Handler&lt;br /&gt;
.org OVF0addr&lt;br /&gt;
           rjmp    multiplex&lt;br /&gt;
&lt;br /&gt;
;&lt;br /&gt;
;********************************************************************&lt;br /&gt;
; Die Multiplexfunktion&lt;br /&gt;
;&lt;br /&gt;
; Aufgabe dieser Funktion ist es, bei jedem Durchlauf eine andere Stelle&lt;br /&gt;
; der 7-Segmentanzeige zu aktivieren und das dort vorgesehene Muster&lt;br /&gt;
; auszugeben&lt;br /&gt;
; Die Funktion wird regelmässig in einem Timer Interrupt aufgerufen&lt;br /&gt;
;&lt;br /&gt;
multiplex:&lt;br /&gt;
           push    temp                ; Alle verwendeten Register sichern&lt;br /&gt;
           push    temp1&lt;br /&gt;
           in      temp, SREG&lt;br /&gt;
           push    temp&lt;br /&gt;
           push    ZL&lt;br /&gt;
           push    ZH&lt;br /&gt;
&lt;br /&gt;
           ldi     temp1, 0            ; Die 7 Segment ausschalten&lt;br /&gt;
           out     PORTC, temp1&lt;br /&gt;
&lt;br /&gt;
                                       ; Das Muster für die nächste Stelle ausgeben&lt;br /&gt;
                                       ; Dazu zunächst mal berechnen, welches Segment als&lt;br /&gt;
                                       ; nächstest ausgegeben werden muss&lt;br /&gt;
           ldi     ZL, LOW( Segment0 ) &lt;br /&gt;
           ldi     ZH, HIGH( Segment0 )&lt;br /&gt;
           lds     temp, NextSegment&lt;br /&gt;
           add     ZL, temp&lt;br /&gt;
           adc     ZH, temp1&lt;br /&gt;
&lt;br /&gt;
           ld      temp, Z             ; das entsprechende Muster holen und ausgeben&lt;br /&gt;
           out     PORTD, temp&lt;br /&gt;
&lt;br /&gt;
           lds     temp1, NextDigit    ; Und die betreffende Stelle einschalten&lt;br /&gt;
           out     PORTC, temp1&lt;br /&gt;
&lt;br /&gt;
           lds     temp, NextSegment&lt;br /&gt;
           inc     temp&lt;br /&gt;
           lsl     temp1               ; beim nächsten Interrupt kommt reihum die&lt;br /&gt;
           cpi     temp1, $10          ; nächste Stelle dran.&lt;br /&gt;
           brne    multi1&lt;br /&gt;
           ldi     temp, 0&lt;br /&gt;
           ldi     temp1, $01&lt;br /&gt;
&lt;br /&gt;
multi1:&lt;br /&gt;
           sts     NextSegment, temp&lt;br /&gt;
           sts     NextDigit, temp1&lt;br /&gt;
&lt;br /&gt;
           pop     ZH                  ; die gesicherten Register wiederherstellen&lt;br /&gt;
           pop     ZL&lt;br /&gt;
           pop     temp&lt;br /&gt;
           out     SREG, temp&lt;br /&gt;
           pop     temp1&lt;br /&gt;
           pop     temp&lt;br /&gt;
           reti&lt;br /&gt;
;&lt;br /&gt;
;************************************************************************&lt;br /&gt;
; 16 Bit-Zahl aus dem Registerpaar temp (=low), temp1 (=high) ausgeben&lt;br /&gt;
; die Zahl muss kleiner als 10000 sein, da die Zehntausenderstelle&lt;br /&gt;
; nicht berücksichtigt wird.&lt;br /&gt;
; Werden mehr als 4 7-Segmentanzeigen eingesetzt, dann muss dies&lt;br /&gt;
; natürlich auch hier berücksichtigt werden&lt;br /&gt;
;&lt;br /&gt;
out_number:&lt;br /&gt;
           push    temp&lt;br /&gt;
           push    temp1&lt;br /&gt;
&lt;br /&gt;
           ldi     temp2, -1            ; Die Tausenderstelle bestimmen&lt;br /&gt;
_out_tausend:&lt;br /&gt;
           inc     temp2&lt;br /&gt;
           subi    temp, low(1000)      ; -1000&lt;br /&gt;
           sbci    temp1, high(1000)&lt;br /&gt;
           brcc    _out_tausend&lt;br /&gt;
&lt;br /&gt;
           ldi     ZL, low(2*Codes)     ; fuer diese Ziffer das Codemuster fuer&lt;br /&gt;
           ldi     ZH, high(2*Codes)    ; die Anzeige in der Codetabelle nachschlagen&lt;br /&gt;
           add     ZL, temp2&lt;br /&gt;
&lt;br /&gt;
           lpm&lt;br /&gt;
           sts     Segment3, r0         ; und dieses Muster im SRAM ablegen&lt;br /&gt;
                                        ; die OvI Routine sorgt dann duer die Anzeige&lt;br /&gt;
           ldi     temp2, 10&lt;br /&gt;
&lt;br /&gt;
_out_hundert:                           ; die Hunderterstelle bestimmen&lt;br /&gt;
           dec     temp2                &lt;br /&gt;
           subi    temp, low(-100)      ; +100&lt;br /&gt;
           sbci    temp1, high(-100)&lt;br /&gt;
           brcs    _out_hundert&lt;br /&gt;
&lt;br /&gt;
           ldi     ZL, low(2*Codes)     ; wieder in der Codetabelle das entsprechende&lt;br /&gt;
           ldi     ZH, high(2*Codes)    ; Muster nachschlagen&lt;br /&gt;
           add     ZL, temp2&lt;br /&gt;
&lt;br /&gt;
           lpm&lt;br /&gt;
           sts     Segment2, r0         ; und im SRAM hinterlassen&lt;br /&gt;
&lt;br /&gt;
           ldi     temp2, -1&lt;br /&gt;
_out_zehn:                              ; die Zehnerstelle bestimmen&lt;br /&gt;
           inc     temp2&lt;br /&gt;
           subi    temp, low(10)        ; -10&lt;br /&gt;
           sbci    temp1, high(10)&lt;br /&gt;
           brcc    _out_zehn&lt;br /&gt;
&lt;br /&gt;
           ldi     ZL, low(2*Codes)     ; wie gehabt: Die Ziffer in der Codetabelle&lt;br /&gt;
           ldi     ZH, high(2*Codes)    ; aufsuchen&lt;br /&gt;
           add     ZL, temp2&lt;br /&gt;
&lt;br /&gt;
           lpm&lt;br /&gt;
           sts     Segment1, r0         ; und entsprechend im SRAM ablegen&lt;br /&gt;
&lt;br /&gt;
_out_einer:                             ; bleiben noch die Einer&lt;br /&gt;
           subi    temp, low(-10)       ; +10&lt;br /&gt;
           sbci    temp1, high(-10)&lt;br /&gt;
&lt;br /&gt;
           ldi     ZL, low(2*Codes)     ; ... Codetabelle&lt;br /&gt;
           ldi     ZH, high(2*Codes)&lt;br /&gt;
           add     ZL, temp&lt;br /&gt;
&lt;br /&gt;
           lpm&lt;br /&gt;
           sts     Segment0, r0         ; und ans SRAm ausgeben&lt;br /&gt;
&lt;br /&gt;
           pop     temp1&lt;br /&gt;
           pop     temp&lt;br /&gt;
&lt;br /&gt;
           ret&lt;br /&gt;
;&lt;br /&gt;
;**************************************************************************&lt;br /&gt;
;&lt;br /&gt;
main:&lt;br /&gt;
           ldi     temp, LOW(RAMEND)  ; Stackpointer initialisieren&lt;br /&gt;
           out     SPL, temp&lt;br /&gt;
           ldi     temp, HIGH(RAMEND)&lt;br /&gt;
           out     SPH, temp&lt;br /&gt;
;                                     die Segmenttreiber initialisieren&lt;br /&gt;
           ldi     temp, $FF&lt;br /&gt;
           out     DDRD, temp&lt;br /&gt;
;                                     die Treiber für die einzelnen Stellen&lt;br /&gt;
           ldi     temp, $0F&lt;br /&gt;
           out     DDRC, temp&lt;br /&gt;
;                                     initialisieren der Steuerung für die&lt;br /&gt;
;                                     Interrupt Routine&lt;br /&gt;
           ldi     temp, 1&lt;br /&gt;
           sts     NextDigit, temp&lt;br /&gt;
&lt;br /&gt;
           ldi     temp, 0&lt;br /&gt;
           sts     NextSegment, temp&lt;br /&gt;
&lt;br /&gt;
           ldi     temp, ( 1 &amp;lt;&amp;lt; CS01 ) | ( 1 &amp;lt;&amp;lt; CS00 )&lt;br /&gt;
           out     TCCR0, temp&lt;br /&gt;
&lt;br /&gt;
           ldi     temp, 1 &amp;lt;&amp;lt; TOIE0&lt;br /&gt;
           out     TIMSK, temp&lt;br /&gt;
&lt;br /&gt;
           sei&lt;br /&gt;
&lt;br /&gt;
           ldi     temp, 0&lt;br /&gt;
           ldi     temp1, 0&lt;br /&gt;
&lt;br /&gt;
loop:&lt;br /&gt;
           inc     temp&lt;br /&gt;
           brne    _loop&lt;br /&gt;
           inc     temp1&lt;br /&gt;
_loop:&lt;br /&gt;
           rcall    out_number&lt;br /&gt;
&lt;br /&gt;
           cpi     temp, low( 4000 )&lt;br /&gt;
           brne    wait&lt;br /&gt;
           cpi     temp1, high( 4000 )&lt;br /&gt;
           brne    wait&lt;br /&gt;
&lt;br /&gt;
           ldi     temp, 0&lt;br /&gt;
           ldi     temp1, 0&lt;br /&gt;
&lt;br /&gt;
wait:      ldi     r21, 1&lt;br /&gt;
wait0:     ldi     r22, 0&lt;br /&gt;
wait1:     ldi     r23, 0&lt;br /&gt;
wait2:     dec     r23&lt;br /&gt;
           brne    wait2&lt;br /&gt;
           dec     r22&lt;br /&gt;
           brne    wait1&lt;br /&gt;
           dec     r21&lt;br /&gt;
           brne    wait0&lt;br /&gt;
&lt;br /&gt;
           rjmp    loop&lt;br /&gt;
&lt;br /&gt;
Codes:&lt;br /&gt;
    .db  0b11000000, 0b11111001     ; 0: a, b, c, d, e, f&lt;br /&gt;
                                    ; 1: b, c&lt;br /&gt;
    .db  0b10100100, 0b10110000     ; 2: a, b, d, e, g&lt;br /&gt;
                                    ; 3: a, b, c, d, g&lt;br /&gt;
    .db  0b10011001, 0b10010010     ; 4: b, c, f, g&lt;br /&gt;
                                    ; 5: a, c, d, f, g&lt;br /&gt;
    .db  0b10000010, 0b11111000     ; 6: a, c, d, e, f, g&lt;br /&gt;
                                    ; 7: a, b, c&lt;br /&gt;
    .db  0b10000000, 0b10010000     ; 8: a, b, c, d, e, f, g&lt;br /&gt;
                                    ; 9: a, b, c, d, f, g &lt;br /&gt;
&lt;br /&gt;
           .DSEG&lt;br /&gt;
NextDigit:   .byte 1         ; Bitmuster für die Aktivierung des nächsten Segments&lt;br /&gt;
NextSegment: .byte 1         ; Nummer des nächsten aktiven Segments&lt;br /&gt;
Segment0:    .byte 1         ; Ausgabemuster für Segment 0&lt;br /&gt;
Segment1:    .byte 1         ; Ausgabemuster für Segment 1&lt;br /&gt;
Segment2:    .byte 1         ; Ausgabemuster für Segment 2&lt;br /&gt;
Segment3:    .byte 1         ; Ausgabemuster für Segment 3&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Navigation_zurückhoch|&lt;br /&gt;
zurücktext=SRAM|&lt;br /&gt;
zurücklink=AVR-Tutorial: SRAM|&lt;br /&gt;
hochtext=Inhaltsverzeichnis|&lt;br /&gt;
hochlink=AVR-Tutorial}}&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR]][[Category:AVR-Tutorial]]&lt;/div&gt;</summary>
		<author><name>85.183.44.11</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_7-Segment-Anzeige&amp;diff=34583</id>
		<title>AVR-Tutorial: 7-Segment-Anzeige</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_7-Segment-Anzeige&amp;diff=34583"/>
		<updated>2009-02-24T13:37:13Z</updated>

		<summary type="html">&lt;p&gt;85.183.44.11: /* Typen von 7-Segment Anzeigen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Die Ausgabe von Zahlenwerten auf ein Text-LCD ist sicherlich das Nonplusultra, aber manchmal liegen die Dinge sehr viel einfacher. Um beispielsweise eine Temperatur anzuzeigen ist ein LCD etwas Overkill. In solchen Fällen kann die Ausgabe auf ein paar 7-Segmentanzeigen gemacht werden. Ausserdem haben 7-Segmentanzeigen einen ganz besonderen Charme :-)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Eine einzelne 7-Segment Anzeige==&lt;br /&gt;
&lt;br /&gt;
===Schaltung===&lt;br /&gt;
&lt;br /&gt;
Eine einzelne 7-Segmentanzeige wird nach dem folgenden Schema am &#039;&#039;&#039;Port D&#039;&#039;&#039; des Mega8 angeschlossen. Port D wurde deshalb gewählt, da er am Mega8 als einziger Port aus den vollen 8 Bit besteht. Die 7-Segmentanzeige hat eine gemeinsame Anode.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tut_7_Seg_01.gif | framed | left | Ansteuerung einer einzelnen 7-Segmentanzeige]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Welcher Pin an der Anzeige welchem Segment (a-g) bzw. dem Dezimalpunkt entspricht wird am besten dem Datenblatt zur Anzeige entnommen. Im Folgenden wird von dieser Segmentbelegung ausgegangen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tut_7_Seg_02.gif | framed | left | Pinbelegung der 7-Segmentanzeige]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wird eine andere Belegung genutzt dann ist das prinzipiell möglich, jedoch müsste das in der Programmierung berücksichtigt werden.&lt;br /&gt;
&lt;br /&gt;
Da eine 7-Segmentanzeige konzeptionell sieben einzelnen LEDs entspricht, ergibt sich im Prinzip keine Änderung in der Ansteuerung einer derartigen Anzeige im Vergleich zur LED Ansteuerung wie sie im [[AVR-Tutorial: IO-Grundlagen]] gezeigt wird. Genau wie bei den einzelnen LEDs wird eine davon eingeschaltet, indem der zugehörige Port Pin auf 0 gesetzt wird. Aber anders als bei einzelnen LED möchte man mit einer derartigen Anzeige eine Ziffernanzeige erhalten. Dazu ist es lediglich notwendig, für eine bestimmte Ziffer die richtigen LEDs einzuschalten.&lt;br /&gt;
&lt;br /&gt;
===Codetabelle===&lt;br /&gt;
&lt;br /&gt;
Die Umkodierung von einzelnen Ziffern in ein bestimmtes Ausgabemuster bezeichnet man als Codetabelle. Die auszugebende Ziffer wird als Offset zum Anfang dieser Tabelle aufgefasst und aus der Tabelle erhält man ein Byte (Code), welches direkt auf den Port ausgegeben werden kann und das entsprechende Bitmuster enthält, sodass die für diese Ziffer notwendigen LED ein- bzw. ausgeschaltet sind.&lt;br /&gt;
&lt;br /&gt;
Beispiel: Um die Ziffer &#039;&#039;&#039;3&#039;&#039;&#039; anzuzeigen, müssen auf der Anzeige die Segmente &#039;&#039;&#039;a&#039;&#039;&#039;, &#039;&#039;&#039;b&#039;&#039;&#039;, &#039;&#039;&#039;c&#039;&#039;&#039;, &#039;&#039;&#039;d&#039;&#039;&#039; und &#039;&#039;&#039;g&#039;&#039;&#039; aufleuchten. Alle anderen Segmente sollen dunkel sein.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tut_7_Seg_02a.gif | framed | left | Darstellung der Ziffer &amp;quot;3&amp;quot;]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aus dem Anschlußschema ergibt sich, dass die dazu notwendige Ausgabe am Port binär &#039;&#039;&#039;10110000&#039;&#039;&#039; lauten muss. Untersucht man dies für alle Ziffern, so ergibt sich folgende Tabelle:&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
    .db  0b11000000     ; 0: a, b, c, d, e, f&lt;br /&gt;
    .db  0b11111001     ; 1: b, c&lt;br /&gt;
    .db  0b10100100     ; 2: a, b, d, e, g&lt;br /&gt;
    .db  0b10110000     ; 3: a, b, c, d, g&lt;br /&gt;
    .db  0b10011001     ; 4: b, c, f, g&lt;br /&gt;
    .db  0b10010010     ; 5: a, c, d, f, g&lt;br /&gt;
    .db  0b10000010     ; 6: a, c, d, e, f, g&lt;br /&gt;
    .db  0b11111000     ; 7: a, b, c&lt;br /&gt;
    .db  0b10000000     ; 8: a, b, c, d, e, f, g&lt;br /&gt;
    .db  0b10010000     ; 9: a, b, c, d, f, g&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Programm===&lt;br /&gt;
&lt;br /&gt;
Das Testprogramm stellt nacheinander die Ziffern 0 bis 9 auf der 7-Segmentanzeige dar. Die jeweils auszugebende Zahl steht im Register &#039;&#039;&#039;count&#039;&#039;&#039; und wird innerhalb der Schleife um jeweils 1 erhöht. Hat das Register den Wert 10 erreicht, so wird es wieder auf 0 zurückgesetzt. Nach der Erhöhung folgt eine Warteschleife, welche dafür sorgt, dass bis zur nächsten Ausgabe eine gewisse Zeit vergeht. Normalerweise macht man keine derartigen langen Warteschleifen, aber hier geht es ja nicht ums Warten sondern um die Ansteuerung einer 7-Segmentanzeige. Einen Timer dafür zu benutzen wäre zunächst zuviel Aufwand.&lt;br /&gt;
&lt;br /&gt;
Die eigentliche Ausgabe und damit der in diesem Artikel interessante Teil findet jedoch direkt nach dem Label &amp;lt;i&amp;gt;loop&amp;lt;/i&amp;gt; statt. Die bereits bekannte Codetabelle wird mittels &#039;&#039;&#039;.db&#039;&#039;&#039; Direktive (&#039;&#039;&#039;d&#039;&#039;&#039;efine &#039;&#039;&#039;b&#039;&#039;&#039;yte) in den [[Speicher#Flash-ROM | Flash-Speicher]] gelegt. Der Zugriff darauf erfolgt über den Z-Pointer und dem Befehl &#039;&#039;&#039;lpm&#039;&#039;&#039;. Zusätzlich wird vor dem Zugriff noch der Wert des Registers &#039;&#039;&#039;count&#039;&#039;&#039; und damit der aktuelle Zählerwert zum Z-Pointer addiert.&lt;br /&gt;
&lt;br /&gt;
Beachtet werden muss nur, dass der Zählerwert verdoppelt werden muss. Dies hat folgenden Grund: Wird die Tabelle so wie hier gezeigt mittels einzelnen &#039;&#039;&#039;.db&#039;&#039;&#039; Anweisungen aufgebaut, so fügt der Assembler sog. &#039;&#039;&#039;Padding Bytes&#039;&#039;&#039; zwischen die einzelnen Bytes ein, damit jede &#039;&#039;&#039;.db&#039;&#039;&#039; Anweisung auf einer geraden Speicheradresse liegt. Dies ist eine direkte Folge der Tatsache, dass der Flash-Speicher &#039;&#039;&#039;wortweise&#039;&#039;&#039; (16 Bit) und nicht &#039;&#039;&#039;byteweise&#039;&#039;&#039; (8 Bit) organisiert ist. Da aber von einem .db in der Tabelle zum nächsten .db eine Differenz von 2 Bytes vorliegt, muss dies in der Berechnung berücksichtigt werden. Im zweiten Beispiel auf dieser Seite wird dies anders gemacht. Dort wird gezeigt wie man durch eine andere Schreibweise der Tabelle das Erzeugen der Padding Bytes durch den Assembler verhindern kann.&lt;br /&gt;
&lt;br /&gt;
Aus dem gleichen Grund wird auch der Z-Pointer mit dem 2-fachen der Startadresse der Tabelle geladen. Die Startadresse wird vom Assembler in wortweiser Adressierung eingesetzt, &#039;&#039;&#039;lpm&#039;&#039;&#039; möchte die Zugriffsadresse als Byteadresse angegeben haben.&lt;br /&gt;
&lt;br /&gt;
Interessant ist auch, dass in der Berechnung ein Register benötigt wird, welches den Wert 0 enthält. Dies deshalb, da es im AVR keinen Befehl gibt der eine Konstante mit gleichzeitiger Berücksichtigung des Carry-Bits addieren kann. Daher muss diese Konstante zunächst in ein Register geladen werden und erst dann kann die Addition mithilfe dieses Registers vorgenommen werden. Das Interessante daran ist nun, dass dieser Umstand in sehr vielen Programmen vorkommt und es sich bei der Konstanten in der überwiegenden Mehrzahl der Fälle um die Konstante 0 handelt. Viele Programmierer reservieren daher von vorne herein ein Register für diesen Zweck und nennen es das Zero-Register. Sinnvollerweise legt man dieses Register in den Breich r0..r15, da diese Register etwas zweitklassig sind (ldi, cpi etc. funktionieren nicht damit).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
.def zero  = r1&lt;br /&gt;
.def count = r16&lt;br /&gt;
.def temp1 = r17&lt;br /&gt;
&lt;br /&gt;
.org 0x0000&lt;br /&gt;
           rjmp    main                ; Reset Handler&lt;br /&gt;
;&lt;br /&gt;
main:&lt;br /&gt;
           ldi     temp1, LOW(RAMEND)  ; Stackpointer initialisieren&lt;br /&gt;
           out     SPL, temp1&lt;br /&gt;
           ldi     temp1, HIGH(RAMEND)&lt;br /&gt;
           out     SPH, temp1&lt;br /&gt;
;&lt;br /&gt;
           ldi     temp1, $FF        ; die Anzeige hängt am Port D&lt;br /&gt;
           out     DDRD, temp1       ; alle Pins auf Ausgang&lt;br /&gt;
;&lt;br /&gt;
           ldi     count, 0          ; und den Zähler initialisieren&lt;br /&gt;
           mov     zero, count&lt;br /&gt;
;&lt;br /&gt;
loop:&lt;br /&gt;
           ldi     ZL, LOW(Codes*2)  ; die Startadresse der Tabelle in den&lt;br /&gt;
           ldi     ZH, HIGH(Codes*2) ; Z-Pointer laden&lt;br /&gt;
&lt;br /&gt;
           mov     temp1, count      ; die wortweise Adressierung der Tabelle&lt;br /&gt;
           add     temp1, count      ; berücksichtigen&lt;br /&gt;
&lt;br /&gt;
           add     ZL, temp1         ; und ausgehend vom Tabellenanfang&lt;br /&gt;
           adc     ZH, zero          ; die Adresse des Code Bytes berechnen&lt;br /&gt;
&lt;br /&gt;
           lpm                       ; dieses Code Byte in das Register r0 laden&lt;br /&gt;
&lt;br /&gt;
           out     PORTD, r0         ; und an die Anzeige ausgeben&lt;br /&gt;
;&lt;br /&gt;
           inc     count             ; den Zähler erhöhen, wobei der Zähler&lt;br /&gt;
           cpi     count, 10         ; immer nur von 0 bis 9 zählen soll&lt;br /&gt;
           brne    wait&lt;br /&gt;
           ldi     count, 0&lt;br /&gt;
;&lt;br /&gt;
wait:      ldi     r17, 10           ; und etwas warten, damit die Ziffer auf&lt;br /&gt;
wait0:     ldi     r18, 0            ; der Anzeige auch lesbar ist, bevor die&lt;br /&gt;
wait1:     ldi     r19, 0            ; nächste Ziffer gezeigt wird&lt;br /&gt;
wait2:     dec     r19&lt;br /&gt;
           brne    wait2&lt;br /&gt;
           dec     r18&lt;br /&gt;
           brne    wait1&lt;br /&gt;
           dec     r17&lt;br /&gt;
           brne    wait0&lt;br /&gt;
;&lt;br /&gt;
           rjmp    loop              ; auf zur nächsten Ausgabe&lt;br /&gt;
;&lt;br /&gt;
Codes:                               ; Die Codetabelle für die Ziffern 0 bis 9&lt;br /&gt;
                                     ; sie regelt, welche Segmente für eine bestimmte&lt;br /&gt;
                                     ; Ziffer eingeschaltet werden müssen&lt;br /&gt;
                                     ;&lt;br /&gt;
           .db     0b11000000        ; 0: a, b, c, d, e, f&lt;br /&gt;
           .db     0b11111001        ; 1: b, c&lt;br /&gt;
           .db     0b10100100        ; 2: a, b, d, e, g&lt;br /&gt;
           .db     0b10110000        ; 3: a, b, c, d, g&lt;br /&gt;
           .db     0b10011001        ; 4: b, c, f, g&lt;br /&gt;
           .db     0b10010010        ; 5: a, c, d, f, g&lt;br /&gt;
           .db     0b10000010        ; 6: a, c, d, e, f, g&lt;br /&gt;
           .db     0b11111000        ; 7: a, b, c&lt;br /&gt;
           .db     0b10000000        ; 8: a, b, c, d, e, f, g&lt;br /&gt;
           .db     0b10010000        ; 9: a, b, c, d, f, g &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Mehrere 7-Segment Anzeigen (Multiplexen)==&lt;br /&gt;
&lt;br /&gt;
Mit dem bisherigen Vorwissen könnte man sich jetzt daran machen, auch einmal drei oder vier Anzeigen mit dem Mega8 anzusteuern. Leider gibt es da ein Problem, denn für eine Anzeige sind acht Portpins notwendig - vier Anzeigen würden demnach 32 Portpins benötigen. Die hat der Mega8 aber nicht. Dafür gibt es aber mehrere Auswege. Schieberegister sind bereits in einem anderen [[AVR-Tutorial:_Schieberegister|Tutorial]] beschrieben. Damit könnte man sich ganz leicht die benötigten 32 Ausgangsleitungen mit nur 3 Portpins erzeugen. Das Prinzip der Ansteuerung unterscheidet sich in nichts von der Ansteurung einer einzelnen 7-Segment Anzeige, lediglich die Art und Weise, wie die &#039;Ausgangspins&#039; zu ihren Werten kommen ist anders und durch die Verwendung von Schieberegistern vorgegeben. An dieser Stelle soll aber eine andere Variante der Ansteuerung gezeigt werden. Im Folgenden werden wir uns daher das [[Multiplexen]] einmal näher ansehen.&lt;br /&gt;
&lt;br /&gt;
Multiplexen bedeutet, dass nicht alle vier Anzeigen gleichzeitig eingeschaltet sind, sondern immer nur Eine für eine kurze Zeit. Geschieht der Wechsel zwischen den Anzeigen schneller als wir Menschen das wahrnehmen können, so erscheinen uns alle vier Anzeigen gleichzeitig in Betrieb zu sein obwohl immer nur Eine für eine kurze Zeit aufleuchtet. Dabei handelt es sich praktisch um eine [[LED-Matrix]]. Die vier Anzeigen können sich dadurch die einzelnen Segmentleitungen teilen und alles was benötigt wird sind 4 zusätzliche Steuerleitungen für die 4 Anzeigen, mit denen jeweils eine Anzeige eingeschaltet wird. Dieses Ein/Ausschalten wird mit einem pnp-Transistor in der Versorgungsspannung jeder Anzeige realisiert, die vom Mega8 am &#039;&#039;&#039;PortC&#039;&#039;&#039; angesteuert werden.&lt;br /&gt;
&lt;br /&gt;
Ein Aspekt dieser Ansteuerungsart ist die Multiplexfrequenz. Sie muss hoch genug sein, um ein Flimmern der Anzeige zu vermeiden. Das menschliche Auge ist träge, im Kino reichen 24 Bilder pro Sekunde, beim Fernseher sind es 50. Um auf der sicheren Seite zu sein, dass auch Standbilder ruhig wirken, sollen jedes Segment mit mindestens 100 Hz angesteuert werden, es also mindestens alle 10ms angeschaltet ist. In Ausnahmefällen können aber selbst 100 Hz noch flimmern, z.B. wenn die Anzeige schnell bewegt wird oder wenn es zu Interferenzerscheinungen mit künstlichen Lichtquellen kommt, die mit Wechselstrom betrieben werden.&lt;br /&gt;
&lt;br /&gt;
Bei genauerer Betrachtung fällt auch auf, dass die vier Anzeigen nicht mehr ganz so hell leuchten wie die eine einzelne Anzeige ohne Multiplexen. Bei wenigen Anzeigen ist dies praktisch kaum sichtbar, erst bei mehreren Anzeigen wird es deutlich. Um dem entgegen zu wirken lässt man pro Segment einfach mehr Strom fließen, bei LEDs dürfen dann 20mA überschritten werden. Als Faustregel gilt, dass der n-fache Strom für die (1/n)-fache Zeit fließen darf. Details finden sich im Datenblatt unter dem Punkt &#039;&#039;&#039;Peak-Current&#039;&#039;&#039; (Spitzenstrom) und &#039;&#039;&#039;Duty-Cycle&#039;&#039;&#039; ([[PWM | Tastverhältnis]]).&lt;br /&gt;
 &lt;br /&gt;
Allerdings gibt es noch ein anderes Problem wenn insgesamt zu viele Anzeigen gemultiplext werden. Die Pulsströme durch die LEDs werden einfach zu hoch. Die meisten LEDs kann man bis 8:1 multiplexen, manchmal auch bis 16:1. Hier fliesst aber schon ein Pulsstrom von 320mA (16 x 20mA), was nicht mehr ganz ungefährlich ist. &#039;&#039;&#039;Strom lässt sich durch Multiplexen nicht sparen&#039;&#039;&#039;, denn die verbrauchte Leistung ändert sich beim n-fachen Strom für 1/n der Zeit nicht. Kritisch wird es aber, wenn das Multiplexen deaktiviert wird (Ausfall der Ansteuerung durch Hardware- oder Softwarefehler) und der n-fache Strom dauerhaft durch eine Segment-LED fließt. Bei 320mA werden die meisten LEDs innerhalb von Sekunden zerstört. Hier muss sichergestellt werden, dass sowohl Programm (Breakpoint im Debugger) als auch Schaltung (Reset, Power-On, [http://www.mikrocontroller.net/topic/107941]) diesen Fall verhindern. Prinzipiell sollte man immer den Pulsstrom und die Multiplexfrequenz einmal überschlagen, bevor der Lötkolben angeworfen wird.&lt;br /&gt;
&lt;br /&gt;
===Schaltung===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tut_7_Seg_03.gif | framed | left | Ansteuerung von vier 7-Segmentanzeigen per Multiplex]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sollten die Anzeigen zu schwach leuchten so können, wie bereits beschrieben, die Ströme durch die Anzeigen erhöht werden. Dazu werden die 330 Ohm Widerstände kleiner gemacht. Da hier 4 Anzeigen gemultiplext werden, würden sich Widerstände in der Größenordnung von 100 Ohm anbieten. Auch kann dann der Basiswiderstand der Transistoren verkleinert werden.&lt;br /&gt;
&lt;br /&gt;
===Programm===&lt;br /&gt;
&lt;br /&gt;
Das folgende Programm zeigt eine Möglichkeit zum Multiplexen. Dazu wird ein Timer benutzt, der in regelmässigen Zeitabständen einen Overflow [[Interrupt]] auslöst. Innerhalb der Overflow Interrupt Routine wird&lt;br /&gt;
* die momentan erleuchtete Anzeige abgeschaltet&lt;br /&gt;
* das Muster für die nächste Anzeige am Port D ausgegeben&lt;br /&gt;
* die nächste Anzeige durch eine entsprechende Ausgabe am Port C eingeschaltet&lt;br /&gt;
&lt;br /&gt;
Da Interruptfunktionen kurz sein sollten, holt die Interrupt Routine das auszugebende Muster für jede Stelle direkt aus dem SRAM, wo sie die Ausgabefunktion hinterlassen hat. Dies hat 2 Vorteile:&lt;br /&gt;
* Zum einen braucht die Interrupt Routine die Umrechnung einer Ziffer in das entsprechende Bitmuster nicht selbst machen&lt;br /&gt;
* Zum anderen ist die Anzeigefunktion dadurch unabhängig von dem was angezeigt wird. Die Interrupt Routine gibt das Bitmuster so aus, wie sie es aus dem SRAM liest. Werden die SRAM Zellen mit geeigneten Bitmustern gefüllt, können so auch einige Buchstaben oder Balkengrafik oder auch kleine Balken-Animationen abgespielt werden. Insbesondere letzteres sieht man manchmal bei Consumer-Geräten kurz nach dem Einschalten des Gerätes um eine Art Defektkontrolle zu ermöglichen oder einfach nur als optischer Aufputz.&lt;br /&gt;
&lt;br /&gt;
Die Funktion out_number ist in einer ähnlichen Form auch schon an anderer Stelle vorgekommen: Sie verwendet die Technik der fortgesetzten Subtraktionen um eine Zahl in einzelne Ziffern zu zerlegen. Sobald jede Stelle feststeht, wird über die Codetabelle das Bitmuster aufgesucht, welches für die Interrupt Funktion an der entsprechenden Stelle im SRAM abgelegt wird.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Achtung&#039;&#039;&#039;: Anders als bei der weiter oben gezeigten Variante wurde die Codetabelle ohne Padding Bytes angelegt. Dadurch ist es auch nicht notwendig derartige Padding Bytes in der Programmierung zu berücksichtigen.&lt;br /&gt;
&lt;br /&gt;
Der Rest ist wieder die übliche Portinitialisierung, Timerinitialisierung und eine einfache Anwendung, indem ein 16 Bit Zähler laufend erhöht und über die Funktion out_number ausgegeben wird. Wie schon im ersten Beispiel, wurde auch hier kein Aufwand getrieben: Zähler um 1 erhöhen und mit Warteschleifen eine gewisse Verzögerungszeit einhalten. In einer realen Applikation wird man das natürlich nicht so machen, sondern ebenfalls einen Timer für diesen Teilaspekt der Aufgabenstellung einsetzen.&lt;br /&gt;
&lt;br /&gt;
Weiterhin ist auch noch interessant. Die Overflow Interrupt Funktion ist wieder so ausgelegt, dass sie völlig transparent zum restlichen Programm ablaufen kann. Dies bedeutet, dass alle verwendeten Register beim Aufruf der Interrupt Funktion gesichert und beim Verlassen wiederhergestellt werden. Dadurch ist man auf der absolut sicheren Seite, hat aber den Nachteil etwas Rechenzeit für manchmal unnötige Sicherungs- und Aufräumarbeiten zu &#039;verschwenden&#039;. Stehen genug freie Register zur Verfügung, dann wird man natürlich diesen Aufwand nicht treiben, sondern ein paar Register ausschließlich für die Zwecke der Behandlung der 7-Segment Anzeige abstellen und sich damit den Aufwand der Registersicherung sparen (mit Ausnahme von &#039;&#039;&#039;SREG&#039;&#039;&#039; natürlich!).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
.include &amp;quot;m8def.inc&amp;quot;&lt;br /&gt;
&lt;br /&gt;
.def temp  = r16&lt;br /&gt;
.def temp1 = r17&lt;br /&gt;
.def temp2 = r18&lt;br /&gt;
&lt;br /&gt;
.org 0x0000&lt;br /&gt;
           rjmp    main                ; Reset Handler&lt;br /&gt;
.org OVF0addr&lt;br /&gt;
           rjmp    multiplex&lt;br /&gt;
&lt;br /&gt;
;&lt;br /&gt;
;********************************************************************&lt;br /&gt;
; Die Multiplexfunktion&lt;br /&gt;
;&lt;br /&gt;
; Aufgabe dieser Funktion ist es, bei jedem Durchlauf eine andere Stelle&lt;br /&gt;
; der 7-Segmentanzeige zu aktivieren und das dort vorgesehene Muster&lt;br /&gt;
; auszugeben&lt;br /&gt;
; Die Funktion wird regelmässig in einem Timer Interrupt aufgerufen&lt;br /&gt;
;&lt;br /&gt;
multiplex:&lt;br /&gt;
           push    temp                ; Alle verwendeten Register sichern&lt;br /&gt;
           push    temp1&lt;br /&gt;
           in      temp, SREG&lt;br /&gt;
           push    temp&lt;br /&gt;
           push    ZL&lt;br /&gt;
           push    ZH&lt;br /&gt;
&lt;br /&gt;
           ldi     temp1, 0            ; Die 7 Segment ausschalten&lt;br /&gt;
           out     PORTC, temp1&lt;br /&gt;
&lt;br /&gt;
                                       ; Das Muster für die nächste Stelle ausgeben&lt;br /&gt;
                                       ; Dazu zunächst mal berechnen, welches Segment als&lt;br /&gt;
                                       ; nächstest ausgegeben werden muss&lt;br /&gt;
           ldi     ZL, LOW( Segment0 ) &lt;br /&gt;
           ldi     ZH, HIGH( Segment0 )&lt;br /&gt;
           lds     temp, NextSegment&lt;br /&gt;
           add     ZL, temp&lt;br /&gt;
           adc     ZH, temp1&lt;br /&gt;
&lt;br /&gt;
           ld      temp, Z             ; das entsprechende Muster holen und ausgeben&lt;br /&gt;
           out     PORTD, temp&lt;br /&gt;
&lt;br /&gt;
           lds     temp1, NextDigit    ; Und die betreffende Stelle einschalten&lt;br /&gt;
           out     PORTC, temp1&lt;br /&gt;
&lt;br /&gt;
           lds     temp, NextSegment&lt;br /&gt;
           inc     temp&lt;br /&gt;
           lsl     temp1               ; beim nächsten Interrupt kommt reihum die&lt;br /&gt;
           cpi     temp1, $10          ; nächste Stelle dran.&lt;br /&gt;
           brne    multi1&lt;br /&gt;
           ldi     temp, 0&lt;br /&gt;
           ldi     temp1, $01&lt;br /&gt;
&lt;br /&gt;
multi1:&lt;br /&gt;
           sts     NextSegment, temp&lt;br /&gt;
           sts     NextDigit, temp1&lt;br /&gt;
&lt;br /&gt;
           pop     ZH                  ; die gesicherten Register wiederherstellen&lt;br /&gt;
           pop     ZL&lt;br /&gt;
           pop     temp&lt;br /&gt;
           out     SREG, temp&lt;br /&gt;
           pop     temp1&lt;br /&gt;
           pop     temp&lt;br /&gt;
           reti&lt;br /&gt;
;&lt;br /&gt;
;************************************************************************&lt;br /&gt;
; 16 Bit-Zahl aus dem Registerpaar temp (=low), temp1 (=high) ausgeben&lt;br /&gt;
; die Zahl muss kleiner als 10000 sein, da die Zehntausenderstelle&lt;br /&gt;
; nicht berücksichtigt wird.&lt;br /&gt;
; Werden mehr als 4 7-Segmentanzeigen eingesetzt, dann muss dies&lt;br /&gt;
; natürlich auch hier berücksichtigt werden&lt;br /&gt;
;&lt;br /&gt;
out_number:&lt;br /&gt;
           push    temp&lt;br /&gt;
           push    temp1&lt;br /&gt;
&lt;br /&gt;
           ldi     temp2, -1            ; Die Tausenderstelle bestimmen&lt;br /&gt;
_out_tausend:&lt;br /&gt;
           inc     temp2&lt;br /&gt;
           subi    temp, low(1000)      ; -1000&lt;br /&gt;
           sbci    temp1, high(1000)&lt;br /&gt;
           brcc    _out_tausend&lt;br /&gt;
&lt;br /&gt;
           ldi     ZL, low(2*Codes)     ; fuer diese Ziffer das Codemuster fuer&lt;br /&gt;
           ldi     ZH, high(2*Codes)    ; die Anzeige in der Codetabelle nachschlagen&lt;br /&gt;
           add     ZL, temp2&lt;br /&gt;
&lt;br /&gt;
           lpm&lt;br /&gt;
           sts     Segment3, r0         ; und dieses Muster im SRAM ablegen&lt;br /&gt;
                                        ; die OvI Routine sorgt dann duer die Anzeige&lt;br /&gt;
           ldi     temp2, 10&lt;br /&gt;
&lt;br /&gt;
_out_hundert:                           ; die Hunderterstelle bestimmen&lt;br /&gt;
           dec     temp2                &lt;br /&gt;
           subi    temp, low(-100)      ; +100&lt;br /&gt;
           sbci    temp1, high(-100)&lt;br /&gt;
           brcs    _out_hundert&lt;br /&gt;
&lt;br /&gt;
           ldi     ZL, low(2*Codes)     ; wieder in der Codetabelle das entsprechende&lt;br /&gt;
           ldi     ZH, high(2*Codes)    ; Muster nachschlagen&lt;br /&gt;
           add     ZL, temp2&lt;br /&gt;
&lt;br /&gt;
           lpm&lt;br /&gt;
           sts     Segment2, r0         ; und im SRAM hinterlassen&lt;br /&gt;
&lt;br /&gt;
           ldi     temp2, -1&lt;br /&gt;
_out_zehn:                              ; die Zehnerstelle bestimmen&lt;br /&gt;
           inc     temp2&lt;br /&gt;
           subi    temp, low(10)        ; -10&lt;br /&gt;
           sbci    temp1, high(10)&lt;br /&gt;
           brcc    _out_zehn&lt;br /&gt;
&lt;br /&gt;
           ldi     ZL, low(2*Codes)     ; wie gehabt: Die Ziffer in der Codetabelle&lt;br /&gt;
           ldi     ZH, high(2*Codes)    ; aufsuchen&lt;br /&gt;
           add     ZL, temp2&lt;br /&gt;
&lt;br /&gt;
           lpm&lt;br /&gt;
           sts     Segment1, r0         ; und entsprechend im SRAM ablegen&lt;br /&gt;
&lt;br /&gt;
_out_einer:                             ; bleiben noch die Einer&lt;br /&gt;
           subi    temp, low(-10)       ; +10&lt;br /&gt;
           sbci    temp1, high(-10)&lt;br /&gt;
&lt;br /&gt;
           ldi     ZL, low(2*Codes)     ; ... Codetabelle&lt;br /&gt;
           ldi     ZH, high(2*Codes)&lt;br /&gt;
           add     ZL, temp&lt;br /&gt;
&lt;br /&gt;
           lpm&lt;br /&gt;
           sts     Segment0, r0         ; und ans SRAm ausgeben&lt;br /&gt;
&lt;br /&gt;
           pop     temp1&lt;br /&gt;
           pop     temp&lt;br /&gt;
&lt;br /&gt;
           ret&lt;br /&gt;
;&lt;br /&gt;
;**************************************************************************&lt;br /&gt;
;&lt;br /&gt;
main:&lt;br /&gt;
           ldi     temp, LOW(RAMEND)  ; Stackpointer initialisieren&lt;br /&gt;
           out     SPL, temp&lt;br /&gt;
           ldi     temp, HIGH(RAMEND)&lt;br /&gt;
           out     SPH, temp&lt;br /&gt;
;                                     die Segmenttreiber initialisieren&lt;br /&gt;
           ldi     temp, $FF&lt;br /&gt;
           out     DDRD, temp&lt;br /&gt;
;                                     die Treiber für die einzelnen Stellen&lt;br /&gt;
           ldi     temp, $0F&lt;br /&gt;
           out     DDRC, temp&lt;br /&gt;
;                                     initialisieren der Steuerung für die&lt;br /&gt;
;                                     Interrupt Routine&lt;br /&gt;
           ldi     temp, 1&lt;br /&gt;
           sts     NextDigit, temp&lt;br /&gt;
&lt;br /&gt;
           ldi     temp, 0&lt;br /&gt;
           sts     NextSegment, temp&lt;br /&gt;
&lt;br /&gt;
           ldi     temp, ( 1 &amp;lt;&amp;lt; CS01 ) | ( 1 &amp;lt;&amp;lt; CS00 )&lt;br /&gt;
           out     TCCR0, temp&lt;br /&gt;
&lt;br /&gt;
           ldi     temp, 1 &amp;lt;&amp;lt; TOIE0&lt;br /&gt;
           out     TIMSK, temp&lt;br /&gt;
&lt;br /&gt;
           sei&lt;br /&gt;
&lt;br /&gt;
           ldi     temp, 0&lt;br /&gt;
           ldi     temp1, 0&lt;br /&gt;
&lt;br /&gt;
loop:&lt;br /&gt;
           inc     temp&lt;br /&gt;
           brne    _loop&lt;br /&gt;
           inc     temp1&lt;br /&gt;
_loop:&lt;br /&gt;
           rcall    out_number&lt;br /&gt;
&lt;br /&gt;
           cpi     temp, low( 4000 )&lt;br /&gt;
           brne    wait&lt;br /&gt;
           cpi     temp1, high( 4000 )&lt;br /&gt;
           brne    wait&lt;br /&gt;
&lt;br /&gt;
           ldi     temp, 0&lt;br /&gt;
           ldi     temp1, 0&lt;br /&gt;
&lt;br /&gt;
wait:      ldi     r21, 1&lt;br /&gt;
wait0:     ldi     r22, 0&lt;br /&gt;
wait1:     ldi     r23, 0&lt;br /&gt;
wait2:     dec     r23&lt;br /&gt;
           brne    wait2&lt;br /&gt;
           dec     r22&lt;br /&gt;
           brne    wait1&lt;br /&gt;
           dec     r21&lt;br /&gt;
           brne    wait0&lt;br /&gt;
&lt;br /&gt;
           rjmp    loop&lt;br /&gt;
&lt;br /&gt;
Codes:&lt;br /&gt;
    .db  0b11000000, 0b11111001     ; 0: a, b, c, d, e, f&lt;br /&gt;
                                    ; 1: b, c&lt;br /&gt;
    .db  0b10100100, 0b10110000     ; 2: a, b, d, e, g&lt;br /&gt;
                                    ; 3: a, b, c, d, g&lt;br /&gt;
    .db  0b10011001, 0b10010010     ; 4: b, c, f, g&lt;br /&gt;
                                    ; 5: a, c, d, f, g&lt;br /&gt;
    .db  0b10000010, 0b11111000     ; 6: a, c, d, e, f, g&lt;br /&gt;
                                    ; 7: a, b, c&lt;br /&gt;
    .db  0b10000000, 0b10010000     ; 8: a, b, c, d, e, f, g&lt;br /&gt;
                                    ; 9: a, b, c, d, f, g &lt;br /&gt;
&lt;br /&gt;
           .DSEG&lt;br /&gt;
NextDigit:   .byte 1         ; Bitmuster für die Aktivierung des nächsten Segments&lt;br /&gt;
NextSegment: .byte 1         ; Nummer des nächsten aktiven Segments&lt;br /&gt;
Segment0:    .byte 1         ; Ausgabemuster für Segment 0&lt;br /&gt;
Segment1:    .byte 1         ; Ausgabemuster für Segment 1&lt;br /&gt;
Segment2:    .byte 1         ; Ausgabemuster für Segment 2&lt;br /&gt;
Segment3:    .byte 1         ; Ausgabemuster für Segment 3&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Navigation_zurückhoch|&lt;br /&gt;
zurücktext=SRAM|&lt;br /&gt;
zurücklink=AVR-Tutorial: SRAM|&lt;br /&gt;
hochtext=Inhaltsverzeichnis|&lt;br /&gt;
hochlink=AVR-Tutorial}}&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR]][[Category:AVR-Tutorial]]&lt;/div&gt;</summary>
		<author><name>85.183.44.11</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Vergleiche&amp;diff=34582</id>
		<title>AVR-Tutorial: Vergleiche</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Vergleiche&amp;diff=34582"/>
		<updated>2009-02-24T13:36:27Z</updated>

		<summary type="html">&lt;p&gt;85.183.44.11: /* Schleifenkonstrukte */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Vergleiche und Entscheidungen sind in jeder Programmiersprache ein zentrales Mittel um den Programmfluss abhängig von Bedingungen zu kontrollieren. In einem [[AVR]] spielen dazu 3 Komponenten zusammen:&lt;br /&gt;
* Vergleichsbefehle&lt;br /&gt;
* die Flags im Statusregister&lt;br /&gt;
* bedingte Sprungbefehle&lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang ist dabei folgender: Die Vergleichsbefehle führen einen Vergleich durch, zum Beispiel zwischen zwei Registern oder zwischen einem Register und einer Konstante. Das Ergebnis des Vergleiches wird in den Flags abgelegt. Die bedingten Sprungbefehle werten die Flags aus und führen bei einem positiven Ergebnis den Sprung aus. Besonders der erste Satzteil ist wichtig! Den bedingten Sprungbefehlen ist es nämlich völlig egal, ob die Flags über Vergleichsbefehle oder über sonstige Befehle gesetzt wurden. Die Sprungbefehle werten einfach nur die Flags aus, wie auch immer diese zu ihrem Zustand kommen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vergleiche==&lt;br /&gt;
Um einen Vergleich durchzuführen, wird intern eine Subtraktion der beiden Operanden durchgeführt. Das eigentliche Ergebnis der Subtraktion wird allerdings verworfen, es bleibt nur die neue Belegung der Flags übrig, die in weiterer Folge ausgewertet werden kann&lt;br /&gt;
&lt;br /&gt;
===CP - Compare===&lt;br /&gt;
Vergleicht den Inhalt zweier Register miteinander. Prozessorintern wird dabei eine Subtraktion der beiden Register durchgeführt. Das eigentliche Subtraktionsergebnis wird allerdings verworfen, das Subtraktionsergebnis beeinflusst lediglich die Flags.&lt;br /&gt;
&lt;br /&gt;
===CPC - Compare with Carry===&lt;br /&gt;
Vergleicht den Inhalt zweier Register, wobei das Carry Flag in den Vergleich mit einbezogen wird. Dieser Befehl wird für Arithmetik mit grossen Variablen (16/32 Bit) benötigt. Siehe [[AVR-Tutorial: Arithmetik]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Bedingte Sprünge==&lt;br /&gt;
&lt;br /&gt;
Die bedingten Sprünge werten immer bestimmte Flags im Statusregister &#039;&#039;&#039;SREG&#039;&#039;&#039; aus. Es spielt dabei keine Rolle, ob dies nach einem Vergleichsbefehl oder einem sonstigen Befehl gemacht wird. Entscheidend ist einzig und alleine der Zustand des abgefragten Flags. Die Namen der Sprungbefehle wurden allerdings so gewählt, daß sich im Befehlsnamen die Beziehung der Operanden direkt nach einem Compare Befehl wiederspiegelt. Zu beachten ist auch, daß die Flags nicht nur durch Vergleichsbefehle verändert werden, sondern auch durch arithmetische Operationen, Schiebebefehle und logische [[Bitmanipulation | Verknüpfungen]]. Da dieses Information wichtig ist, ist auch in der bei Atmel erhältlichen [http://www.atmel.com/dyn/resources/prod_documents/doc0856.pdf Übersicht über alle Assemblerbefehle] bei jedem Befehl angegeben, ob und wie er Flags beeinflusst. Ebenso ist dort eine kompakte Übersicht aller bedingten Sprünge zu finden. Beachten muss man jedoch, dass die bedingten Sprünge maximal 64 Worte weit springen können.&lt;br /&gt;
&lt;br /&gt;
=== Bedingte Sprünge für vorzeichenlose Zahlen ===&lt;br /&gt;
&lt;br /&gt;
====BRSH - Branch if Same or Higher ====&lt;br /&gt;
&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Carry Flag (C)&#039;&#039;&#039; nicht gesetzt ist. Wird dieser Branch direkt nach einer &#039;&#039;&#039;CP&#039;&#039;&#039;, &#039;&#039;&#039;CPI&#039;&#039;&#039;, &#039;&#039;&#039;SUB&#039;&#039;&#039; oder &#039;&#039;&#039;SUBI&#039;&#039;&#039; Operation eingesetzt, so findet der Sprung dann statt, wenn der erste Operand größer oder gleich dem zweiten Operanden ist.&lt;br /&gt;
&lt;br /&gt;
====BRLO - Branch if Lower ====&lt;br /&gt;
&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Carry Flag (C)&#039;&#039;&#039; gesetzt ist. Wird dieser Branch direkt nach einer &#039;&#039;&#039;CP&#039;&#039;&#039;, &#039;&#039;&#039;CPI&#039;&#039;&#039;, &#039;&#039;&#039;SUB&#039;&#039;&#039; oder &#039;&#039;&#039;SUBI&#039;&#039;&#039; Operation eingesetzt, so findet der Sprung dann statt, wenn der erste Operand kleiner dem zweiten Operanden ist.&lt;br /&gt;
&lt;br /&gt;
=== Bedingte Sprünge für vorzeichenbehaftete Zahlen ===&lt;br /&gt;
&lt;br /&gt;
====BRGE - Branch if Greater or Equal ====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Signed Flag (S)&#039;&#039;&#039; nicht gesetzt ist. Wird dieser Branch direkt nach einer &#039;&#039;&#039;CP&#039;&#039;&#039;, &#039;&#039;&#039;CPI&#039;&#039;&#039;, &#039;&#039;&#039;SUB&#039;&#039;&#039; oder &#039;&#039;&#039;SUBI&#039;&#039;&#039; eingesetzt, so findet der Sprung dann und nur dann statt, wenn der zweite Operand größer oder gleich dem ersten Operanden ist.&lt;br /&gt;
&lt;br /&gt;
====BRLT - Branch if Less Than ====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Signed Flag (S)&#039;&#039;&#039; gesetzt ist. Wird dieser Branch direkt nach einer &#039;&#039;&#039;CP&#039;&#039;&#039;, &#039;&#039;&#039;CPI&#039;&#039;&#039;, &#039;&#039;&#039;SUB&#039;&#039;&#039; oder &#039;&#039;&#039;SUBI&#039;&#039;&#039; Operation eingesetzt, so findet der Sprung dann und nur dann statt, wenn der zweite Operand kleiner als der erste Operand ist.&lt;br /&gt;
&lt;br /&gt;
====BRMI - Branch if Minus====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Negativ Flag (N)&#039;&#039;&#039; gesetzt ist, das Ergbnis der letzen Operation also negativ war.&lt;br /&gt;
&lt;br /&gt;
====BRPL - Branch if Plus====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Negativ Flag (N)&#039;&#039;&#039; nicht gesetzt ist, das Ergbnis der letzen Operation also positiv war (einschiesslich Null).&lt;br /&gt;
&lt;br /&gt;
=== Sonstige bedingte Sprünge ===&lt;br /&gt;
&lt;br /&gt;
====BREQ - Branch if Equal====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Zero Flag (Z)&#039;&#039;&#039; gesetzt ist. Ist nach einem Vergleich das Zero Flag gesetzt, lieferte die interne Subtraktion also 0, so waren beide Operanden gleich.&lt;br /&gt;
&lt;br /&gt;
====BRNE - Branch if Not Equal====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Zero Flag (Z)&#039;&#039;&#039; nicht gesetzt ist. Ist nach einem Vergleich das Zero Flag nicht gesetzt, lieferte die interne Subtraktion also nicht 0, so waren beide Operanden verschieden.&lt;br /&gt;
&lt;br /&gt;
====BRCC - Branch if Carry Flag is Cleared====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Carry Flag (C)&#039;&#039;&#039; nicht gesetzt ist. Dieser Befehl wird oft für Arithmetik mit grossen Variablen (16/32 Bit) bzw. im Zusammenhang mit Schiebeoperatioen verwendet.&lt;br /&gt;
&lt;br /&gt;
====BRCS - Branch if Carry Flag is Set====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Carry Flag (C)&#039;&#039;&#039; gesetzt ist. Die Verwendung ist sehr ähnlich zu BRCC.&lt;br /&gt;
&lt;br /&gt;
=== Selten verwendete bedingte Sprünge ===&lt;br /&gt;
&lt;br /&gt;
====BRHC - Branch if Half Carry Flag is Cleared====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Half Carry Flag (H)&#039;&#039;&#039; nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRHS - Branch if Half Carry Flag is Set====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Half Carry Flag (H)&#039;&#039;&#039; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRID - Branch if Global Interrupt is Disabled (Cleared)====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Interrupt Flag (I)&#039;&#039;&#039; nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRIS - Branch if Global Interrupt is Enabled (Set)====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Interrupt Flag (I)&#039;&#039;&#039; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRTC - Branch if T Flag is Cleared====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;(T)&#039;&#039;&#039; nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRTS - Branch if T Flag is Set====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;(T)&#039;&#039;&#039; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRVC - Branch if Overflow Cleared====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Overflow Flag (V)&#039;&#039;&#039; nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRVS - Branch if Overflow Set====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Overflow Flag (V)&#039;&#039;&#039; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
==Beispiele==&lt;/div&gt;</summary>
		<author><name>85.183.44.11</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Vergleiche&amp;diff=34581</id>
		<title>AVR-Tutorial: Vergleiche</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Vergleiche&amp;diff=34581"/>
		<updated>2009-02-24T13:36:10Z</updated>

		<summary type="html">&lt;p&gt;85.183.44.11: /* Flags */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Vergleiche und Entscheidungen sind in jeder Programmiersprache ein zentrales Mittel um den Programmfluss abhängig von Bedingungen zu kontrollieren. In einem [[AVR]] spielen dazu 3 Komponenten zusammen:&lt;br /&gt;
* Vergleichsbefehle&lt;br /&gt;
* die Flags im Statusregister&lt;br /&gt;
* bedingte Sprungbefehle&lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang ist dabei folgender: Die Vergleichsbefehle führen einen Vergleich durch, zum Beispiel zwischen zwei Registern oder zwischen einem Register und einer Konstante. Das Ergebnis des Vergleiches wird in den Flags abgelegt. Die bedingten Sprungbefehle werten die Flags aus und führen bei einem positiven Ergebnis den Sprung aus. Besonders der erste Satzteil ist wichtig! Den bedingten Sprungbefehlen ist es nämlich völlig egal, ob die Flags über Vergleichsbefehle oder über sonstige Befehle gesetzt wurden. Die Sprungbefehle werten einfach nur die Flags aus, wie auch immer diese zu ihrem Zustand kommen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Vergleiche==&lt;br /&gt;
Um einen Vergleich durchzuführen, wird intern eine Subtraktion der beiden Operanden durchgeführt. Das eigentliche Ergebnis der Subtraktion wird allerdings verworfen, es bleibt nur die neue Belegung der Flags übrig, die in weiterer Folge ausgewertet werden kann&lt;br /&gt;
&lt;br /&gt;
===CP - Compare===&lt;br /&gt;
Vergleicht den Inhalt zweier Register miteinander. Prozessorintern wird dabei eine Subtraktion der beiden Register durchgeführt. Das eigentliche Subtraktionsergebnis wird allerdings verworfen, das Subtraktionsergebnis beeinflusst lediglich die Flags.&lt;br /&gt;
&lt;br /&gt;
===CPC - Compare with Carry===&lt;br /&gt;
Vergleicht den Inhalt zweier Register, wobei das Carry Flag in den Vergleich mit einbezogen wird. Dieser Befehl wird für Arithmetik mit grossen Variablen (16/32 Bit) benötigt. Siehe [[AVR-Tutorial: Arithmetik]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Bedingte Sprünge==&lt;br /&gt;
&lt;br /&gt;
Die bedingten Sprünge werten immer bestimmte Flags im Statusregister &#039;&#039;&#039;SREG&#039;&#039;&#039; aus. Es spielt dabei keine Rolle, ob dies nach einem Vergleichsbefehl oder einem sonstigen Befehl gemacht wird. Entscheidend ist einzig und alleine der Zustand des abgefragten Flags. Die Namen der Sprungbefehle wurden allerdings so gewählt, daß sich im Befehlsnamen die Beziehung der Operanden direkt nach einem Compare Befehl wiederspiegelt. Zu beachten ist auch, daß die Flags nicht nur durch Vergleichsbefehle verändert werden, sondern auch durch arithmetische Operationen, Schiebebefehle und logische [[Bitmanipulation | Verknüpfungen]]. Da dieses Information wichtig ist, ist auch in der bei Atmel erhältlichen [http://www.atmel.com/dyn/resources/prod_documents/doc0856.pdf Übersicht über alle Assemblerbefehle] bei jedem Befehl angegeben, ob und wie er Flags beeinflusst. Ebenso ist dort eine kompakte Übersicht aller bedingten Sprünge zu finden. Beachten muss man jedoch, dass die bedingten Sprünge maximal 64 Worte weit springen können.&lt;br /&gt;
&lt;br /&gt;
=== Bedingte Sprünge für vorzeichenlose Zahlen ===&lt;br /&gt;
&lt;br /&gt;
====BRSH - Branch if Same or Higher ====&lt;br /&gt;
&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Carry Flag (C)&#039;&#039;&#039; nicht gesetzt ist. Wird dieser Branch direkt nach einer &#039;&#039;&#039;CP&#039;&#039;&#039;, &#039;&#039;&#039;CPI&#039;&#039;&#039;, &#039;&#039;&#039;SUB&#039;&#039;&#039; oder &#039;&#039;&#039;SUBI&#039;&#039;&#039; Operation eingesetzt, so findet der Sprung dann statt, wenn der erste Operand größer oder gleich dem zweiten Operanden ist.&lt;br /&gt;
&lt;br /&gt;
====BRLO - Branch if Lower ====&lt;br /&gt;
&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Carry Flag (C)&#039;&#039;&#039; gesetzt ist. Wird dieser Branch direkt nach einer &#039;&#039;&#039;CP&#039;&#039;&#039;, &#039;&#039;&#039;CPI&#039;&#039;&#039;, &#039;&#039;&#039;SUB&#039;&#039;&#039; oder &#039;&#039;&#039;SUBI&#039;&#039;&#039; Operation eingesetzt, so findet der Sprung dann statt, wenn der erste Operand kleiner dem zweiten Operanden ist.&lt;br /&gt;
&lt;br /&gt;
=== Bedingte Sprünge für vorzeichenbehaftete Zahlen ===&lt;br /&gt;
&lt;br /&gt;
====BRGE - Branch if Greater or Equal ====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Signed Flag (S)&#039;&#039;&#039; nicht gesetzt ist. Wird dieser Branch direkt nach einer &#039;&#039;&#039;CP&#039;&#039;&#039;, &#039;&#039;&#039;CPI&#039;&#039;&#039;, &#039;&#039;&#039;SUB&#039;&#039;&#039; oder &#039;&#039;&#039;SUBI&#039;&#039;&#039; eingesetzt, so findet der Sprung dann und nur dann statt, wenn der zweite Operand größer oder gleich dem ersten Operanden ist.&lt;br /&gt;
&lt;br /&gt;
====BRLT - Branch if Less Than ====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Signed Flag (S)&#039;&#039;&#039; gesetzt ist. Wird dieser Branch direkt nach einer &#039;&#039;&#039;CP&#039;&#039;&#039;, &#039;&#039;&#039;CPI&#039;&#039;&#039;, &#039;&#039;&#039;SUB&#039;&#039;&#039; oder &#039;&#039;&#039;SUBI&#039;&#039;&#039; Operation eingesetzt, so findet der Sprung dann und nur dann statt, wenn der zweite Operand kleiner als der erste Operand ist.&lt;br /&gt;
&lt;br /&gt;
====BRMI - Branch if Minus====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Negativ Flag (N)&#039;&#039;&#039; gesetzt ist, das Ergbnis der letzen Operation also negativ war.&lt;br /&gt;
&lt;br /&gt;
====BRPL - Branch if Plus====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Negativ Flag (N)&#039;&#039;&#039; nicht gesetzt ist, das Ergbnis der letzen Operation also positiv war (einschiesslich Null).&lt;br /&gt;
&lt;br /&gt;
=== Sonstige bedingte Sprünge ===&lt;br /&gt;
&lt;br /&gt;
====BREQ - Branch if Equal====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Zero Flag (Z)&#039;&#039;&#039; gesetzt ist. Ist nach einem Vergleich das Zero Flag gesetzt, lieferte die interne Subtraktion also 0, so waren beide Operanden gleich.&lt;br /&gt;
&lt;br /&gt;
====BRNE - Branch if Not Equal====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Zero Flag (Z)&#039;&#039;&#039; nicht gesetzt ist. Ist nach einem Vergleich das Zero Flag nicht gesetzt, lieferte die interne Subtraktion also nicht 0, so waren beide Operanden verschieden.&lt;br /&gt;
&lt;br /&gt;
====BRCC - Branch if Carry Flag is Cleared====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Carry Flag (C)&#039;&#039;&#039; nicht gesetzt ist. Dieser Befehl wird oft für Arithmetik mit grossen Variablen (16/32 Bit) bzw. im Zusammenhang mit Schiebeoperatioen verwendet.&lt;br /&gt;
&lt;br /&gt;
====BRCS - Branch if Carry Flag is Set====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Carry Flag (C)&#039;&#039;&#039; gesetzt ist. Die Verwendung ist sehr ähnlich zu BRCC.&lt;br /&gt;
&lt;br /&gt;
=== Selten verwendete bedingte Sprünge ===&lt;br /&gt;
&lt;br /&gt;
====BRHC - Branch if Half Carry Flag is Cleared====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Half Carry Flag (H)&#039;&#039;&#039; nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRHS - Branch if Half Carry Flag is Set====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Half Carry Flag (H)&#039;&#039;&#039; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRID - Branch if Global Interrupt is Disabled (Cleared)====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Interrupt Flag (I)&#039;&#039;&#039; nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRIS - Branch if Global Interrupt is Enabled (Set)====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Interrupt Flag (I)&#039;&#039;&#039; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRTC - Branch if T Flag is Cleared====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;(T)&#039;&#039;&#039; nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRTS - Branch if T Flag is Set====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;(T)&#039;&#039;&#039; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRVC - Branch if Overflow Cleared====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Overflow Flag (V)&#039;&#039;&#039; nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRVS - Branch if Overflow Set====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Overflow Flag (V)&#039;&#039;&#039; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
==Beispiele==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schleifenkonstrukte===&lt;br /&gt;
&lt;br /&gt;
Ein immer wiederkehrendes Muster in der Programmierung ist eine &#039;&#039;&#039;Schleife&#039;&#039;&#039;. Die einfachste Form einer Schleife ist die &#039;&#039;&#039;Zählschleife&#039;&#039;&#039;. Dabei wird ein Register von einem Startwert ausgehend eine gewisse Anzahl erhöht, bis ein Endwert erreicht wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
    ldi     r17, 10         ; der Startwert sei in diesem Beispiel 10&lt;br /&gt;
loop:&lt;br /&gt;
                            ; an dieser Stelle stehen die Befehle, welche innerhalb der Schleife&lt;br /&gt;
                            ; mehrfach ausgeführt werden sollen&lt;br /&gt;
&lt;br /&gt;
    inc     r17             ; erhöhe das Zaehlregister&lt;br /&gt;
    cpi     r17, 134        ; mit dem Endwert vergleichen&lt;br /&gt;
    brne    loop            ; und wenn der Endwert noch nicht erricht ist&lt;br /&gt;
                            ; wird bei der Marke loop ein weiterer Schleifendurchlauf ausgeführt&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sehr oft ist es auch möglich das Konstrukt umzudrehen. Anstatt von einem Startwert aus zu inkrementieren genügt es die Anzahl der gewünschten Schleifendurchläufe in ein Register zu laden und dieses Register zu dekrementieren. Dabei kann man von der Eigenschaft der Dekrementieranweisung gebrauch machen, das &#039;&#039;&#039;Zero Flag (Z)&#039;&#039;&#039; zu beeinflussen. Ist das Ergebnis des Dekrements 0, so wird das &#039;&#039;&#039;Zero Flag (Z)&#039;&#039;&#039; gesetzt, welches wiederum in der nachfolgenden &#039;&#039;&#039;BRNE&#039;&#039;&#039; Anweisung für einen bedingen Sprung benutzt werden kann. Das vereinfacht die Schleife und spart eine Anweisung sowie einen Takt Ausführungzeit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
    ldi     r17, 124        ; Die Anzahl der Wiederholungen in ein Register laden&lt;br /&gt;
loop:&lt;br /&gt;
                            ; an dieser Stelle stehen die Befehle, welche innerhalb der Schleife&lt;br /&gt;
                            ; mehrfach ausgeführt werden sollen&lt;br /&gt;
&lt;br /&gt;
    dec     r17             ; Schleifenzähler um 1 verringern, dabei wird das Zero Flag beeinflusst&lt;br /&gt;
    brne    loop            ; wenn r17 noch nicht 0 geworden ist -&amp;gt; Schleife wiederholen&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Navigation_zurückhochvor|&lt;br /&gt;
zurücktext=Interrupts|&lt;br /&gt;
zurücklink=AVR-Tutorial: Interrupts|&lt;br /&gt;
hochtext=Inhaltsverzeichnis|&lt;br /&gt;
hochlink=AVR-Tutorial|&lt;br /&gt;
vortext=Mehrfachverzweigungen|&lt;br /&gt;
vorlink=AVR-Tutorial: Mehrfachverzweigung}}&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR]][[Category:AVR-Tutorial]]&lt;/div&gt;</summary>
		<author><name>85.183.44.11</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Vergleiche&amp;diff=34580</id>
		<title>AVR-Tutorial: Vergleiche</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Vergleiche&amp;diff=34580"/>
		<updated>2009-02-24T13:35:54Z</updated>

		<summary type="html">&lt;p&gt;85.183.44.11: /* Entscheidungen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Vergleiche und Entscheidungen sind in jeder Programmiersprache ein zentrales Mittel um den Programmfluss abhängig von Bedingungen zu kontrollieren. In einem [[AVR]] spielen dazu 3 Komponenten zusammen:&lt;br /&gt;
* Vergleichsbefehle&lt;br /&gt;
* die Flags im Statusregister&lt;br /&gt;
* bedingte Sprungbefehle&lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang ist dabei folgender: Die Vergleichsbefehle führen einen Vergleich durch, zum Beispiel zwischen zwei Registern oder zwischen einem Register und einer Konstante. Das Ergebnis des Vergleiches wird in den Flags abgelegt. Die bedingten Sprungbefehle werten die Flags aus und führen bei einem positiven Ergebnis den Sprung aus. Besonders der erste Satzteil ist wichtig! Den bedingten Sprungbefehlen ist es nämlich völlig egal, ob die Flags über Vergleichsbefehle oder über sonstige Befehle gesetzt wurden. Die Sprungbefehle werten einfach nur die Flags aus, wie auch immer diese zu ihrem Zustand kommen.&lt;br /&gt;
&lt;br /&gt;
==Flags==&lt;br /&gt;
&lt;br /&gt;
Die Flags residieren im Statusregister &#039;&#039;&#039;SREG&#039;&#039;&#039;. Ihre Aufgabe ist es, das Auftreten bestimmter Ereignisse, die während Berechnungen eintreten können festzuhalten.&lt;br /&gt;
&lt;br /&gt;
  +---+---+---+---+---+---+---+---+&lt;br /&gt;
  | I | T | H | S | V | N | Z | C |&lt;br /&gt;
  +---+---+---+---+---+---+---+---+&lt;br /&gt;
&lt;br /&gt;
===Carry (C)===&lt;br /&gt;
Das Carry Flag zeigt an, ob ein Überlauf oder Unterlauf bei einer 8-Bit Berechnung statt gefunden hat (Addition, Subtraktion). Ebenso ist es ein Zwischenspeicher bei Schiebe- und Rotationsoperationen.&lt;br /&gt;
&lt;br /&gt;
===Zero (Z)===&lt;br /&gt;
Das Zero Flag hält fest, ob das Ergebnis der letzten 8-Bit Berechnung 0 war oder nicht.&lt;br /&gt;
&lt;br /&gt;
===Negative (N)===&lt;br /&gt;
Spiegelt den Zustand des höchstwertigen Bits der letzten 8-Bit Berechnung wieder. In 2-Komplement Arithmetik bedeutet ein gesetztes 7. Bit eine negative Zahl, daher der Name.&lt;br /&gt;
&lt;br /&gt;
===Overflow (V)===&lt;br /&gt;
Dieses Bit wird gesetzt, wenn bei einer Berechnung mit 2-Komplement Arithmetik ein Überlauf (Unterlauf) stattgefunden hat. Dies entspricht einem Überlauf von Bit 6 ins Bit 7&lt;br /&gt;
&lt;br /&gt;
===Signed (S)===&lt;br /&gt;
Das Signed Bit ist eine Verknüpfung aus dem N und dem V Flag. Es wird hauptsächlich für &#039;Signed&#039; Tests benötigt. Daher auch der Name.&lt;br /&gt;
&lt;br /&gt;
===Half Carry (H)===&lt;br /&gt;
Das Half Carry Flag hat die gleiche Aufgabe wie das Carry Flag, nur beschäftigt es sich mit einem Überlauf von Bit 3 nach Bit 4. Das Haupteinsatzgebiet ist der Bereich der BCD Arithmetik.&lt;br /&gt;
&lt;br /&gt;
=== Transfer (T)===&lt;br /&gt;
Das T-Flag wird von keiner Berechnung gesetzt, sondern steht zur ausschliesslichen Verwendung des Programmierers zur Verfügung. Damit können Bits von einer Stelle schnell an eine andere kopiert oder getestet werden.&lt;br /&gt;
&lt;br /&gt;
===Interrupt (I)===&lt;br /&gt;
Das Interrupt Flag hat ebenfalls nichts mit Vergleichen zu tun, sondern steuert ob Interrupts systemweit zugelassen sind (siehe [[AVR-Tutorial: Interrupts]]).&lt;br /&gt;
&lt;br /&gt;
==Vergleiche==&lt;br /&gt;
Um einen Vergleich durchzuführen, wird intern eine Subtraktion der beiden Operanden durchgeführt. Das eigentliche Ergebnis der Subtraktion wird allerdings verworfen, es bleibt nur die neue Belegung der Flags übrig, die in weiterer Folge ausgewertet werden kann&lt;br /&gt;
&lt;br /&gt;
===CP - Compare===&lt;br /&gt;
Vergleicht den Inhalt zweier Register miteinander. Prozessorintern wird dabei eine Subtraktion der beiden Register durchgeführt. Das eigentliche Subtraktionsergebnis wird allerdings verworfen, das Subtraktionsergebnis beeinflusst lediglich die Flags.&lt;br /&gt;
&lt;br /&gt;
===CPC - Compare with Carry===&lt;br /&gt;
Vergleicht den Inhalt zweier Register, wobei das Carry Flag in den Vergleich mit einbezogen wird. Dieser Befehl wird für Arithmetik mit grossen Variablen (16/32 Bit) benötigt. Siehe [[AVR-Tutorial: Arithmetik]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Bedingte Sprünge==&lt;br /&gt;
&lt;br /&gt;
Die bedingten Sprünge werten immer bestimmte Flags im Statusregister &#039;&#039;&#039;SREG&#039;&#039;&#039; aus. Es spielt dabei keine Rolle, ob dies nach einem Vergleichsbefehl oder einem sonstigen Befehl gemacht wird. Entscheidend ist einzig und alleine der Zustand des abgefragten Flags. Die Namen der Sprungbefehle wurden allerdings so gewählt, daß sich im Befehlsnamen die Beziehung der Operanden direkt nach einem Compare Befehl wiederspiegelt. Zu beachten ist auch, daß die Flags nicht nur durch Vergleichsbefehle verändert werden, sondern auch durch arithmetische Operationen, Schiebebefehle und logische [[Bitmanipulation | Verknüpfungen]]. Da dieses Information wichtig ist, ist auch in der bei Atmel erhältlichen [http://www.atmel.com/dyn/resources/prod_documents/doc0856.pdf Übersicht über alle Assemblerbefehle] bei jedem Befehl angegeben, ob und wie er Flags beeinflusst. Ebenso ist dort eine kompakte Übersicht aller bedingten Sprünge zu finden. Beachten muss man jedoch, dass die bedingten Sprünge maximal 64 Worte weit springen können.&lt;br /&gt;
&lt;br /&gt;
=== Bedingte Sprünge für vorzeichenlose Zahlen ===&lt;br /&gt;
&lt;br /&gt;
====BRSH - Branch if Same or Higher ====&lt;br /&gt;
&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Carry Flag (C)&#039;&#039;&#039; nicht gesetzt ist. Wird dieser Branch direkt nach einer &#039;&#039;&#039;CP&#039;&#039;&#039;, &#039;&#039;&#039;CPI&#039;&#039;&#039;, &#039;&#039;&#039;SUB&#039;&#039;&#039; oder &#039;&#039;&#039;SUBI&#039;&#039;&#039; Operation eingesetzt, so findet der Sprung dann statt, wenn der erste Operand größer oder gleich dem zweiten Operanden ist.&lt;br /&gt;
&lt;br /&gt;
====BRLO - Branch if Lower ====&lt;br /&gt;
&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Carry Flag (C)&#039;&#039;&#039; gesetzt ist. Wird dieser Branch direkt nach einer &#039;&#039;&#039;CP&#039;&#039;&#039;, &#039;&#039;&#039;CPI&#039;&#039;&#039;, &#039;&#039;&#039;SUB&#039;&#039;&#039; oder &#039;&#039;&#039;SUBI&#039;&#039;&#039; Operation eingesetzt, so findet der Sprung dann statt, wenn der erste Operand kleiner dem zweiten Operanden ist.&lt;br /&gt;
&lt;br /&gt;
=== Bedingte Sprünge für vorzeichenbehaftete Zahlen ===&lt;br /&gt;
&lt;br /&gt;
====BRGE - Branch if Greater or Equal ====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Signed Flag (S)&#039;&#039;&#039; nicht gesetzt ist. Wird dieser Branch direkt nach einer &#039;&#039;&#039;CP&#039;&#039;&#039;, &#039;&#039;&#039;CPI&#039;&#039;&#039;, &#039;&#039;&#039;SUB&#039;&#039;&#039; oder &#039;&#039;&#039;SUBI&#039;&#039;&#039; eingesetzt, so findet der Sprung dann und nur dann statt, wenn der zweite Operand größer oder gleich dem ersten Operanden ist.&lt;br /&gt;
&lt;br /&gt;
====BRLT - Branch if Less Than ====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Signed Flag (S)&#039;&#039;&#039; gesetzt ist. Wird dieser Branch direkt nach einer &#039;&#039;&#039;CP&#039;&#039;&#039;, &#039;&#039;&#039;CPI&#039;&#039;&#039;, &#039;&#039;&#039;SUB&#039;&#039;&#039; oder &#039;&#039;&#039;SUBI&#039;&#039;&#039; Operation eingesetzt, so findet der Sprung dann und nur dann statt, wenn der zweite Operand kleiner als der erste Operand ist.&lt;br /&gt;
&lt;br /&gt;
====BRMI - Branch if Minus====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Negativ Flag (N)&#039;&#039;&#039; gesetzt ist, das Ergbnis der letzen Operation also negativ war.&lt;br /&gt;
&lt;br /&gt;
====BRPL - Branch if Plus====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Negativ Flag (N)&#039;&#039;&#039; nicht gesetzt ist, das Ergbnis der letzen Operation also positiv war (einschiesslich Null).&lt;br /&gt;
&lt;br /&gt;
=== Sonstige bedingte Sprünge ===&lt;br /&gt;
&lt;br /&gt;
====BREQ - Branch if Equal====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Zero Flag (Z)&#039;&#039;&#039; gesetzt ist. Ist nach einem Vergleich das Zero Flag gesetzt, lieferte die interne Subtraktion also 0, so waren beide Operanden gleich.&lt;br /&gt;
&lt;br /&gt;
====BRNE - Branch if Not Equal====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Zero Flag (Z)&#039;&#039;&#039; nicht gesetzt ist. Ist nach einem Vergleich das Zero Flag nicht gesetzt, lieferte die interne Subtraktion also nicht 0, so waren beide Operanden verschieden.&lt;br /&gt;
&lt;br /&gt;
====BRCC - Branch if Carry Flag is Cleared====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Carry Flag (C)&#039;&#039;&#039; nicht gesetzt ist. Dieser Befehl wird oft für Arithmetik mit grossen Variablen (16/32 Bit) bzw. im Zusammenhang mit Schiebeoperatioen verwendet.&lt;br /&gt;
&lt;br /&gt;
====BRCS - Branch if Carry Flag is Set====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Carry Flag (C)&#039;&#039;&#039; gesetzt ist. Die Verwendung ist sehr ähnlich zu BRCC.&lt;br /&gt;
&lt;br /&gt;
=== Selten verwendete bedingte Sprünge ===&lt;br /&gt;
&lt;br /&gt;
====BRHC - Branch if Half Carry Flag is Cleared====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Half Carry Flag (H)&#039;&#039;&#039; nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRHS - Branch if Half Carry Flag is Set====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Half Carry Flag (H)&#039;&#039;&#039; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRID - Branch if Global Interrupt is Disabled (Cleared)====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Interrupt Flag (I)&#039;&#039;&#039; nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRIS - Branch if Global Interrupt is Enabled (Set)====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Interrupt Flag (I)&#039;&#039;&#039; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRTC - Branch if T Flag is Cleared====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;(T)&#039;&#039;&#039; nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRTS - Branch if T Flag is Set====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;(T)&#039;&#039;&#039; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRVC - Branch if Overflow Cleared====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Overflow Flag (V)&#039;&#039;&#039; nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRVS - Branch if Overflow Set====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Overflow Flag (V)&#039;&#039;&#039; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
==Beispiele==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schleifenkonstrukte===&lt;br /&gt;
&lt;br /&gt;
Ein immer wiederkehrendes Muster in der Programmierung ist eine &#039;&#039;&#039;Schleife&#039;&#039;&#039;. Die einfachste Form einer Schleife ist die &#039;&#039;&#039;Zählschleife&#039;&#039;&#039;. Dabei wird ein Register von einem Startwert ausgehend eine gewisse Anzahl erhöht, bis ein Endwert erreicht wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
    ldi     r17, 10         ; der Startwert sei in diesem Beispiel 10&lt;br /&gt;
loop:&lt;br /&gt;
                            ; an dieser Stelle stehen die Befehle, welche innerhalb der Schleife&lt;br /&gt;
                            ; mehrfach ausgeführt werden sollen&lt;br /&gt;
&lt;br /&gt;
    inc     r17             ; erhöhe das Zaehlregister&lt;br /&gt;
    cpi     r17, 134        ; mit dem Endwert vergleichen&lt;br /&gt;
    brne    loop            ; und wenn der Endwert noch nicht erricht ist&lt;br /&gt;
                            ; wird bei der Marke loop ein weiterer Schleifendurchlauf ausgeführt&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sehr oft ist es auch möglich das Konstrukt umzudrehen. Anstatt von einem Startwert aus zu inkrementieren genügt es die Anzahl der gewünschten Schleifendurchläufe in ein Register zu laden und dieses Register zu dekrementieren. Dabei kann man von der Eigenschaft der Dekrementieranweisung gebrauch machen, das &#039;&#039;&#039;Zero Flag (Z)&#039;&#039;&#039; zu beeinflussen. Ist das Ergebnis des Dekrements 0, so wird das &#039;&#039;&#039;Zero Flag (Z)&#039;&#039;&#039; gesetzt, welches wiederum in der nachfolgenden &#039;&#039;&#039;BRNE&#039;&#039;&#039; Anweisung für einen bedingen Sprung benutzt werden kann. Das vereinfacht die Schleife und spart eine Anweisung sowie einen Takt Ausführungzeit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
    ldi     r17, 124        ; Die Anzahl der Wiederholungen in ein Register laden&lt;br /&gt;
loop:&lt;br /&gt;
                            ; an dieser Stelle stehen die Befehle, welche innerhalb der Schleife&lt;br /&gt;
                            ; mehrfach ausgeführt werden sollen&lt;br /&gt;
&lt;br /&gt;
    dec     r17             ; Schleifenzähler um 1 verringern, dabei wird das Zero Flag beeinflusst&lt;br /&gt;
    brne    loop            ; wenn r17 noch nicht 0 geworden ist -&amp;gt; Schleife wiederholen&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Navigation_zurückhochvor|&lt;br /&gt;
zurücktext=Interrupts|&lt;br /&gt;
zurücklink=AVR-Tutorial: Interrupts|&lt;br /&gt;
hochtext=Inhaltsverzeichnis|&lt;br /&gt;
hochlink=AVR-Tutorial|&lt;br /&gt;
vortext=Mehrfachverzweigungen|&lt;br /&gt;
vorlink=AVR-Tutorial: Mehrfachverzweigung}}&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR]][[Category:AVR-Tutorial]]&lt;/div&gt;</summary>
		<author><name>85.183.44.11</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Vergleiche&amp;diff=34579</id>
		<title>AVR-Tutorial: Vergleiche</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=AVR-Tutorial:_Vergleiche&amp;diff=34579"/>
		<updated>2009-02-24T13:35:36Z</updated>

		<summary type="html">&lt;p&gt;85.183.44.11: /* CPI - Compare Immediate */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Vergleiche und Entscheidungen sind in jeder Programmiersprache ein zentrales Mittel um den Programmfluss abhängig von Bedingungen zu kontrollieren. In einem [[AVR]] spielen dazu 3 Komponenten zusammen:&lt;br /&gt;
* Vergleichsbefehle&lt;br /&gt;
* die Flags im Statusregister&lt;br /&gt;
* bedingte Sprungbefehle&lt;br /&gt;
&lt;br /&gt;
Der Zusammenhang ist dabei folgender: Die Vergleichsbefehle führen einen Vergleich durch, zum Beispiel zwischen zwei Registern oder zwischen einem Register und einer Konstante. Das Ergebnis des Vergleiches wird in den Flags abgelegt. Die bedingten Sprungbefehle werten die Flags aus und führen bei einem positiven Ergebnis den Sprung aus. Besonders der erste Satzteil ist wichtig! Den bedingten Sprungbefehlen ist es nämlich völlig egal, ob die Flags über Vergleichsbefehle oder über sonstige Befehle gesetzt wurden. Die Sprungbefehle werten einfach nur die Flags aus, wie auch immer diese zu ihrem Zustand kommen.&lt;br /&gt;
&lt;br /&gt;
==Flags==&lt;br /&gt;
&lt;br /&gt;
Die Flags residieren im Statusregister &#039;&#039;&#039;SREG&#039;&#039;&#039;. Ihre Aufgabe ist es, das Auftreten bestimmter Ereignisse, die während Berechnungen eintreten können festzuhalten.&lt;br /&gt;
&lt;br /&gt;
  +---+---+---+---+---+---+---+---+&lt;br /&gt;
  | I | T | H | S | V | N | Z | C |&lt;br /&gt;
  +---+---+---+---+---+---+---+---+&lt;br /&gt;
&lt;br /&gt;
===Carry (C)===&lt;br /&gt;
Das Carry Flag zeigt an, ob ein Überlauf oder Unterlauf bei einer 8-Bit Berechnung statt gefunden hat (Addition, Subtraktion). Ebenso ist es ein Zwischenspeicher bei Schiebe- und Rotationsoperationen.&lt;br /&gt;
&lt;br /&gt;
===Zero (Z)===&lt;br /&gt;
Das Zero Flag hält fest, ob das Ergebnis der letzten 8-Bit Berechnung 0 war oder nicht.&lt;br /&gt;
&lt;br /&gt;
===Negative (N)===&lt;br /&gt;
Spiegelt den Zustand des höchstwertigen Bits der letzten 8-Bit Berechnung wieder. In 2-Komplement Arithmetik bedeutet ein gesetztes 7. Bit eine negative Zahl, daher der Name.&lt;br /&gt;
&lt;br /&gt;
===Overflow (V)===&lt;br /&gt;
Dieses Bit wird gesetzt, wenn bei einer Berechnung mit 2-Komplement Arithmetik ein Überlauf (Unterlauf) stattgefunden hat. Dies entspricht einem Überlauf von Bit 6 ins Bit 7&lt;br /&gt;
&lt;br /&gt;
===Signed (S)===&lt;br /&gt;
Das Signed Bit ist eine Verknüpfung aus dem N und dem V Flag. Es wird hauptsächlich für &#039;Signed&#039; Tests benötigt. Daher auch der Name.&lt;br /&gt;
&lt;br /&gt;
===Half Carry (H)===&lt;br /&gt;
Das Half Carry Flag hat die gleiche Aufgabe wie das Carry Flag, nur beschäftigt es sich mit einem Überlauf von Bit 3 nach Bit 4. Das Haupteinsatzgebiet ist der Bereich der BCD Arithmetik.&lt;br /&gt;
&lt;br /&gt;
=== Transfer (T)===&lt;br /&gt;
Das T-Flag wird von keiner Berechnung gesetzt, sondern steht zur ausschliesslichen Verwendung des Programmierers zur Verfügung. Damit können Bits von einer Stelle schnell an eine andere kopiert oder getestet werden.&lt;br /&gt;
&lt;br /&gt;
===Interrupt (I)===&lt;br /&gt;
Das Interrupt Flag hat ebenfalls nichts mit Vergleichen zu tun, sondern steuert ob Interrupts systemweit zugelassen sind (siehe [[AVR-Tutorial: Interrupts]]).&lt;br /&gt;
&lt;br /&gt;
==Vergleiche==&lt;br /&gt;
Um einen Vergleich durchzuführen, wird intern eine Subtraktion der beiden Operanden durchgeführt. Das eigentliche Ergebnis der Subtraktion wird allerdings verworfen, es bleibt nur die neue Belegung der Flags übrig, die in weiterer Folge ausgewertet werden kann&lt;br /&gt;
&lt;br /&gt;
===CP - Compare===&lt;br /&gt;
Vergleicht den Inhalt zweier Register miteinander. Prozessorintern wird dabei eine Subtraktion der beiden Register durchgeführt. Das eigentliche Subtraktionsergebnis wird allerdings verworfen, das Subtraktionsergebnis beeinflusst lediglich die Flags.&lt;br /&gt;
&lt;br /&gt;
===CPC - Compare with Carry===&lt;br /&gt;
Vergleicht den Inhalt zweier Register, wobei das Carry Flag in den Vergleich mit einbezogen wird. Dieser Befehl wird für Arithmetik mit grossen Variablen (16/32 Bit) benötigt. Siehe [[AVR-Tutorial: Arithmetik]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Bedingte Sprünge==&lt;br /&gt;
&lt;br /&gt;
Die bedingten Sprünge werten immer bestimmte Flags im Statusregister &#039;&#039;&#039;SREG&#039;&#039;&#039; aus. Es spielt dabei keine Rolle, ob dies nach einem Vergleichsbefehl oder einem sonstigen Befehl gemacht wird. Entscheidend ist einzig und alleine der Zustand des abgefragten Flags. Die Namen der Sprungbefehle wurden allerdings so gewählt, daß sich im Befehlsnamen die Beziehung der Operanden direkt nach einem Compare Befehl wiederspiegelt. Zu beachten ist auch, daß die Flags nicht nur durch Vergleichsbefehle verändert werden, sondern auch durch arithmetische Operationen, Schiebebefehle und logische [[Bitmanipulation | Verknüpfungen]]. Da dieses Information wichtig ist, ist auch in der bei Atmel erhältlichen [http://www.atmel.com/dyn/resources/prod_documents/doc0856.pdf Übersicht über alle Assemblerbefehle] bei jedem Befehl angegeben, ob und wie er Flags beeinflusst. Ebenso ist dort eine kompakte Übersicht aller bedingten Sprünge zu finden. Beachten muss man jedoch, dass die bedingten Sprünge maximal 64 Worte weit springen können.&lt;br /&gt;
&lt;br /&gt;
=== Bedingte Sprünge für vorzeichenlose Zahlen ===&lt;br /&gt;
&lt;br /&gt;
====BRSH - Branch if Same or Higher ====&lt;br /&gt;
&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Carry Flag (C)&#039;&#039;&#039; nicht gesetzt ist. Wird dieser Branch direkt nach einer &#039;&#039;&#039;CP&#039;&#039;&#039;, &#039;&#039;&#039;CPI&#039;&#039;&#039;, &#039;&#039;&#039;SUB&#039;&#039;&#039; oder &#039;&#039;&#039;SUBI&#039;&#039;&#039; Operation eingesetzt, so findet der Sprung dann statt, wenn der erste Operand größer oder gleich dem zweiten Operanden ist.&lt;br /&gt;
&lt;br /&gt;
====BRLO - Branch if Lower ====&lt;br /&gt;
&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Carry Flag (C)&#039;&#039;&#039; gesetzt ist. Wird dieser Branch direkt nach einer &#039;&#039;&#039;CP&#039;&#039;&#039;, &#039;&#039;&#039;CPI&#039;&#039;&#039;, &#039;&#039;&#039;SUB&#039;&#039;&#039; oder &#039;&#039;&#039;SUBI&#039;&#039;&#039; Operation eingesetzt, so findet der Sprung dann statt, wenn der erste Operand kleiner dem zweiten Operanden ist.&lt;br /&gt;
&lt;br /&gt;
=== Bedingte Sprünge für vorzeichenbehaftete Zahlen ===&lt;br /&gt;
&lt;br /&gt;
====BRGE - Branch if Greater or Equal ====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Signed Flag (S)&#039;&#039;&#039; nicht gesetzt ist. Wird dieser Branch direkt nach einer &#039;&#039;&#039;CP&#039;&#039;&#039;, &#039;&#039;&#039;CPI&#039;&#039;&#039;, &#039;&#039;&#039;SUB&#039;&#039;&#039; oder &#039;&#039;&#039;SUBI&#039;&#039;&#039; eingesetzt, so findet der Sprung dann und nur dann statt, wenn der zweite Operand größer oder gleich dem ersten Operanden ist.&lt;br /&gt;
&lt;br /&gt;
====BRLT - Branch if Less Than ====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Signed Flag (S)&#039;&#039;&#039; gesetzt ist. Wird dieser Branch direkt nach einer &#039;&#039;&#039;CP&#039;&#039;&#039;, &#039;&#039;&#039;CPI&#039;&#039;&#039;, &#039;&#039;&#039;SUB&#039;&#039;&#039; oder &#039;&#039;&#039;SUBI&#039;&#039;&#039; Operation eingesetzt, so findet der Sprung dann und nur dann statt, wenn der zweite Operand kleiner als der erste Operand ist.&lt;br /&gt;
&lt;br /&gt;
====BRMI - Branch if Minus====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Negativ Flag (N)&#039;&#039;&#039; gesetzt ist, das Ergbnis der letzen Operation also negativ war.&lt;br /&gt;
&lt;br /&gt;
====BRPL - Branch if Plus====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Negativ Flag (N)&#039;&#039;&#039; nicht gesetzt ist, das Ergbnis der letzen Operation also positiv war (einschiesslich Null).&lt;br /&gt;
&lt;br /&gt;
=== Sonstige bedingte Sprünge ===&lt;br /&gt;
&lt;br /&gt;
====BREQ - Branch if Equal====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Zero Flag (Z)&#039;&#039;&#039; gesetzt ist. Ist nach einem Vergleich das Zero Flag gesetzt, lieferte die interne Subtraktion also 0, so waren beide Operanden gleich.&lt;br /&gt;
&lt;br /&gt;
====BRNE - Branch if Not Equal====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Zero Flag (Z)&#039;&#039;&#039; nicht gesetzt ist. Ist nach einem Vergleich das Zero Flag nicht gesetzt, lieferte die interne Subtraktion also nicht 0, so waren beide Operanden verschieden.&lt;br /&gt;
&lt;br /&gt;
====BRCC - Branch if Carry Flag is Cleared====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Carry Flag (C)&#039;&#039;&#039; nicht gesetzt ist. Dieser Befehl wird oft für Arithmetik mit grossen Variablen (16/32 Bit) bzw. im Zusammenhang mit Schiebeoperatioen verwendet.&lt;br /&gt;
&lt;br /&gt;
====BRCS - Branch if Carry Flag is Set====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Carry Flag (C)&#039;&#039;&#039; gesetzt ist. Die Verwendung ist sehr ähnlich zu BRCC.&lt;br /&gt;
&lt;br /&gt;
=== Selten verwendete bedingte Sprünge ===&lt;br /&gt;
&lt;br /&gt;
====BRHC - Branch if Half Carry Flag is Cleared====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Half Carry Flag (H)&#039;&#039;&#039; nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRHS - Branch if Half Carry Flag is Set====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Half Carry Flag (H)&#039;&#039;&#039; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRID - Branch if Global Interrupt is Disabled (Cleared)====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Interrupt Flag (I)&#039;&#039;&#039; nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRIS - Branch if Global Interrupt is Enabled (Set)====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Interrupt Flag (I)&#039;&#039;&#039; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRTC - Branch if T Flag is Cleared====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;(T)&#039;&#039;&#039; nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRTS - Branch if T Flag is Set====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;(T)&#039;&#039;&#039; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRVC - Branch if Overflow Cleared====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Overflow Flag (V)&#039;&#039;&#039; nicht gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
====BRVS - Branch if Overflow Set====&lt;br /&gt;
Der Sprung wird durchgeführt, wenn das &#039;&#039;&#039;Overflow Flag (V)&#039;&#039;&#039; gesetzt ist.&lt;br /&gt;
&lt;br /&gt;
==Beispiele==&lt;br /&gt;
&lt;br /&gt;
=== Entscheidungen ===&lt;br /&gt;
&lt;br /&gt;
In jedem Programm kommt früher oder später das Problem, die Ausführung von Codeteilen von irgendwelchen Zahlenwerten, die sich in anderen Registern befinden abhängig zu machen. Sieht beispielweise die Aufgabe vor, daß Register r18 auf 0 gesetzt werden soll, wenn im Register r17 der Zahlenwert 25 enthalten ist, dann lautet der Code&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
    cpi     r17, 25         ; vergleiche r17 mit der Konstante 25&lt;br /&gt;
    brne    nicht_gleich    ; wenn nicht gleich, dann mach bei nicht_gleich weiter&lt;br /&gt;
    ldi     r18, 0          ; hier stehen nun Anweisungen für den Fall&lt;br /&gt;
                            ; dass R17 gleich 25 ist&lt;br /&gt;
    rjmp    weiter          ; meist will man den anderen Zweig nicht durchlaufen, darum der Sprung&lt;br /&gt;
nicht_gleich:&lt;br /&gt;
    ldi     r18,123         ; hier stehen nun Anweisungen für den Fall&lt;br /&gt;
                            ; dass R17 ungleich 25 ist&lt;br /&gt;
weiter:                     ; hier geht das Programm weiter&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In ähnlicher Weise können die anderen bedingten Sprungbefehle eingesetzt werden, um die üblicherweise vorkommenden Vergleiche auf Gleichheit, Ungleichheit, Größer, Kleiner zu realisieren.&lt;br /&gt;
&lt;br /&gt;
===Schleifenkonstrukte===&lt;br /&gt;
&lt;br /&gt;
Ein immer wiederkehrendes Muster in der Programmierung ist eine &#039;&#039;&#039;Schleife&#039;&#039;&#039;. Die einfachste Form einer Schleife ist die &#039;&#039;&#039;Zählschleife&#039;&#039;&#039;. Dabei wird ein Register von einem Startwert ausgehend eine gewisse Anzahl erhöht, bis ein Endwert erreicht wird.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
    ldi     r17, 10         ; der Startwert sei in diesem Beispiel 10&lt;br /&gt;
loop:&lt;br /&gt;
                            ; an dieser Stelle stehen die Befehle, welche innerhalb der Schleife&lt;br /&gt;
                            ; mehrfach ausgeführt werden sollen&lt;br /&gt;
&lt;br /&gt;
    inc     r17             ; erhöhe das Zaehlregister&lt;br /&gt;
    cpi     r17, 134        ; mit dem Endwert vergleichen&lt;br /&gt;
    brne    loop            ; und wenn der Endwert noch nicht erricht ist&lt;br /&gt;
                            ; wird bei der Marke loop ein weiterer Schleifendurchlauf ausgeführt&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sehr oft ist es auch möglich das Konstrukt umzudrehen. Anstatt von einem Startwert aus zu inkrementieren genügt es die Anzahl der gewünschten Schleifendurchläufe in ein Register zu laden und dieses Register zu dekrementieren. Dabei kann man von der Eigenschaft der Dekrementieranweisung gebrauch machen, das &#039;&#039;&#039;Zero Flag (Z)&#039;&#039;&#039; zu beeinflussen. Ist das Ergebnis des Dekrements 0, so wird das &#039;&#039;&#039;Zero Flag (Z)&#039;&#039;&#039; gesetzt, welches wiederum in der nachfolgenden &#039;&#039;&#039;BRNE&#039;&#039;&#039; Anweisung für einen bedingen Sprung benutzt werden kann. Das vereinfacht die Schleife und spart eine Anweisung sowie einen Takt Ausführungzeit.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;avrasm&amp;gt;&lt;br /&gt;
    ldi     r17, 124        ; Die Anzahl der Wiederholungen in ein Register laden&lt;br /&gt;
loop:&lt;br /&gt;
                            ; an dieser Stelle stehen die Befehle, welche innerhalb der Schleife&lt;br /&gt;
                            ; mehrfach ausgeführt werden sollen&lt;br /&gt;
&lt;br /&gt;
    dec     r17             ; Schleifenzähler um 1 verringern, dabei wird das Zero Flag beeinflusst&lt;br /&gt;
    brne    loop            ; wenn r17 noch nicht 0 geworden ist -&amp;gt; Schleife wiederholen&lt;br /&gt;
&amp;lt;/avrasm&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Navigation_zurückhochvor|&lt;br /&gt;
zurücktext=Interrupts|&lt;br /&gt;
zurücklink=AVR-Tutorial: Interrupts|&lt;br /&gt;
hochtext=Inhaltsverzeichnis|&lt;br /&gt;
hochlink=AVR-Tutorial|&lt;br /&gt;
vortext=Mehrfachverzweigungen|&lt;br /&gt;
vorlink=AVR-Tutorial: Mehrfachverzweigung}}&lt;br /&gt;
&lt;br /&gt;
[[Category:AVR]][[Category:AVR-Tutorial]]&lt;/div&gt;</summary>
		<author><name>85.183.44.11</name></author>
	</entry>
</feed>